Not able to Seralize QHash to DataStream - qt

while leaning about QHash and serializing QHash to DataStream I got an error with the following code.
typedef QHash <quint32,QString> hashtype1;
typedef QHash <QLocale::Language,hashtype1> hashtype;
hashtype1 hash;
hash.insert(1, "Key1");
hash.insert(2, "Key2");
hashtype hash1;
hash1.insert(QLocale::English, hash);
hash1.insert(QLocale::French, hash);
QByteArray ba;
QByteArray ba1;
QDataStream ds(&ba, QIODevice::ReadWrite);
QDataStream ds1(&ba1, QIODevice::ReadWrite);
ds << hash;
ds1 << hash1;
qDebug() << ds.device()->readAll();
ds.device()->reset();
ds1.device()->reset();
hashtype1 hashcopy;
ds >> hashcopy;
hashtype hash1copy;
ds1 >> hash1copy;
The last statement is giving an error saying
/usr/include/qt4/QtCore/qdatastream.h:362: error: no match for ‘operator>>’ in ‘in >> k’
I am not able to correct this..
Am I doing somthing wrong??
How can I correct this?

The problem is that there are no QDataStream operators for QLocale::Language. When streaming out this works because it gets automatically converted to an integer type. It can't do this for streaming in. So you will either need to change your QHash to use a different template parameter for the key or write streaming operators for QLocale::Language (which should be trivial, you just need to cast it to/from int).

Related

Get a string representation of a single byte from QByteArray?

I have a QByteArray i create manually:
QByteArray hexArray(QByteArray::fromHex("495676"));
If this was encoded ASCII it would be "IVv".
If I want to get a single byte of data from that array.
I can do that like this:
qDebug() << messageToBeSent_raw[0];
However, that outputs I, which is correct but I would like to get 49. What I'm looking for is an equivalent of the QByteArray::toHex() just for a single byte. Is there a way to do it?
You can use QString::number.
qDebug() << QString::number(hexArray[0], 16);

Qt parse string of undefined size from a binary data stream

