Stock bytes in QVariantMap - c++

I'm getting the bytes data from a QImage in a QByteArray and i want to write the datas from the QByteArray in a QVariantMap, but after stocking the bytes, the bytes are changed and the image is not valid...
I tried to stock the QByteArray directly but the thing is i'm going to receive QVariantMap (as a JSON) from Windows phone, android and iOS. And the QByteArray will not exist on those OS so i doubt that the .toByteArray function will work...
Here is an example of what i tried using a QString but the bytes are changed when the QString is filled...
QFile tmp("default_profile.jpg");
tmp.open(QIODevice::ReadOnly);
if (tmp.exists() == true)
{
QByteArray tab;
tab = tmp.read(tmp.size());
int i = 0;
char *data = tab.data();
QString str;
while (i != tmp.size())
{
if (i < 100)
qDebug() << "AVANT = " << " i = " << i << "[" << *data + '0' << "]";
i++;
str.append(*data);
++data;
}
QVariantMap *tmp = new QVariantMap();
(*tmp)["name"] = "test.jpg";
(*tmp)["data"] = str;
(*tmp)["size"] = tab.size();
(*tmp)["type"] = "PhonePic";
this->fileReceived("", "", tmp);
}
And here is the fileReceived:
QFile tmp((*src)["name"].toString());
tmp.open(QIODevice::ReadWrite | QIODevice::Truncate);
char *test = (char *)malloc((*src)["size"].toInt());
QString str;
str = (*src)["data"].toString();
int i = 0;
char *data = const_cast<char *>(str.toStdString().c_str());
while (i != 8143)
{
if (i < 100)
qDebug() << "AFTER = " << " i = " << i << "[" << *data + '0' << "]";
i++;
++data;
}
qDebug() << tmp.write(str.toStdString().c_str(), (*src)["size"].toInt());
The size of the "AFTER" QString is good, but the values are not good...
Does someone know what i'm doing wrong ? or maybe have an idea of how i get do it ?
Thanks for people who will try to help me.

You load binary data into a QByteArray. Then you append the data in this QByteArray byte by byte to a QString, which converts every single byte into unicode. And last but not least you you just try to cast this back into raw data? No way. So pointing you to what you are doing wrong was easy.
Helping you is much more difficult. Why do you think you can use QString, when QByteArray is not available? When QVariantMap is available, then you have a complete Qt. So using QByteArray should not be a problem. But I must admit, I don't fully understand your post and your problem, so I might overlook something.

You can send a QImage directly in a QVariant or QVariantMap. How the particular json library that you use will deal with the json-to-Qt interface, that's a whole another story.
Since QVariant is in Qt Core and not Qt Gui, you have to use QVariant::value() or the qvariant_cast() template function when working with GUI types such as QImage.

Related

QTextStream write data in file

I'm learning QtCreator and having troubles writing data in file. Here's some code :
char *str;
int i = 1;
QFile outFile("path/to/file/out.txt");
outFile.open(QIODevice::ReadWrite);
QTextStream out(&outFile);
while (i < rows * 2) {
str = dynamic_cast<QLineEdit *>(this->getItem(i))->text().toLocal8Bit().data();
std::cout << str << std::endl;
out << str << "\n";
i += 2;
}
getItem returns a QWidget * from a QFormLayout filled with QLineEdit (that explains the dynamic cast). Anyway, when I pass str into std::cout it works fine, the data is printed, but when I pass str into out, it writes only the first char of str in the file.
I don't get what I'm doing wrong, I really would appreciate any tips.
This line is a problem: str = dynamic_cast<QLineEdit *>(this->getItem(i))->text().toLocal8Bit().data();
dynamic_cast<QLineEdit *>(this->getItem(i))-> is OK
->text() creates a temporary QString
.toLocal8Bit() creates a temporary QByteArray
.data() returns a pointer to the internal data of the QByteArray
As soon as the line is passed the QByteArray will be destroyed and you have a dangling pointer. str points to invalid data.
Everything you do with this pointer afterwards (except letting it point to somewhere else) is undefined behaviour.
Try to use something like this:
int i = 1;
QFile outFile("path/to/file/out.txt");
outFile.open(QIODevice::ReadWrite);
QTextStream out(&outFile);
while (i < rows * 2)
{
QLineEdit* lineEdit = dynamic_cast<QLineEdit *>(this->getItem(i));
if (lineEdit)
{
QByteArray str = lineEdit->text().toLocal8Bit();
std::cout << str.data() << std::endl;
out << str.data() << "\n";
i += 2;
}
else
{
std::cerr << "Item at " << i << " is no QLineEdit*" << std::endl;
}
}
out.close();
Also please check whether QFile is actually open and whether QTextStream reports some errors when writing.

