zlib对avail_in和avail_out进行膨胀/收缩的保证是什么?

时间:2017-10-20 07:31:43

标签: compression zlib deflate inflate miniz

调用zlib后,avail_inavail_out inflate的状态提供了哪些保证?我看到miniz的特殊行为,我想确保它不是对zlib API的误解。实际上,在调用inflate后,我avail_in非零,avail_out也非零,因此某些输入看起来没有得到处理。更多细节如下。

我一直在使用miniz来扩充/收缩我流入/流出磁盘的文件。我的膨胀/收缩循环与zpipe.c中的zlib样本相同,包括使用MZ_NO_FLUSH

这个循环几乎总是有效,但今天我膨胀了一个早先放气的流并且始终保持MZ_DATA_ERROR。在添加了正确的标题后,gzip能够将其充气并且我的数据完好无损。

我的问题的根源归结为对mz_inflate的最后一次调用。我在这里包括典型的膨胀循环:

/* decompress until deflate stream ends or end of file */
do {
    strm.avail_in = fread(in, 1, CHUNK, source);
    if (ferror(source)) {
        (void)inflateEnd(&strm);
        return Z_ERRNO;
    }
    if (strm.avail_in == 0)
        break;
    strm.next_in = in;

    /* run inflate() on input until output buffer not full */
    do {
        strm.avail_out = CHUNK;
        strm.next_out = out;
        ret = inflate(&strm, Z_NO_FLUSH);
        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;
        if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
            (void)inflateEnd(&strm);
            return Z_ERRNO;
        }
    } while (strm.avail_out == 0);

    /* done when inflate() says it's done */
} while (ret != Z_STREAM_END);

内部do循环重复,直到处理完所有当前块并且avail_out有额外空间。但是,在此特定流的最后一个块上,inflate未返回错误,而是将avail_in减少为某个非零数字,并且还会减少avail_out 到某个(其他)非零数字。因此内部do循环退出,因为avail_out非零,我们尝试将更多数据导入next_inavail_in,即使不是全部avail_in已处理1}},因为avail_in非零。这会破坏next_inavail_in中的任何内容,并且inflate会在下一次通话中失败。

我的解决方法是从

更改内循环的终止条件
strm.avail_out == 0

strm.avail_out == 0 || strm.avail_in > 0

但我不知道这是否正确。我觉得这可能是miniz中的错误,但我不确定。我原以为如果avail_in表示仍有待处理的数据,则avail_out必须为零。

如果相关:我使用的输入缓冲区大小为512KB,输出缓冲区为2MB。

1 个答案:

答案 0 :(得分:2)

如果inflate()返回Z_OKZ_BUF_ERROR,而avail_out 为零,则avail_in 为< / em>零。

您能提供有问题的压缩数据吗?