我正在尝试使用zlib
1.2.8的一些代码来调试问题。问题是这个较大的项目可以创建存档,但在尝试提取该存档时会遇到Z_DATA_ERROR
标题问题。
为此,我用C ++编写了一个小型测试程序,压缩(“缩小”)指定的常规文件,将压缩数据写入第二个常规文件,并提取(“膨胀”)到第三个常规文件,一次一行。然后我diff
第一个和第三个文件,以确保我得到相同的字节。
作为参考,此测试项目位于:https://github.com/alexpreynolds/zlib-test并在Clang下编译(也应在GNU GCC下编译)。
我的一个大问题是如何在我的大项目中正确处理标题数据。
在我的第一个测试场景中,我可以使用以下代码设置压缩机制:
z_error = deflateInit(this->z_stream_ptr, ZLIB_TEST_COMPRESSION_LEVEL);
此处,ZLIB_TEST_COMPRESSION_LEVEL
为1
,以提供最佳速度。然后我在deflate()
指针上运行z_stream
,直到没有任何东西从压缩中消失。
要提取这些字节,我可以使用inflateInit()
:
int ret = inflateInit(this->z_stream_ptr);
那么标题格式是什么?在这种情况下?
在我的第二个测试场景中,我设置了这样的deflate机器:
z_error = deflateInit2(this->z_stream_ptr,
ZLIB_TEST_COMPRESSION_LEVEL,
ZLIB_TEST_COMPRESSION_METHOD,
ZLIB_TEST_COMPRESSION_WINDOW_BITS,
ZLIB_TEST_COMPRESSION_MEM_LEVEL,
ZLIB_TEST_COMPRESSION_STRATEGY);
这些deflate常量分别为1
级别,Z_DEFLATED
方法,15+16
或31
表示窗口位,8
表示内存级别,和Z_DEFAULT_STRATEGY
用于战略。
以前的inflateInit()
电话不起作用;相反,我必须使用inflateInit2()
并指定修改后的窗口位值:
int ret = inflateInit2(this->z_stream_ptr, ZLIB_TEST_COMPRESSION_WINDOW_BITS + 16);
在这种情况下,窗口位值不是31
调用中的deflateInit2()
,而是15+32
或47
。
如果我使用31
(或除47
之外的任何其他值),那么我会在后续的Z_DATA_ERROR
来电中获得inflate()
。也就是说,如果我为inflateInit2()
调用使用相同的窗口位:
int ret = inflateInit2(this->z_stream_ptr, ZLIB_TEST_COMPRESSION_WINDOW_BITS);
然后我在尝试inflate()
时遇到以下错误:
Error: inflate to stream failed [-3]
此处-3
与Z_DATA_ERROR
相同。
根据文档,31
与deflateInit2()
一起使用应该写一个gzip
标题和预告片。因此,应该期望以下31
调用inflateInit2()
能够提取标头信息。
为什么修改后的值47
有效,而31
?
我的测试项目大致类似于zlib
站点上的示例代码,但提取/通胀代码除外,它一次膨胀一个z_stream
块并解析换行输出字符。
只有当提出新的提取数据缓冲区时才会运行inflate()
,这有点特别 - 比如inflate()
次调用之间缺少标题信息 - 而不是在一次传递中运行整个提取,如在zlib
示例代码中那样?
我更大的调试问题是寻找一种强大的方法来提取zlib
- 仅在请求时压缩数据,这样我就可以一次提取一行数据,而不是获取整个提取的文件。关于我处理zlib
格式参数的方式似乎搞砸了我,但我无法弄清楚为什么或如何解决这个问题。
答案 0 :(得分:5)
deflateInit()
和inflateInit()
,以及deflateInit2()
和inflateInit2()
以及{0}中的windowBits
所有进程zlib包装的deflate数据。 (请参阅RFC 1950和RFC 1951。)
deflateInit2()
的 inflateInit2()
和windowBits
处理原始deflate数据,没有标题或预告片。 16 {31}中deflateInit2()
和inflateInit2()
windowBits
,即16添加到0..15,处理gzip包装的deflate数据(RFC 1952)。在{32}中使用inflateInit2()
的{{1}}(32添加到0..15)将自动检测gzip或zlib标头(但不是原始deflate数据),并相应地解压缩。
为什么修改后的值47有效,但不是31?
31确实有效。我没有尝试查看你的代码来调试它。
只有在新的时候才能运行inflate() 要求提取数据的缓冲区 - 就像标题信息一样 inflate()调用之间缺少 - 而不是运行整个 一次传递提取,如zlib示例代码?
我无法弄清楚你在这里问的是什么。也许一个更明确的例子会有所帮助。 windowBits
的重点是一次解压缩一块。