ビットエンディアン順で数値をバイト配列に変換する方法
-
05-07-2019 - |
質問
zlib APIを使用してVB6で作成されたデータを解凍しようとしています。
これは、qUncompress関数で可能です。 http://doc.trolltech.com/4.4/qbytearray.html#qUncompress
QRStreamからreadRawBytesを介してcharにデータを読み込みました 配列。これを解凍のためにQByteArrayに変換しました。私 圧縮された長さと予想される解凍された長さを持っているが、取得していない qUncompressから返されたもの。
ただし、予想される解凍後の長さをビッグエンディアン形式で追加する必要があります。誰かがこれを行って、例を持っていますか?
解決
年齢でVB6を使用したことがないので、これがほぼ正しいことを願っています。私はvb6が配列のインデックス付けに()を使用したと考えます。何か問題が発生した場合は、お知らせください。
qUncompressのドキュメントを見ると、バイト5からQByteArrayにデータを配置しているはずです(この例では、配列のインデックスベースを1に設定したままにしておきます)。
配列の名前がqArrで、予想される非圧縮サイズがSizeであるとします。 「ビッグエンディアン」で表現では、最初のバイトは最初のアドレスにあります。
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)
それは理にかなっていますか?
リトルエンディアンが必要な場合は、インデックスの順序を逆にするだけで(qArr(4)-qArr(1))、計算を同じままにすることができます。
他のヒント
これにより、任意のデータをある形式から別の形式に変換できます。
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
FileIOを扱っている場合は、TempLBのバイトフィールドを使用できます
トリックは、VB6のあいまいなコマンドであるLSETを使用することです
.NETを使用している場合、プロセスを実行する方がはるかに簡単です。ここでの秘theは、MemoryStreamを使用して個々のバイトを取得および設定することです。これで、int16 / int32 / int64の計算ができるようになりました。ただし、浮動小数点データを扱う場合、LSETまたはMemoryStreamを使用する方がはるかに明確で簡単にデバッグできます。
Frameworkバージョン1.1以降を使用している場合、バイト配列を使用するBitConvertorクラスがあります。
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
一部のzlib圧縮データを圧縮解除するCのチャンクが必要なようです。 その場合、実際にzlibを使用し、zlibデータをそこに供給するだけで済みます。 zlibホームページ: http://www.zlib.net/ 。
誤解した場合、データの圧縮解除に使用する言語と、zlibが選択されない理由を具体的に教えてください。
//int length;
byte[] bigEndianBytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(length))
逆に:
//byte[] bigEndianBytes;
int length = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(bigEndianBytes))
VBで長さを先頭に追加してqUncompressで直接使用するのに適しているのか、VBで生成されたデータをそのまま使用して長さを先頭に追加するのかは、質問からわかりませんでしたqUncompressを呼び出す前にC ++で。
マイクGにはがありますVBソリューションを投稿しました。 C ++で実行する場合は、2つの選択肢があります。QByteArrayの先頭に長さを追加するか、zlibのuncompressを直接呼び出します。どちらの場合も、qCompressおよびqUncompressのQtソース(corelib / tools / qbytearray.cpp)が参考になります。
これは、qCompressが圧縮データであるbazipに長さ(nバイト)を追加する方法です。
bazip[0] = (nbytes & 0xff000000) >> 24;
bazip[1] = (nbytes & 0x00ff0000) >> 16;
bazip[2] = (nbytes & 0x0000ff00) >> 8;
bazip[3] = (nbytes & 0x000000ff);
bazipは結果のQByteArray
また、uncompressを直接呼び出す場合は、qUncompressラッパーを使用する代わりに、使用する呼び出しは
です。baunzip.resize(len);
res = ::uncompress((uchar*)baunzip.data(), &len,
(uchar*)data+4, nbytes-4);
baunzipはQByteArrayです。あなたの場合、データの先頭に長さが追加されていないため、+ 4と-4を削除します。
助けてくれてありがとう、それは役に立ちました。
コードが動作するようになった:
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);