zlib圧縮ストリームの終わりを見つける
-
08-07-2019 - |
質問
QtでNMDCクライアント(p2p、DC ++、および友人)を使用しています。プロトコル自体は非常に簡単です:
$command parameters|
圧縮を除く:
" ZPipeは、コマンド$ ZOn |を送信することで機能しますクライアントに。 $ ZOnの後に、コマンドを含むZLib圧縮ストリームが続きます。このストリームは、ZLibが定義するEOFで終了します。 (圧縮ストリームには$ ZOffはありません!)"
関連するコードは次のとおりです。
QTcpSocket *conn;
bool compressed;
QByteArray zbuffer;
QByteArray buffer;
// ...
void NMDCConnection::on_conn_readyRead() {
// this gets called whenever we get new data from the hub
if(compressed) { // gets set when we receive $ZOn
zbuffer.append(conn->readAll());
// Magic happens here
if( stream_is_complete ) {
buffer.append(uncompressed_stream);
buffer.append(remainder_of_data);
compressed = false;
}
} else {
buffer.append(conn->readAll());
};
parse(buffer);
}
では、 stream_is_complete
、 uncompressed_stream
、および remainder_of_data
の値を取得するにはどうすればよいですか?ストリームに含まれている可能性があるため、次の「$」を探すことはできません。 zlibのドキュメントでEOFに似たものを探してみましたが、そのようなものはありません。実際、すべてのストリームが一見ランダムな文字で終了しています。
また、qUncompress()をいじりましたが、それは完全なストリームを望んでいます。
解決
zlibを直接使用していますか?
完全に未テスト...
z_stream zstrm;
QByteArray zout;
// when you see a $ZOn|, initialize the z_stream struct
parse() {
...
if (I see a $ZOn|) {
zstrm.next_in = Z_NULL;
zstrm.avail_in = 0;
zstrm.zalloc = Z_NULL;
zstrm.zfree = Z_NULL;
zstrm.opaque = 0;
inflateInit(&zstrm);
compressed = true;
}
}
void NMDCConnection::on_conn_readyRead() {
if (compressed) {
zbuffer.append(conn->readAll());
int rc;
do {
zstrm.next_in = zbuffer.data();
zstrm.avail_in = zbuffer.size();
zout.resize(zstrm.total_out + BLOCK_SIZE);
zstrm.next_out = zout.data() + zstrm.total_out;
zstrm.avail_out = BLOCK_SIZE;
rc = inflate(&zstrm, Z_SYNC_FLUSH);
zbuffer.remove(0, zstrm.next_in - zbuffer.data());
} while (rc == Z_OK && zstrm->avail_out == 0);
if (rc == Z_STREAM_END) {
zout.truncate(zstrm.total_out);
buffer.append(zout);
zout.clear();
buffer.append(zbuffer);
zbuffer.clear();
compress = false;
inflateEnd(&zstrm);
}
else if (rc != Z_OK) {
// ERROR! look at zstrm.msg
}
}
else // whatever
}
これは、 qbuffer
から qout
に段階的に解凍(膨張)し、 inflate
が「これ以上」と言ったときに停止します。
QuaZip から代わりに借りた方がいいかもしれません。
他のヒント
ファイルの終わりは、zlibにとって特別なものではありません。コードで見られる問題は、「readAll()」を使用していることです。実際には、ファイルの終わりなどの「エラー」を報告する手段がありません。
" read()"を使用してください。代わりに、ループで。ストリームを読み取り、0バイトの読み取りを返した場合、ストリームの終わりに到達していることを確認できます(もう一方の端が接続を閉じています)。あなたが読んだバッファは、以前のすべての「読み」のバッファに結合します;ループ内で、完全なバッファが提供されます。