How to extract integers from a QByteArray in Qt using toInt? - c++

I am a beginner with C++ and Qt. The data sent is a string of ASCII characters ex:"jdlsfjffjf: XX" where I would like to extract the number XX. I know I should possibly use indexof to point to it but not sure how. Any direction? Here's the server side code that receives, displays and writes. I get the correct numbers in the application but gibberish characters in the file I'm writing to.
void Receiver::processPendingDatagrams()
{
while (udpSocket->hasPendingDatagrams()) {
QByteArray datagram; //array of bytes
datagram.resize(udpSocket->pendingDatagramSize()); //size it depending on sent data
udpSocket->readDatagram(datagram.data(), datagram.size()); //read all
statusLabel->setText(tr("%1 C").arg(datagram.data()));
//writing stream to file
bool ok;
QFile file("file.dat");
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
out << datagram.toInt(&ok, 10 );
}

int num = datagram.right(datagram.size() - datagram.indexOf(':') - 1).toInt();

Related

How to convert QString with special characters into a byte stream to send it via Linux pipe

I have a QString containing a special character (µ) encoded in UTF-8:
QString data = "197,45 \xc2\xb5m";
I need to send that string via a Linux pipe to another program. I tried to convert the string into something like this:
char msg[15];
for(int i = 0; i < data.length(); i++) {
msg[i] = data.toUtf8()[i];
}
msg[data.length()] = '\0';
I send msg to the pipe, but I only receive "197,45 µ", not "197,45 µm". I try to read the data on the read end with:
char data[15];
read(fd, data, nbytes);
I don't know much about character/string conversion, so I would be glad if you could explain how I should approach this problem. Thank you.
What you are doing seems to be mainly "serializing the data" into a binary pipe, so an option that could make sense is to use a QDataStream which is designed for that purpose.
Something like:
QByteArray buffer;
QDataStream stream(&buffer, QIODevice::WriteOnly);
QString data = "197,45 \xc2\xb5m";
stream << data;
sendToPipe(buffer.constData(), buffer.size());
And the similar on the other side, using operator>> to read the data from the stream.
QByteArray buffer(dataPtr, size);
QDataStream stream(buffer);
QString data;
stream >> data;
It is conceptually wrong to store UTF-8 encoded bytes in a QString. Use QByteArray for that, OR use QString::fromUtf8() to convert your UTF-8 string literals to a proper QString. To go back, use the qUtf8Printable macro or QString::toUtf8 to get a QByteArray.

How to read Binary data from file using QDataStream?

if you look in the documentation of QT. You can use readBytes or readRawBytes to read the binary data from a file. I am comfortable in any case, either reading the data from file or stream.
In case of readBytes - Reads the buffer s from the stream and returns a reference to the stream.
In case of readRawBytes - Reads L (length) bytes from the stream into s(buffer char*) and returns the number of bytes reads.
void readBinary(QString path)
{
QFile file(path);
if (!file.open(QIODevice::ReadOnly)) {
qDebug() << "Could not open bin file for reading";
return;
}
QDataStream in(&file);
char *data = new char[30];
qint32 bytes = in.readRawData(data, 30);
//in >> data;
qInfo() << "bytes read: " << bytes;
qInfo() << data;
file.close();
}
It shows no of bytes reads but not showing binary data on a screen.
What I am missing here?
Do we need to do serialization/de-serialization of binary data? In other words marshelling/un-marshelling of data. because I have read in official documentation encoding/decoding you need to take care of by own and need to set version of QT while reading/writing the data in the file.
How do we write back to the file/stream.
If we have another method to read/write the data directly from a file.
Do we need to write the whole binary data into buffer and then reads it again? This way we can maintain format of data.
Want some answers from you guys!
for your reference - consider the snippet of binary data in the file as mentioned below.
00000000: 0000 0520 a52a 0108 8520 0108 9320 0108 ... .*... ... ..
00000010: 9920 0108 9f20 0108 a520 0108 0000 0000 . ... ... ......
Links which I had followed on StackOverflow to resolve this issue are- Link1 , Link2, Link3, Link4
What I am missing here?
You are using raw pointers instead of QByteArray. And then you are trying to print binary data as a text.
...
QDataStream in(&file);
// You can use QByteArray which was created especially ti avoid raw char pointers
QByteArray ba(30, 0);
qint32 bytes = in.readRawData(ba.data(), ba.size());
qInfo() << "bytes read: " << bytes;
qInfo() << ba.toHex('\s'); // You read binary data, not a text. Do not try to print it as a text
Do we need to do serialization/de-serialization of binary data? In other words marshelling/un-marshelling of data. because I have read in official documentation encoding/decoding you need to take care of by own and need to set version of QT while reading/writing the data in the file.
Generally speaking, yes. Anyway you will have some serialization/de-serialization mechanism in your code. Qt suggest the mechanism out-of-the-box. You can forget about raw pointers, sizes, byte orders.
From the docs:
You don't have to set a version if you are using the current version
of Qt, but for your own custom binary formats we recommend that you
do; see Versioning in the Detailed Description.
QByteArray ba;
// fill it by some data
// Write to file
QDataStream out(&file); // output file, socket, etc.
out << ba;
// Read from file
QDataStream in(&file);
in >> ba;
How do we write back to the file/stream.
// Write to file
QDataStream out(&file); // output file, socket, etc.
out << ba;
If we have another method to read/write the data directly from a file.
Do we need to write the whole binary data into buffer and then reads it again? This way we can maintain format of data. Want some answers from you guys!
With QDataStream you can read/write directly the data structures you need, for example:
struct MyStruct
{
double d;
int a;
QString str;
QPixmap pix;
QVector<int> vec;
//overload the operators
friend QDataStream &operator << (QDataStream &out, const MyStruct &d)
{
out << d.d << d.a << d.str << d.pix << d.vec;
return out;
}
friend QDataStream &operator >> (QDataStream &in, MyStruct &d)
{
in >> d.d >> d.a >> d.str >> d.pix >> d.vec;
return in;
}
}
// Now you can:
MyStruct data;
out << data;

QDataStream writing wrong values to QByteArray

I'm writing a simple TCP based network application in Qt and wanted to use QDataStream and QByteArray to send data over the network. The problem is that when I'm putting data into QByteArray they are "zeroed". For example (a slot in MainWindow that is connected to timer timeout signal):
void MainWindow::SendPlayer1Data(){
QByteArray block;
QDataStream s(&block, QIODevice::OpenModeFlag::ReadWrite);
QString h="hello";
s<<h;
qDebug() << "h: " << data;
qDebug() << "block: " << QString(block); // equivalent to s >> h on receiving end
qDebug() << "block[0]: " << int(block[0]);
}
h: "hello"
block: ""
block[0]: 0
I receive "hello" once at the beginning but after that I only get "". The same goes for qint32. Both client and server shows that QByteArray size is 14 bytes, so QDataStream writes data into that array, but it makes them 0 (it shows "" when I use s >> h and then use qDebug() << h)
The issue here is writing a QString directly to a stream that is expecting a QByteArray, consider the following
QByteArray block;
QDataStream s(&block, QIODevice::OpenModeFlag::ReadWrite);
QString h = "hello";
s << h;
qDebug() << block;
Which outputs
"\x00\x00\x00\n\x00h\x00""e\x00l\x00l\x00o"
So the data is there, it just isn't there how one might expect it. The easiest way to solve this is to create a QByteArray from a string encoded with UTF8 (or other encoding of your choice). This can trivially be done on the fly,
QByteArray block;
QDataStream s(&block, QIODevice::OpenModeFlag::ReadWrite);
QString h = "hello";
QByteArray data(h.toUtf8(), 5);
s << data;
qDebug() << block;
Which outputs
"\x00\x00\x00\x05hello"
Because when this QByteArray is sent through the QDataStream the length of the array and 3 NULL characters are prepended - the NULL characters are there in case the buffer is larger than a relatively small 5 (you can test that for yourself by passing a larger value - a small factor of 256 is most demonstrative - as the second parameter in the QByteArray constructor as this is the buffer length). But if you try to explicitly construct a QString (as s >> h does) from the NULL-commenced QByteArray it will create an empty string. To correct for this you can use QByteArray::remove() to remove the first 4 bytes like this
QByteArray block;
QDataStream s(&block, QIODevice::OpenModeFlag::ReadWrite);
QString h = "hello";
QByteArray data(h.toUtf8());
s << data;
qDebug() << QString::fromUtf8(block.remove(0, 4));
Which outputs
"hello"
Complete example
#include <qbytearray.h>
#include <qdatastream.h>
#include <qdebug.h>
int main() {
QByteArray block;
QDataStream s(&block, QIODevice::OpenModeFlag::ReadWrite);
QString h = "hello";
QByteArray data(h.toUtf8());
s << data;
qDebug() << QString::fromUtf8(block.remove(0, 4));
}
Ok, I have figured it out.
The problem was not the QByteArray or socket because, as #William Miller mentioned, the data was there.
The problem was with QDataStream on client side - I decided to create a new QDataStream object every time the slot responsible for receiving data was called. This way I was able to pack data easily into QByteArray, send it and receive every time.
The client function for receiving:
void ClientTcpHelper::ReceivePacket(){
if(socket.waitForReadyRead(20)){
//qDebug()<<"Packet: "<<socket.peek(30)<<endl;
qDebug()<<"Receiving packet!"<<endl;
Data=socket.readAll();
emit DataReceived();
}
else{
//qDebug()<<"Failed to receive packet!"<<endl;
}}
and unpacking data to variables:
void ClientTcpHelper::UnpackData(){
stream=new QDataStream (&this->Data,QIODevice::OpenModeFlag::ReadWrite);
*stream>>h>>a>>b;
Data.clear();
delete stream;}
h,a and b are members of a class.
Unfortunately I can not explain why QDataStream need to be destroyed every time here in order to handle data as I wanted it from the beginning.

Sending a big buffer through uart in Qt5

I'm a beginner in Qt. Now I want to use Qt5 to send a 9-byte command through uart.
Here is my command:
FFFFFF5550464DAA0E
I want to transfer my command to a Qstring object. When I write my code like this, it tells me the const is too big.
QString str=0xFFFFFF5550464DAA0E;
So I choose an array like this, but it still doesn't work.
char cmd[9]={0xFF,0xFF,0xFF,0x55,0x50,0x46,0x4D,0xAA,0x0E};
for(int i=0;i<9;i++)
{
QString str=cmd[i];
QByteArray outData=str.toLatin1();
int size=outData.size();
outData=myHelper::HexStrToByteArray(str);
size=outData.size();
myCom->write(outData);
}
I also try this which failes again
char cmd[9]={0xFF,0xFF,0xFF,0x55,0x50,0x46,0x4D,0xAA,0x0E};
QString str=cmd;
QByteArray outData=str.toLatin1();
int size=outData.size();
outData=myHelper::HexStrToByteArray(str);
size=outData.size();
myCom->write(outData);
So could anyone tell me how to do this ?
This line of code:
QString str=0xFFFFFF5550464DAA0E;
0xFFFFFF5550464DAA0E is not a string. You're trying to assign a very big constant (9 bytes) number to a string. Note that 0xFF is not a string but a character with ASCII code 0xFF. With your second attempt you're on the right way:
char cmd[9]={0xFF,0xFF,0xFF,0x55,0x50,0x46,0x4D,0xAA,0x0E};
Now you have two options; it depends on what you have to send, 9 bytes or a longer string with that commands represented as a hex string and encoded as ASCII. First case is easier, drop all your code:
QByteArray outData = QByteArray(cmd, sizeof(cmd));
myCom->write(outData);
With this code you won't send a string to your device but 9 bytes (0xFF...0x0E). If you have to send a string then you can do what paxdiablo suggested:
QByteArray outData = QByteArray("\xFF\xFF\xFF\x55\x50\x46\x4D\xAA\x0E", 9);
myCom->write(outData);
Or:
QByteArray outData = QString("0xFF0xFF0xFF0x550x500x460x4D0xAA0x0E")
.toLatin1();
myCom->write(outData);
Or in alternative you can do this:
char cmd[9]={0xFF,0xFF,0xFF,0x55,0x50,0x46,0x4D,0xAA,0x0E};
QByteArray outData = QByteArray(cmd, sizeof(cmd)).toHex();
myCom->write(outData);
Which one is right for you? Well you should clarify your context...
You don't need to mess about with strings and conversions. You can just make the QByteArray directly from the data itself, with a simple one-liner:
QbyteArray data("\xFF\xFF\xFF\x55\x50\x46\x4D\xAA\x0E", 9);
Following that, the statement:
myCom->write(data);
will then output the nine bytes as specified in the string.

How to transfer larger objects through a socket in QT?

I would like to send/recieve image files and 2 ints as messages in a client server program.
I'm using QLocalSocket and QImage for this.
However I don't know how to read from the socket only after the image and the integers are fully written to the buffer, since the readyRead signal is already fired after the first couple of bytes.
Here's parts of my code:
// sending
QDataStream stream(socket);
stream << image << i << j;
// recieving
void MainWindow::readyRead() {
// ...
if (socket->bytesAvailable() > 400)
{
QByteArray b = socket->readAll();
QDataStream stream(&b, QIODevice::ReadOnly);
QImage image;
int i, j;
stream >> image >> i >> j;
// ...
}
}
I tried guessing the incoming file size, but since QImage is serialized to PNG the data size is variable and sometimes the end of the file doesn't get written to the buffer before I start to read it.
Is there an easy solution to this?
I would send a fixed size header first that describes the data being sent, specifically the type and size in bytes.
Then as you receive readReady events you pull whatever data is available into a buffer. Once you determine you have received all of the necessary data, you can stream it into a QImage object.
The BMP format has size information and PNG format has size information for each chunk. These are formats with what QImage serializes.
If you don't want to extract the information from raw data then serialize QImage first to QBuffer (so you know/control size and format better). Then stream that size and buffer.
Code example:
QBuffer buffer;
image.save(&buffer, "PNG", 100); //can change the compression level to suit the application - see http://qt-project.org/doc/qt-4.8/qimage.html#save
qint64 length = sizeof(quint32) + buffer.data().size(); //http://doc.qt.digia.com/4.7/datastreamformat.html
stream << length;
stream << buffer.data();
Then on the other end, first stream out the qint64 length so you know how big socket->bytesAvailable() has to be to stream out the full QByteArray. Then:
QByteArray ba;
stream >> ba;
QImage image = QImage::fromData(ba); // Get image from buffer data