字符串在膨胀后包含许多'\0'

string contain many '\0' after inflate

我尝试解压用 zlib 压缩的数据块,作者说对于解压我必须使用 inflate_initinflateZ_SYNC_FLUSH。我确定这一定有效,因为它以这种方式在 php 上有效:

$temp = substr($temp, 2, -4);
$temp{0} = chr(ord($temp{0}) | 1);
$temp = gzinflate($temp);

但是我检查了很多在 C++ 上解压缩这个的方法,但每次都失败了。 这是其中之一:

char compressedblockbuffer[3371];
char uncompressedblockbuffer[8192];

is.read(compressedblockbuffer, 3371);

z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 3371;
strm.next_in = (Bytef *)compressedblockbuffer;
strm.avail_out = 8192;
strm.next_out = (Bytef *)uncompressedblockbuffer;

inflateInit(&strm);
inflate(&strm, Z_SYNC_FLUSH);
inflateEnd(&strm);

这不是完整的代码,只是展示问题的示例,这就是我指定已知大小的原因。 我使用最后一个 zlib 实现,所以自 2003-2004 年以来 zlib 膨胀可能会发生什么变化? 所以结果是:

看来 uncompressedblockbuffer 在 2、3、4 索引和许多其他索引处包含“\0”,如果我将其打印到控制台,我只会看到两个第一个元素。

更新:

您要解压什么样的数据?许多二进制格式在其数据中完全接受 NUL 字节,因为它只是读作 0 值。例如,在许多格式的图像数据内部,它只表示该通道或像素中的 0 值(取决于数据大小)。更不用说,二进制格式不一定按字节读取。 NUL 字节实际上可能是 2 字节或 4 字节值的一部分。

这是尝试将二进制数据读取为字符串时出现的问题。二进制数据不需要遵循文本规则。这就是为什么数据边界通常是一个单独的 size 值,因为它不能像文本那样终止于 NUL 值。

如果您有未压缩的原始数据用于比较,要么将该数据加载到内存中并比较数据,要么将解压缩后的数据保存到文件中并使用 diff 工具对文件进行二进制比较。

如果 PHP 中的 gzinflate() 可以处理数据,那么您的代码将不会。 gzinflate() 需要原始压缩数据。您的代码正在寻找 zlib 包装的压缩数据。如果你想解码原始压缩数据,你需要使用 inflateInit2(&strm, -15) 代替。

您对 inflate() 的调用可能 return 出现了您没有检查的错误。您需要始终检查 zlib 例程的 return 代码,或者就此而言,任何可能 return 出错的函数。