如何在 2013 zlib API 界面中模仿(被黑)1998 uncompress() 上的 "use_crc" 标志?
How to mimic a "use_crc" flag on (hacked) 1998 uncompress() in 2013 zlib API interface?
我正在将一个项目的代码从 1998 版的 zlib 更新到 2013 版的 zlib。似乎发生了变化的一件事是,解压缩函数上曾经有一个 "use_crc" 标志,现在似乎不见了:
int ZEXPORT uncompress (dest, destLen, source, sourceLen, use_crc)
Bytef *dest;
uLongf *destLen;
const Bytef *source;
uLong sourceLen;
int use_crc; // <-- vanished (?)
(UPDATE: 正如@Joe 所指出的,这很可能是 third-party modification。标题相应更新。剩下的问题是仍然适用,如 "how should I best do this with today's stock zlib".)
在我研究的代码中,uncompress() 被解构 .zip 的二进制格式并传入 "payload" 数据的东西调用。该代码一直将 crc 标志作为 1 传递。如果未使用该标志,它将获得 Z_DATA_ERROR (-3)。 (没有 use_crc 标志的 zlib 得到 Z_DATA_ERROR 就好像该标志是假的一样。)
在实验中,我发现非常小的文件在没有 use_crc 的情况下也能正常工作。然后小计数文件在 "12345678901234"
和 "123456789012345"
之间交叉到 not-working。原因是:这是第一个被缩小而不是未压缩存储的文件 (zip 所谓的节省“6%”)
在考虑让 zlib 接受它的选项时,我尝试了很多方法。这包括尝试 16 + MAX_WBITS。似乎没有什么能像旧代码那样处理 zip test.zip test.txt 中的有效负载。
如果我愿意从我的目标大小中减去一个,我似乎能够抑制错误检查...在丢失一个字节的情况下。这是带有硬编码的最小 zip 负载的简单测试程序:
#include <stdio.h>
#include "zlib.h"
int main(int argc, char *argv[]) {
char compressed[] = { 0x78, 0x9C, 0x33, 0x34, 0x32, 0x36, 0x31, 0x35, 0x33,
0xB7, 0xB0, 0x34, 0x30, 0x04, 0xB1, 0xB8, 0x00, 0x31, 0x30, 0xB1, 0x30,
0x10, 0x00, 0x00, 0x00 }; // last 4 bytes are size (16)
char uncompressed[16 + 1]; // account for null terminator
int ret; z_stream strm;
memset(uncompressed, 'X', 16);
uncompressed[16] = '[=13=]';
strm.zalloc = strm.zfree = strm.opaque = Z_NULL;
strm.total_out = 0;
strm.avail_in = 25;
strm.next_in = compressed;
ret = inflateInit2(&strm, MAX_WBITS /* + 16 */); // it is Z_OK
strm.avail_out = 15; // 16 gives error -3: "incorrect header check"
strm.next_out = uncompressed;
ret = inflate(&strm, Z_NO_FLUSH);
if (ret != /* Z_STREAM_END */ Z_OK) { // doesn't finish...
printf("inflate() error %d: %s\n", ret, strm.msg);
return 2;
}
inflateEnd(&strm);
printf("successful inflation: %s\n", uncompressed);
return 0;
}
输出为:
successful inflation: 123456789012345X
显示数据正在解压缩,但我们需要全部 16 个字节。 (应该接收的文件中有一个换行符。) 16 + MAX_WBITS 甚至无法得到。
知道出了什么问题吗?似乎没有任何设置排列可以毫无错误地到达那里。
没有,zlib 接口自 20 多年前推出以来没有发生过不兼容的更改。 uncompress()
.
从来没有 use_crc
参数
你举的例子是一个two-byte zlib header, deflate-compressed数据,big中deflate数据的CRC-32 -endian 顺序,后跟 little-endian 顺序的 four-byte 长度。这是 zlib 和 gzip 包装器的真正奇怪的混搭,与您一直提到的 zip 格式没有任何关系。 ("payloads inside of zip files" 是什么意思?)zlib 在末尾有一个 big-endian 顺序的 Adler-32,而 gzip 有一个 little-endian 顺序的 CRC-32,后跟 four-byte little-endian 顺序的长度。这个把它们混在一起,包括字节顺序,然后故意误导性地在上面放一个有效的 zlib header,这是对这个世界上所有善良和体面的东西的侮辱。
我很确定想出这种格式的人当时喝醉了。
为了对此进行解码,您需要:
丢弃流的前两个字节。 (您可以检查它是否是一个有效的 zlib header,但事实证明这在解释流的其余部分时毫无意义。)
使用raw deflate,用inflateInit2(&strm, -15)
初始化,解压缩数据。解压缩时,跟踪总长度并使用 crc32()
.
计算 CRC-32
deflate 数据完成后,读取接下来的四个字节,assemble它们按big-endian顺序为32位值,并将其与CRC-32进行比较你计算了。如果不匹配,则流已损坏,或者它不是这些格式奇怪的流之一。 (也许再试一次,将它解码为普通的 zlib 流。如果它有一个好的 zlib header,那么它可能就是它的实际情况,而不是这些 Frankenstein 流之一。)
读取接下来的四个字节和 assemble little-endian 顺序的字节,并将其与未压缩数据的长度进行比较。如果不匹配,那就是流损坏了,或者不是你想的那样。
如果数据没有到此结束,则说明还有其他奇怪的事情正在发生。请教喝醉的人
我正在将一个项目的代码从 1998 版的 zlib 更新到 2013 版的 zlib。似乎发生了变化的一件事是,解压缩函数上曾经有一个 "use_crc" 标志,现在似乎不见了:
int ZEXPORT uncompress (dest, destLen, source, sourceLen, use_crc)
Bytef *dest;
uLongf *destLen;
const Bytef *source;
uLong sourceLen;
int use_crc; // <-- vanished (?)
(UPDATE: 正如@Joe 所指出的,这很可能是 third-party modification。标题相应更新。剩下的问题是仍然适用,如 "how should I best do this with today's stock zlib".)
在我研究的代码中,uncompress() 被解构 .zip 的二进制格式并传入 "payload" 数据的东西调用。该代码一直将 crc 标志作为 1 传递。如果未使用该标志,它将获得 Z_DATA_ERROR (-3)。 (没有 use_crc 标志的 zlib 得到 Z_DATA_ERROR 就好像该标志是假的一样。)
在实验中,我发现非常小的文件在没有 use_crc 的情况下也能正常工作。然后小计数文件在 "12345678901234"
和 "123456789012345"
之间交叉到 not-working。原因是:这是第一个被缩小而不是未压缩存储的文件 (zip 所谓的节省“6%”)
在考虑让 zlib 接受它的选项时,我尝试了很多方法。这包括尝试 16 + MAX_WBITS。似乎没有什么能像旧代码那样处理 zip test.zip test.txt 中的有效负载。
如果我愿意从我的目标大小中减去一个,我似乎能够抑制错误检查...在丢失一个字节的情况下。这是带有硬编码的最小 zip 负载的简单测试程序:
#include <stdio.h>
#include "zlib.h"
int main(int argc, char *argv[]) {
char compressed[] = { 0x78, 0x9C, 0x33, 0x34, 0x32, 0x36, 0x31, 0x35, 0x33,
0xB7, 0xB0, 0x34, 0x30, 0x04, 0xB1, 0xB8, 0x00, 0x31, 0x30, 0xB1, 0x30,
0x10, 0x00, 0x00, 0x00 }; // last 4 bytes are size (16)
char uncompressed[16 + 1]; // account for null terminator
int ret; z_stream strm;
memset(uncompressed, 'X', 16);
uncompressed[16] = '[=13=]';
strm.zalloc = strm.zfree = strm.opaque = Z_NULL;
strm.total_out = 0;
strm.avail_in = 25;
strm.next_in = compressed;
ret = inflateInit2(&strm, MAX_WBITS /* + 16 */); // it is Z_OK
strm.avail_out = 15; // 16 gives error -3: "incorrect header check"
strm.next_out = uncompressed;
ret = inflate(&strm, Z_NO_FLUSH);
if (ret != /* Z_STREAM_END */ Z_OK) { // doesn't finish...
printf("inflate() error %d: %s\n", ret, strm.msg);
return 2;
}
inflateEnd(&strm);
printf("successful inflation: %s\n", uncompressed);
return 0;
}
输出为:
successful inflation: 123456789012345X
显示数据正在解压缩,但我们需要全部 16 个字节。 (应该接收的文件中有一个换行符。) 16 + MAX_WBITS 甚至无法得到。
知道出了什么问题吗?似乎没有任何设置排列可以毫无错误地到达那里。
没有,zlib 接口自 20 多年前推出以来没有发生过不兼容的更改。 uncompress()
.
use_crc
参数
你举的例子是一个two-byte zlib header, deflate-compressed数据,big中deflate数据的CRC-32 -endian 顺序,后跟 little-endian 顺序的 four-byte 长度。这是 zlib 和 gzip 包装器的真正奇怪的混搭,与您一直提到的 zip 格式没有任何关系。 ("payloads inside of zip files" 是什么意思?)zlib 在末尾有一个 big-endian 顺序的 Adler-32,而 gzip 有一个 little-endian 顺序的 CRC-32,后跟 four-byte little-endian 顺序的长度。这个把它们混在一起,包括字节顺序,然后故意误导性地在上面放一个有效的 zlib header,这是对这个世界上所有善良和体面的东西的侮辱。
我很确定想出这种格式的人当时喝醉了。
为了对此进行解码,您需要:
丢弃流的前两个字节。 (您可以检查它是否是一个有效的 zlib header,但事实证明这在解释流的其余部分时毫无意义。)
使用raw deflate,用
inflateInit2(&strm, -15)
初始化,解压缩数据。解压缩时,跟踪总长度并使用crc32()
. 计算 CRC-32
deflate 数据完成后,读取接下来的四个字节,assemble它们按big-endian顺序为32位值,并将其与CRC-32进行比较你计算了。如果不匹配,则流已损坏,或者它不是这些格式奇怪的流之一。 (也许再试一次,将它解码为普通的 zlib 流。如果它有一个好的 zlib header,那么它可能就是它的实际情况,而不是这些 Frankenstein 流之一。)
读取接下来的四个字节和 assemble little-endian 顺序的字节,并将其与未压缩数据的长度进行比较。如果不匹配,那就是流损坏了,或者不是你想的那样。
如果数据没有到此结束,则说明还有其他奇怪的事情正在发生。请教喝醉的人