调用inflate
后,zlib
对avail_in
和avail_out
的状态给出了什么保证?我看到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);
内部CCD_ 14循环重复,直到所有当前块都已被处理并且CCD_。然而,在该特定流的最后一个块上,inflate
没有返回错误,而是将avail_in
减少到某个非零值,并且将avail_out
也减少到某(其他)非零值。因此,由于avail_out
为非零,内部do
循环退出,并且我们继续尝试将更多数据输入到next_in
和avail_in
中,即使不是所有的avail_in
都已处理,因为avail_in
为非零。这会破坏next_in
和avail_in
中的任何内容,并且inflate
在下一次调用中失败。
我的解决方法是从更改内部循环的终止条件
strm.avail_out == 0
至
strm.avail_out == 0 || strm.avail_in > 0
但我不知道这是否正确。我觉得这可能是miniz
中的一个错误,但不确定。我本以为,如果avail_in
指示仍有数据要处理,那么avail_out
必须为零。
如果它是相关的:我使用的输入缓冲区大小是512KB,输出缓冲区是2MB。
如果inflate()
返回Z_OK
或Z_BUF_ERROR
,并且avail_out
为而不是零,则avail_in
为0。
你能提供有问题的压缩数据吗?