Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

How to encode/decode and write and read binary data?



  • Hello!

    I'm writing a server and part of the messages I receive are headers. The Header is constructed in the following way:

    • First byte: binary operation code (Size 1 Byte)

    • Bytes 1-3: Header Checksum:(Size 2 Bytes)

    • Bytes 4-8 Payload index (Size 4 Bytes)

    • Bytes 9 - 10 Payload Checksum (Size 2 Bytes)

    Altogether 9 Bytes.

    I want to use binary encoding for things such as the operation code and the payload index rather than ASCII encoding because 1-byte ASCII encoding would give me at most 0-9 (10 options), while one byte in binary will give me 00000000 - 11111111 (256 options)

    However, I'm unsure how to parse this information on the receiving end. I've looked at QBuffer and QDataStream which seems to be most suitable for the task. But couldn't figure out exactly how to perform the task I need.

    For example, when I get a new message from a client that is stored in a QTcpesocket's buffer, I read the first 9 bytes.

    QByteArray ba;
     
    ba.append(this->socket->read(this->HEADER_SIZE)) ; //HEADER_SIZE = 9
    
    

    So now I have my whole header in the ba ByteArray. Now I want to separate it into chunks and parse them individually. I thought of doing something like this:

    
        QBuffer buffer(&receivedHeaderByteArray);
        buffer.open(QIODevice::ReadOnly);
    
        QByteArray opCodeByteArray = buffer.read(1);
    
        QByteArray headerCheckSumByteArray = buffer.read(2);
    
        QByteArray payloadIndex = buffer.read(4) ;
    
        QByteArray payloadChecksum = buffer.read(2);
    
    

    Presumably, now I have my header info separated into chunks but how do I convert the bytes in opCodeByteArray from a binary representation into an int?

    Would something like this be correct:

    QByteArray opCodeByteArray = buffer.read(1);
    QBuffer buffer(&opCodeByteArray );
    buffer.open(QIODevice::ReadOnly);
    qint8 opCodeInt;
    in >> opCodeInt;
    

    Also, How would I encode an int into a binary value? For example, if I want to write '7'it would be '111' in binary. But sending '111' in ASCII would take 3 Bytes while encoded to binary it will be only one byte '00000111'



  • Edit

    Bytes 1-3 [...] Size 2 Bytes

    does not hold mathematically but nevermind

    @Curtwagner1984 said in How to encode/decode and write and read binary data?:

    Now I want to separate it into chunks and parse them individually

    First byte: ba.front();
    Bytes 1-3: ba.mid(1,2);
    Bytes 4-8: ba.mid(4,4);
    Bytes 9 - 10: ba.mid(9,2);

    How would I encode an int into a binary value? For example, if I want to write '7'

    QDataStream baStream(&ba,QIODevice::WriteOnly);
    baStream << static_cast<quint8>(7);
    


  • @VRonin said in How to encode/decode and write and read binary data?:

    First byte: ba.front();
    Bytes 1-3: ba.mid(1,2);
    Bytes 4-8: ba.mid(4,4);
    Bytes 9 - 10: ba.mid(9,2);

    Thanks! What did you mean 'does not hold mathematically?'
    And converting this to ints would be done like this:?

    QByteArray opCode = ba.front();
    QDataStream baStream(&opCode,QIODevice::ReadOnly);
    qint8 opCodeInt;
    baStream >> opCodeInt;
    


  • @Curtwagner1984 said in How to encode/decode and write and read binary data?:

    What did you mean 'does not hold mathematically?'

    Bytes 1-3 is 3 Bytes (1,2 and 3), not 2

    And converting this to ints

    please be very careful with terminology here. Qt requires int to be 4 bytes in size, with that comes the problem of endianness.
    If you just mean the numeric value in each byte you can just iterate over the internal buffer using .cbegin()/cend() or by using ba.data()[i]



  • @VRonin said in How to encode/decode and write and read binary data?:

    @Curtwagner1984 said in How to encode/decode and write and read binary data?:

    What did you mean 'does not hold mathematically?'

    Bytes 1-3 is 3 Bytes (1,2 and 3), not 2

    Oh, my bad...
    I thought you meant the whole concept doesn't hold mathematically...

    And converting this to ints

    please be very careful with terminology here. Qt requires int to be 4 bytes in size, with that comes the problem of endianness.

    Could you please elaborate on this? Isn't this what qint8 and qint16 are for?



  • Take the "Header Checksum" for example they are already stored as qint8 numerals inside QByteArray, if you want to convert those 2 bytes in a 4 bytes int then it becomes a problem. If you just want to access the values you can use constData().operator[]

    const QByteArray checksum= ba.mid(1,2);
    qDebug() << "First Byte in decimal" << static_cast<qint16>(checksum.constData()[0]); //the cast is necessary otherwise qDebug() will try to print an ascii value
    qDebug() << "Full Values in hexadecimal" << checksum.toHex();
    

Log in to reply