How to convert a number to a bytearray in bit endian order
-
05-07-2019 - |
Question
I am trying to uncompress some data created in VB6 using the zlib API.
I have read this is possible with the qUncompress function: http://doc.trolltech.com/4.4/qbytearray.html#qUncompress
I have read the data in from QDataStream via readRawBytes into a char array, which I then converted to a QByteArray for decompression. I have the compressed length and the expected decompressed length but am not getting anything back from qUncompress.
However I need to prepend the expected decompressed length in big endian format. Has anybody done this and have an example?
Solution
I haven't used VB6 in ages, so I hope this is approximately correct. I think that vb6 used () for array indexing. If I got anything wrong, please let me know.
Looking at the qUncompress docs, you should have put your data in your QByteArray starting at byte 5 (I'm going to assume that you left the array index base set to 1 for this example).
Let's say the array is named qArr, and the expected uncompressed size is Size. In a "big-endian" representation, the first byte is at the first address.
qArr(1) = int(Size/(256*256*256))
qArr(2) = 255 And int(Size/256*256)
qArr(3) = 255 And int(Size/256)
qArr(4) = 255 And int(Size)
Does that make sense?
If you needed little endian, you could just reverse the order of the indexes (qArr(4) - qArr(1)) and leave the calculations the same.
OTHER TIPS
This is how I can convert arbitary data from one format to another.
Private Type LongByte
H1 As Byte
H2 As Byte
L1 As Byte
L2 As Byte
End Type
Private Type LongType
L As Long
End Type
Function SwapEndian(ByVal LongData as Long) as Long
Dim TempL As LongType
Dim TempLB As LongByte
Dim TempVar As Long
TempL.L = LongData
LSet TempLB = TempL
'Swap is a subroutine I wrote to swap two variables
Swap TempLB.H1, TempLB.L2
Swap TempLB.H2, TempLB.L1
LSet TempL = TempLB
TempVar = TempL.L
SwapEndian = TempVar
End Function
If you are dealing with FileIO then you can use the Byte fields of TempLB
The trick is using LSET an obscure command of VB6
If you are using .NET then doing the process is much easier. Here the trick is using a MemoryStream to retrieve and set the individual bytes. Now you could do math for int16/int32/int64. But if you are dealing with with floating point data, using LSET or the MemoryStream is much clearer and easier to debug.
If you are using Framework version 1.1 or beyond then you have the BitConvertor Class which uses arrays of bytes.
Private Structure Int32Byte
Public H1 As Byte
Public H2 As Byte
Public L1 As Byte
Public L2 As Byte
Public Function Convert() As Integer
Dim M As New MemoryStream()
Dim bR As IO.BinaryReader
Dim bW As New IO.BinaryWriter(M)
Swap(H1, L2)
Swap(H2, L1)
bW.Write(H1)
bW.Write(H2)
bW.Write(L1)
bW.Write(L2)
M.Seek(0, SeekOrigin.Begin)
bR = New IO.BinaryReader(M)
Convert = bR.ReadInt32()
End Function
End Structure
It looks like you want a C chunk of code that uncompresses some zlib compressed data. In that case is it possible for you to actually use zlib and just feed the zlib data to it. The zlib homepage: http://www.zlib.net/.
If I got it wrong, could you be specific what is the language that should be used for uncompressing the data and why zlib would not be a choice?
//int length;
byte[] bigEndianBytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(length))
Conversely:
//byte[] bigEndianBytes;
int length = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(bigEndianBytes))
It wasn't clear to me from your question whether you want to prepend the length in VB so that it is suitable for direct use by qUncompress or whether you wanted to use the VB produced data as it is now and prepend the length in C++ before calling qUncompress.
Mike G has posted a VB solution. If you want to do it in C++ then you have two choices, either add the length at the start of the QByteArray or call zlib's uncompress directly. In both cases the Qt source for qCompress and qUncompress (corelib/tools/qbytearray.cpp) are a good reference.
This is how qCompress adds the length (nbytes) to bazip, the compressed data:
bazip[0] = (nbytes & 0xff000000) >> 24;
bazip[1] = (nbytes & 0x00ff0000) >> 16;
bazip[2] = (nbytes & 0x0000ff00) >> 8;
bazip[3] = (nbytes & 0x000000ff);
where bazip is the result QByteArray
Alternatively if you want to call uncompress directly, instead of using the qUncompress wrapper the call it uses is
baunzip.resize(len);
res = ::uncompress((uchar*)baunzip.data(), &len,
(uchar*)data+4, nbytes-4);
where baunzip is a QByteArray. In your case you would drop the +4 and -4 since your data does not have the length prepended to it.
Thank you for all your help, it was useful.
The I got the code working with:
char slideStr[currentCompressedLen];
int slideByteRead = in.readRawData(slideStr, currentCompressedLen);
QByteArray aInCompBytes = QByteArray(slideStr, slideByteRead);
aInCompBytesPlusLen = aInCompBytes;
aInCompBytesPlusLen.prepend(QByteArray::number(currentUnCompressedLen));
aInUnCompBytes.resize(currentUnCompressedLen);
aInUnCompBytes = qUncompress(aInCompBytesPlusLen);