How to use QDataStream::readBytes()

According to the documentation for readBytes() (in Qt 5.4's QDataStream), I would expect the following code to copy the input_array into newly allocated memory and point raw at the copy:
QByteArray input_array{"\x01\x02\x03\x04qwertyuiop"};
QDataStream unmarshaller{&input_array, QIODevice::ReadOnly};
char* raw;
uint length;
unmarshaller.readBytes(raw, length);
qDebug() << "raw null? " << (raw == nullptr) << " ; length = " << length << endl;
...but the code prints raw null? true ; length = 0, indicating that no bytes were read from the input array.
Why is this? What am I misunderstanding about readBytes()?
The documentation does not describe this clearly enough, but QDataStream::readBytes expects the data to be in a certain format: quint32 part which is the data length and then the data itself.
So to read data using QDataStream::readBytes you should first write it using QDataStream::writeBytes or write it any other way using the proper format.
An example:
QByteArray raw_input = "\x01\x02\x03\x04qwertyuiop";
QByteArray ba;
QDataStream writer(&ba, QIODevice::WriteOnly);
writer.writeBytes(raw_input.constData(), raw_input.length());
QDataStream reader(ba);
char* raw;
uint length;
reader.readBytes(raw, length);
qDebug() << "raw null? " << (raw == NULL) << " ; length = " << length << endl;
Also you can use QDataStream::readRawData and QDataStream::writeRawData to read and write arbitrary data.

Convert str to char* issue

I need to convert a Str to char* but I sometimes lose a part of the string.
For example:
str: "/Users/seb/Pictures/Photos/20141009 - Aulani - Hawaii/20141009_083318_Richtone(HDR).jpg"
char*: /Users/seb/Pictures/Photos/20141009 - Aulani - Hawaii/20141009_083318_Ri
I'm using the code below:
void TreeWidget::CopyFilesFromLocal(QStringList pathList, QTreeWidgetItem * item) {
QString fileelt;
uint32_t Folder_id = INVALID;
MyTreeWidget* myItem = dynamic_cast<MyTreeWidget*>(item);
uint32_t destination_id = myItem->mtp_item_id;
item->setExpanded(true);
qDebug() << "**************************************";
qDebug() << "Send to PULS Start";
qDebug() << "Start of Loop to copy files";
foreach(fileelt, pathList) {
char *txt = NULL;
// char *isFileName = NULL;
qDebug() << "str: " << fileelt;
txt = strdup(m_device.convertQStr2char(fileelt));
qDebug() << "char*: " << txt;
Here is the api I use.
char *PulsDeviceMngr::convertQStr2char(QString str) {
return const_cast<char*>(std::string(str.toUtf8().constData() ).c_str());
}
Any idea ?
The pointer you return form convertQStr2char points to the internal buffer of the temporary std::string which is destroyed after the return. You thus use a dangling pointer and have undefined behavior.
Note that changing the data pointed to by std::string::c_string() through said pointer also is UB. Your const_cast is a very bad idea because it would allow exactly this even if you got the lifetime right.
You could do this instead (includes a couple of unnecessary copies, but get it working first, then worry about the rest):
char *PulsDeviceMngr::convertQStr2char(QString str) {
return strdup(std::string(str.toUtf8().constData() ).c_str());
}
Then do not forget to free the buffer. But it would probably be better to just return the std::string by value and then use .c_str() outside of your conversion function. This way, you do not need to use the non-C++ strdup and do not need to manage memory by hand, which would be error prone anyway.
You don't need an extra method
txt = strdup(fileelt.toUtf8().constData());
will work fine.

Variable change without any direct action

I have wrote an API as defined below. This API is used to find the index of a filename in a file system. The filesystem is coming from an Android device through mtp. What I'm doing is to request a list of files stored on the Android device and compare each file listed to the one I'm looking for 'name2look'
I have created a vector table to store what I'm doing but it's not mandatory. My concerns is that the variable name2look contain the right name I'm looking for "Pictures"
uint32_t USBDevice::GetIndexFromName(LIBMTP_mtpdevice_t *dev, uint32_t storage,const char *name2look)
{
uint32_t idx_fold = 1;
std::vector<MyFileTreeItem*> FSimage;
LIBMTP_file_t *files;
LIBMTP_file_t *file;
std::cout << "NAME : " << name2look << "\n";
files = this->GetFileAndFolder(dev, storage,0);
file = files;
while (file != NULL) {
MyFileTreeItem* FSitem = new MyFileTreeItem();
FSitem->filename = file->filename;
FSitem->index = file->item_id;
FSitem->FileType = file->filetype;
FSimage.push_back(FSitem);
std::cout << "NAME : " << name2look << "\n";
std::cout << "FS NAME : " << file->filename << "\n";
if(std::strcmp(file->filename, name2look)==0) {
std::cout << "FIND IDX : " << file->item_id << "\n";
return file->item_id;
}
file = file->next;
}
return 0;
}
The Log is showing that the first display 'std::cout' is ok. the variable name is still 'Pictures' but when I ask to display it after in the "while" the variable name2look change and is not the same anymore.
First display
NAME : Pictures
second one in the while
NAME : Martin).mp3
FS NAME : Music
How is it possible to be corrupted ??
The function is called by a Qt C++ code:
void MyButtonGroup::buttonClick(QAbstractButton *button)
{
uint32_t status;
QList<QTreeWidgetItem *> itemList;
uint32_t index = 0;
if (button->text() == "Create Folder") {
itemList = this->MyTree->selectedItems();
QString str = itemList[0]->text(0);
char *utf8_text = str.toLatin1().data();
if(utf8_text != NULL)
{
std::cout << "A CHERCHER " << utf8_text << "\n";
index = this->MyDevice.GetIndexFromName(this->dev_id, storage->id, utf8_text);
}
else
index = 0;
CreateFolderDialog *dialog = new CreateFolderDialog(this->MyTree, this->MyDevice, this->dev_id, this->storage, index);
dialog->show();
}
utf8_text report the right value.
Any idea ?
This might be the problem. I am not sure. Check it out.
This line:
char *utf8_text = str.toLatin1().data();
What does the documentation say toLatin1() does? It creates a new QByteArray object and then you call data() on that and you get a pointer to character and then the QByteArray is destroyed at the end of the line because it was TEMPORARY.
And now you have an invalid pointer to freed memory that you then pass into your function. It probably gets overwritten by the first call to new() in your function.
I think you should change it to something like this:
QByteArray latin_str = str.toLatin1();
char *utf8_text = latin_str.data();
Your name utf8_text is weird since you just converted it to Latin1 which isn't UTF8.

QByteArray to QString to std::stringstream doesn't work

anyone know why
QString Lulu ( data ); //data is a QByteArry ( from a QNetworkrequest )
std::stringstream streamedJson ;
// QString Lulu ( data.data() );
qDebug()<< "Lulu:" << Lulu; // here it views the right string
streamedJson << Lulu.toStdString();
qDebug() << "streamedJson: "<< streamedJson ; // here it views 0x7fffc9d46568
doesn't works ?
why it dont view the String here ?
finally i would parse it and give the parsed string out
boost::property_tree::ptree propertyTree;
try
{
boost::property_tree::json_parser::read_json(streamedJson, propertyTree);
}
catch(boost::property_tree::json_parser::json_parser_error& ex)
{
qDebug() << "ex: "<< ex.what(); // this and Lulu views the same (unparsed) string
qDebug ("propertyree error");
}
at the moment it only views "propertyree error". but it should print the parsed String in my console
std::stringstream cannot be directly used with QDebug::operator<<. You can explicitly convert it to QString. For example,
qDebug() << "streamedJson: " << QString::fromStdString(streamedJson.str());
The streamedJson.str() returns an std::string, and then converted to QString using QString::fromStdString.
Your program prints 0x7fffc9d46568 probably because the streamedJson is converted to a qDebug-printable object implicitly. Or maybe there is an operator<< function somewhere in your program that takes std::stringstream as input.
Try initialization of the QString variable as explained below and try putting the value into a std::string variable before pushing it into the std::stringstream.
QString Lulu = QString(data);
std::stringstream streamedJson ;
std::string strLulu = Lulu.toStdString();
streamedJson << strLulu;
qDebug() << "streamedJson: "<< streamedJson;
Hope this helps.
Class QString has function std::string toStdString() const. Maybe you should use it this way:
streamedJson << Lulu.toStdString();
If it will not work you can try
streamedJson << Lulu.toStdString().c_str();
If it will not work too we would find another possible solution. Good luck!
EDIT:
I've read several documents and I guess I've solved your problem. Class std::stringstream has inner representation of string. In order to get std::string from this class you should use its function str():
http://www.cplusplus.com/reference/sstream/stringstream/str/
Then your code should be looking like this:
string myString = streamedJson.str();
std::cout << myString;
I believe it will work.