zlib 的 inflate/deflate 对 avail_in 和 avail_out 有什么保证?

What guarantees does zlib's inflate/deflate make about avail_in and avail_out?

在调用 inflate 之后,zlibavail_inavail_out 的状态提供什么保证?我看到 miniz 的特殊行为,我想确定这不是对 zlib API 的误解。实际上,在调用 inflate 之后,我有 avail_in non-zero,avail_out 也有 non-zero,所以有些输入看起来没有得到处理。下面有更多详细信息。

我一直在使用miniz to inflate/deflate a file I stream to/from disk. My inflate/deflate loop is identical to the zlib sample in zpipe.c,包括使用MZ_NO_FLUSH

这个循环几乎总是有效,但今天我给早些时候放气的流充气,并始终如一地得到 MZ_DATA_ERROR。不过,在添加适当的 header 之后,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 没有 return 错误,而是会将 avail_in 减少到某个 non-zero 数字,并且会减少 avail_out 到一些(其他)non-zero号码。所以内部 do 循环退出,因为 avail_out 是 non-zero,我们尝试将更多数据放入 next_inavail_in,即使不是全部avail_in 已被处理,因为 avail_in 是 non-zero。这破坏了 next_inavail_in 中的任何内容,并且 inflate 在下一次调用时失败。

我的解决方法是将内部循环的终止条件从

strm.avail_out == 0

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

但我不知道这是否正确。我觉得这可能是 miniz 中的错误,但我不确定。我会想,如果avail_in表示还有数据要处理,那avail_out一定是零。

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

如果 inflate() returns Z_OKZ_BUF_ERROR,并且 avail_out 不是 零,则 avail_in 零。

能否提供相关的压缩数据?