1

zlib を使用して、gzip で圧縮された一部の IP パケット ペイロード データを圧縮解除 (膨張) しようとしています。ただし、インフレーションをカバーする zlib が提供するドキュメントの一部を理解するのが難しい場合があります。プログラムが埋める char 配列がありますが、次のコードでそれを膨らませることができないようです:

const u_char payload; /*contains gzip data, 
                      captured prior to this point in the program*/

/*read compressed contents*/
int ret; //return val
z_stream stream;
unsigned char out[MEM_CHUNK]; //output array, MEM_CHUNK defined as 65535

/* allocate inflate state */
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;
stream.avail_in = size_payload; // size of input
stream.next_in = (Bytef *)payload; // input char array
stream.avail_out = (uInt)sizeof(out); // size of output
stream.next_out = (Bytef *)out; // output char array

ret = inflateInit(&stream);
inflate(&stream, Z_NO_FLUSH);
inflateEnd(&stream);

printf("Inflate: %s\n\n", out);

zlibのドキュメントでは、do/while ループを介して継続的に呼び出され、Z_STREAM_END フラグをチェックする inflate があります。私はそうではありませんが、彼らはファイルから作業しているように見えるので、ここで少し混乱しています。このループも必要ですか、それとも inflate をループせずに char 配列を提供できますか?

ここでのガイダンスは本当にありがたいです。私は、圧縮と C++ の両方を扱うのにかなり慣れていません。

ありがとう。

4

1 に答える 1

5

適切で完全な「圧縮ストリーム」を提供していて、データを出力するのに十分なスペースがあると仮定するとinflate、呼び出す必要があるのはinflate1 回だけです。

編集: 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_inandnext_inavail_outandnext_outです (これらは後で設定されます)。

C : 膨張プロセスを開始します。これにより、いくつかの内部データ構造がセットアップされ、inflate関数自体が「実行可能」になります。

D : ファイルから「CHUNK」量のデータを読み取ります。読み取ったバイト数を に格納するstrm.avail_inと、実際のデータが に入りinます。

E : エラーが発生した場合は、inflateを呼び出して終了しinflateEndます。ジョブ完了。

F : データがありません。

G : データの送信元を設定します (next_inは入力バッファに設定されますin)。

H : 私たちは今、物事を膨らませるループに入っています。ここでは、出力バッファを設定しますnext_outavail_out出力がどこに行き、どれだけのスペースがあるかをそれぞれ示します。

I : 自分自身を呼び出しinflateます。これにより、出力がいっぱいになるまで、入力バッファーの一部が圧縮解除されます。

J : このステップで使用できるデータの量を計算します (haveはバイト数)。

K : 終了時にスペースが残るまで- これは、出力バッファーのスペースが不足するのではなくinflate、バッファー内のデータの出力が完了したことを示します。inそれでは、入力ファイルからさらにデータを読み取ります。

L : 呼び出しのエラー コードinflateが「happy」の場合は、もう一度ラウンドします。

明らかに、ネットワークから読み取り、メモリに圧縮解除する場合は、freadandfwriteを適切なread from networkand memcpytype 呼び出しに置き換える必要があります。あなたのデータがどこから来たのかを説明するものを何も提供していないので、それらが何であるかを正確に伝えることはできません -recvまたはreadまたはWSARecv、または何か他のものを呼び出していますか? -そして、それはどこへ行くのですか?

于 2013-06-24T22:26:00.773 に答える