適切で完全な「圧縮ストリーム」を提供していて、データを出力するのに十分なスペースがあると仮定するとinflate
、呼び出す必要があるのはinflate
1 回だけです。
編集: zlib documentationほど明確に書かれていませんが、次のように述べています:
inflate
可能な限り多くのデータを解凍し、入力バッファーが空になるか出力バッファーがいっぱいになると停止します。強制的にフラッシュする場合を除き、出力レイテンシ (出力を生成せずに入力を読み取る) が発生する可能性があります。
もちろん、まだ「メモリ内にあり、完了」していないストリームの場合は、ブロックごとに実行する必要があります。これは、総実行時間が短くなるためです (ネットワークまたはファイルシステムからデータを受信している間に解凍できます)。次のブロックのプリフェッチ キャッシング])。
サンプルコードの関数全体を次に示します。コードを集中させるためにページからテキスト コンポーネントを削除し、文字などでセクションを// A
マーク// B
し、以下のセクションを説明しようとしてマークしました。
int inf(FILE *source, FILE *dest)
{
int ret;
unsigned have;
z_stream strm;
unsigned char in[CHUNK]; // A
unsigned char out[CHUNK];
/* allocate inflate state */
strm.zalloc = Z_NULL; // B
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
ret = inflateInit(&strm); // C
if (ret != Z_OK)
return ret;
/* decompress until deflate stream ends or end of file */
do {
strm.avail_in = fread(in, 1, CHUNK, source); // D
if (ferror(source)) {
(void)inflateEnd(&strm); // E
return Z_ERRNO;
}
if (strm.avail_in == 0) // F
break;
strm.next_in = in; // G
/* run inflate() on input until output buffer not full */
do {
strm.avail_out = CHUNK; // H
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH); // I
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
switch (ret) {
case Z_NEED_DICT:
ret = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void)inflateEnd(&strm);
return ret;
}
have = CHUNK - strm.avail_out; // J
if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
(void)inflateEnd(&strm);
return Z_ERRNO;
}
} while (strm.avail_out == 0); // K
/* done when inflate() says it's done */
} while (ret != Z_STREAM_END); // L
/* clean up and return */
(void)inflateEnd(&strm);
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
}
A :in
は入力バッファです (ファイルからこのバッファに読み込みinflate
、しばらくしてから渡します。は出力データを格納するためにout
使用される出力バッファです。inflate
Bz_stream
: というオブジェクトを設定しますstrm
。これはさまざまなフィールドを保持しますが、そのほとんどはここでは重要ではありません (したがって、Z_NULL に設定されます)。重要なものはavail_in
andnext_in
とavail_out
andnext_out
です (これらは後で設定されます)。
C : 膨張プロセスを開始します。これにより、いくつかの内部データ構造がセットアップされ、inflate
関数自体が「実行可能」になります。
D : ファイルから「CHUNK」量のデータを読み取ります。読み取ったバイト数を に格納するstrm.avail_in
と、実際のデータが に入りin
ます。
E : エラーが発生した場合は、inflate
を呼び出して終了しinflateEnd
ます。ジョブ完了。
F : データがありません。
G : データの送信元を設定します (next_in
は入力バッファに設定されますin
)。
H : 私たちは今、物事を膨らませるループに入っています。ここでは、出力バッファを設定しますnext_out
。avail_out
出力がどこに行き、どれだけのスペースがあるかをそれぞれ示します。
I : 自分自身を呼び出しinflate
ます。これにより、出力がいっぱいになるまで、入力バッファーの一部が圧縮解除されます。
J : このステップで使用できるデータの量を計算します (have
はバイト数)。
K : 終了時にスペースが残るまで- これは、出力バッファーのスペースが不足するのではなくinflate
、バッファー内のデータの出力が完了したことを示します。in
それでは、入力ファイルからさらにデータを読み取ります。
L : 呼び出しのエラー コードinflate
が「happy」の場合は、もう一度ラウンドします。
明らかに、ネットワークから読み取り、メモリに圧縮解除する場合は、fread
andfwrite
を適切なread from network
and memcpy
type 呼び出しに置き換える必要があります。あなたのデータがどこから来たのかを説明するものを何も提供していないので、それらが何であるかを正確に伝えることはできません -recv
またはread
またはWSARecv
、または何か他のものを呼び出していますか? -そして、それはどこへ行くのですか?