zlib的膨胀/放气对avail_in和avail_out有什么保证?



调用inflate后,zlibavail_inavail_out的状态给出了什么保证?我看到miniz的特殊行为,我想确保这不是对zlibAPI的误解。实际上,在调用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);

内部CCD_ 14循环重复,直到所有当前块都已被处理并且CCD_。然而,在该特定流的最后一个块上,inflate没有返回错误,而是将avail_in减少到某个非零值,并且将avail_out减少到某(其他)非零值。因此,由于avail_out为非零,内部do循环退出,并且我们继续尝试将更多数据输入到next_inavail_in中,即使不是所有的avail_in都已处理,因为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。

如果inflate()返回Z_OKZ_BUF_ERROR,并且avail_out而不是零,则avail_in0。

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

最新更新