与压缩相比,为什么提取需要不同的zlib窗口位值?

时间:2015-03-12 07:19:12

标签: c++ c zlib compression

我正在尝试使用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_LEVEL1,以提供最佳速度。然后我在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+1631表示窗口位,8表示内存级别,和Z_DEFAULT_STRATEGY用于战略。

以前的inflateInit()电话不起作用;相反,我必须使用inflateInit2()并指定修改后的窗口位值:

int ret = inflateInit2(this->z_stream_ptr, ZLIB_TEST_COMPRESSION_WINDOW_BITS + 16);

在这种情况下,窗口位值不是31调用中的deflateInit2(),而是15+3247

如果我使用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]

此处-3Z_DATA_ERROR相同。

根据文档,31deflateInit2()一起使用应该写一个gzip标题和预告片。因此,应该期望以下31调用inflateInit2()能够提取标头信息。

为什么修改后的值47有效,而31

我的测试项目大致类似于zlib站点上的示例代码,但提取/通胀代码除外,它一次膨胀一个z_stream块并解析换行输出字符。

只有当提出新的提取数据缓冲区时才会运行inflate(),这有点特别 - 比如inflate()次调用之间缺少标题信息 - 而不是在一次传递中运行整个提取,如在zlib示例代码中那样?

我更大的调试问题是寻找一种强大的方法来提取zlib - 仅在请求时压缩数据,这样我就可以一次提取一行数据,而不是获取整个提取的文件。关于我处理zlib格式参数的方式似乎搞砸了我,但我无法弄清楚为什么或如何解决这个问题。

1 个答案:

答案 0 :(得分:5)

deflateInit()inflateInit(),以及deflateInit2()inflateInit2()以及{0}中的windowBits所有进程zlib包装的deflate数据。 (请参阅RFC 1950RFC 1951。)

在-1 ..- 15中具有负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的重点是一次解压缩一块。