我正在尝试使用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 documentation中,它们通过do / while循环不断调用,以检查Z_STREAM_END标志。我在这里有点困惑,因为似乎它们是通过文件工作的,而我不是。我是否也需要此循环,或者是否可以提供char数组而不循环遍历inflate?

这里的任何指导将不胜感激。我对使用压缩和C++都是新手。

谢谢。

最佳答案

假设您给inflate一个适当且完整的“压缩流”,并且有足够的空间来输出数据,则只需要调用inflate一次。

编辑:它没有像zlib documentation那样清楚地写出来,但是它确实说:



当然,对于尚未“在内存中并已完成”的任何流,您都希望逐块运行它,因为这将减少总运行时间(您可以在[从网络或文件系统接收数据的同时解压缩预取缓存])。

这是示例代码中的全部功能。我从页面上删除了文本组件以集中代码,并用字母// 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;
}

:in是输入缓冲区(我们从文件中读取该缓冲区,然后稍后将其传递给inflateout是输出缓冲区,inflate使用它来存储输出数据。

B :设置一个名为z_streamstrm对象。它包含各种字段,其中大多数字段在这里并不重要(因此设置为Z_NULL)。重要的是avail_innext_in以及avail_outnext_out(稍后设置)。

C :开始通胀过程。这将建立一些内部数据结构,并使inflate函数本身“准备运行”。

D :从文件中读取“大量”数据。将读取的字节数存储在strm.avail_in中,实际数据放入in中。

E :如果我们出错了,请通过调用inflate完成inflateEnd。任务完成。

F :无可用数据,我们完成了。

G :设置数据的来源(next_in设置为输入缓冲区in)。

H :我们现在处于循环中以膨胀事物。在这里,我们设置输出缓冲区:next_outavail_out分别指示输出到达何处以及有多少空间。

:调用inflate本身。这将解压缩一部分输入缓冲区,直到输出已满。

J :计算此步骤中可用的数据量(have是字节数)。

K :直到inflate完成后我们还有空间-这表示in缓冲区中的数据输出完成,而不是out缓冲区中的空间不足。因此,是时候从输入文件中读取更多数据了。

L :如果inflate调用中的错误代码为“happy”,请重新处理。

现在,显然,如果您正在从网络中读取数据并解压缩到内存中,则需要用一些合适的freadfwrite类型调用替换read from networkmemcpy。我无法确切地告诉您这些是什么,因为您还没有提供任何解释数据来源的信息-您是在调用recv还是readWSARecv,还是其他? -它要去哪里?

09-07 08:18