I have a binary data stream which contains data that should be interpreted as a Qstring. Starting from the third byte. Here is how the package is generated (on a client).
QByteArray package;
package.append( QByteArray::fromHex("0002") ); // First two bytes
package.append( "filename.txt" ); // String of undefined size
package.append( QByteArray::fromHex("00")); // End of string
The decoding is done on a different machine (server). I would like to get a Qstring of value "filename.txt" from the QByteArray package without relying on the size of the string (since the server doesn't have that information) but on the string terminator 00. How can this be achieved?
Since this decoding will be done on a different machine, how should the raw data be generated on the client to avoid problems with endianess?
You should wrap the QByteArray in a QDataStream so you can specify the endianess explicitly and make use of the stream operators
QByteArray package;
QDataStream stream(package, QIODevice::WriteOnly);
stream.setByteOrder( QDataStream::BigEndian);
stream << static_cast<quint16>(0x0002); // First two bytes
stream << "filename.txt"; // String of undefined size
// no need to write terminating 0 because data stream will prepend length
then you can read in the other direction:
QByteArray package;
QDataStream stream(package, QIODevice::WriteOnly);
stream.setByteOrder( QDataStream::BigEndian);
quint16 id;
stream >> id; // First two bytes
char* filename;
stream >> filename; // String of undefined size
QString file = QString.fromLatin1(filename);
delete[] filename; //cleanup
or you can pass a QString to the stream in the first place and not need to deal with the char array:
QByteArray package;
QDataStream stream(package, QIODevice::WriteOnly);
stream.setByteOrder( QDataStream::BigEndian);
stream << static_cast<quint16>(0x0002); // First two bytes
stream << QStringLiteral("filename.txt"); // String of undefined size
note that this will write in utf16 meaning it is unicode enabled
the serialization format is documented at http://qt-project.org/doc/qt-5.0/qtcore/datastreamformat.html

Does QBuffer write data in system dependent byte order?

The documentation says that QDataStream writes data in system independent way, but it says nothing about QBuffer. I develop a program that saves data in a file like this:
QByteArray a;
QBuffer b(&a);
b.open(QIODevide::WriteOnly);
quint32 x = 1;
b.write((char*)&x, sizeof(x));
b.close();
QFile f(...);
f.open(QIODevide::WriteOnly);
f.write(a.constData(), a.size());
f.close();
, and i want this file can be read in any other OS (win, linux, Mac OS). Will this code work or i must use QDataStream instead?
The QBuffer documentation says :
The QBuffer class provides a QIODevice interface for a QByteArray.
ie it is only a QByteArray underneath. On the other hand a QByteArray is portable because as long as you see the data as an array of byte and write one byte at a time you are fine. Your code will work:
When you say
I want this file to be read in any other OS
Is your file used by your program only or will it be used by other applications in the system? QDataStream provides nicer functions for I\O and you may be still able to take advantage of it.
It will be platform specific. x representation in memory depend on the endianess.It doesn't occur in the QBuffer, but when you do :
b.write((char*)&x, sizeof(x));
If you are on machines of different endianess, you will obtain different values for the resulting array by doing
char* data = &x;
qDebug()<< data[0];
qDebug()<< data[1];
qDebug()<< data[2];
qDebug()<< data[3];
Take a look at the source code of QDataStream operator
QDataStream &QDataStream::operator<<(qint32 i){
CHECK_STREAM_WRITE_PRECOND(*this)
if (!noswap) {
i = qbswap(i);
}
if (dev->write((char *)&i, sizeof(qint32)) != sizeof(qint32))
q_status = WriteFailed;
return *this;
}

QMap Serialization in Qt

I have a 2 classes: valueNode and keyNode. Both of these classes have 2 private members. Now I create a QMap< keyNode , valueNode >. for this I override operator<(). I want to serialize this QMap but I don't know how.
QMap<QString, QString> map;
map.insert("Hello", " World!");
QByteArray data;
QDataStream * stream = new QDataStream(&data, QIODevice::WriteOnly);
(*stream) << map;
delete stream;
// Now QByteArray should have the map as serialized data.
This should work.
You might wonder about the new and delete madness, but there is a reason: there is no way to flush the data from the stream to the bytearray, except by deconstructing the stream. Or maybe there is, give me a comment if I'm wrong.
Edit:
Oh yeah, forgot one thing.
You need to make these functions:
QDataStream & operator << (QDataStream & out, const MyClass & object);
QDataStream & operator >> (QDataStream & in, MyClass & object);
Introduce them in the headers of your classes and implement in the cpp file of that class.
// MyClass.h
MyClass
{
...
};
QDataStream & operator << ...
QDataStream & operator >> ...
Note that it must be a global function and not a member function.
Note that you must create a pair for each of your classes.
Store it in a QVariant which you can then use a QDataStream to read/write it.

Qt XQuery into a QStringList

I'm trying to use QtXmlQuery to extract some data from XML. I'd like to put this into a QStringList. I try the following:
QByteArray in = "this is where my xml lives";
QBuffer received;
received.setData(in);
received.open(QIODevice::ReadOnly);
QXmlQuery query;
query.bindVariable("data", &received);
query.setQuery(NAMESPACE //contains definition of the t namespace
"doc($data)//t:service/t:serviceID/text()");
QBuffer outb;
outb.open(QIODevice::ReadWrite);
QXmlSerializer s(query, &outb);
query.evaluateTo(&s);
qDebug() << "buffer" << outb.data(); //This works perfectly!
QStringList * queryResult = new QStringList();
query.evaluateTo(queryResult);
qDebug() << "string list" << *queryResult; //This gives me no output!
As you can see, everything works fine when I send the output into a QBuffer via a QXmlSerializer... but I get nothing when I try to use a QStringList.
Try to use string() instead of text(), it should work.

Resources