我有一个内存中的gzip文件,我想使用zlib,版本1.1.3解压缩它。 Uncompress()返回-3,Z_DATA_ERROR,表示源数据已损坏。
我知道我的内存缓冲区是正确的 - 如果我将缓冲区写入文件,它与我的源gzip文件相同。
The gzip file format表示有一个10字节的标头,可选的标头,数据和页脚。是否有可能确定数据的开始位置,并删除该部分?我对这个主题进行了搜索,有几个人建议使用inflateInit2()。但是,在我的zlib版本中,该函数被奇怪地注释掉了。还有其他选择吗?
答案 0 :(得分:1)
我遇到了同样的问题,其他zlib版本(1.2.7)
我不知道为什么inflateInit2()被注释掉了。
如果不调用inflateInit2,您可以执行以下操作:
err = inflateInit(&d_stream);
err = inflateReset2(&d_stream, 31);
inflateReset2也由inflateInit调用。在inflateInit内部,WindowBits设置为15(1111二进制)。但是你必须将它们设置为31(11111)以使gzip正常工作。
原因在于:
在inflateReset2内部完成以下操作:
wrap = (windowBits >> 4) + 1;
如果窗口位设置为15(1111二进制)则导致1,如果窗口位设置为31,则导致2(11111)
现在,如果你调用inflate(),HEAD状态中的以下行检查state-> wrap值以及gzip的幻数
if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */
因此,使用以下代码,我能够进行内存中的gzip解压缩: (注意:此代码假定要解压缩的完整数据在内存中,并且解压缩数据的缓冲区足够大)
int err;
z_stream d_stream; // decompression stream
d_stream.zalloc = (alloc_func)0;
d_stream.zfree = (free_func)0;
d_stream.opaque = (voidpf)0;
d_stream.next_in = deflated; // where deflated is a pointer the the compressed data buffer
d_stream.avail_in = deflatedLen; // where deflatedLen is the length of the compressed data
d_stream.next_out = inflated; // where inflated is a pointer to the resulting uncompressed data buffer
d_stream.avail_out = inflatedLen; // where inflatedLen is the size of the uncompressed data buffer
err = inflateInit(&d_stream);
err = inflateReset2(&d_stream, 31);
err = inflateEnd(&d_stream);
只需在inflateInit2()中进行评论即可获得更好的解决方案。在这里你可以直接设置WindowBits
答案 1 :(得分:0)
是否可以确定数据的开始位置,并将该部分删除?
Gzip有以下magic number:
static const unsigned char gzipMagicBytes[] = { 0x1f, 0x8b, 0x08, 0x00 };
您可以通读文件流并查找这些字节:
static const int testElemSize = sizeof(unsigned char);
static const int testElemCount = sizeof(gzipMagicBytes);
const char *fn = "foo.bar";
FILE *fp = fopen(fn, "rbR");
char testMagicBuffer[testElemCount] = {0};
unsigned long long testMagicOffset = 0ULL;
if (fp != NULL) {
do {
if (memcmp(testMagicBuffer, gzipMagicBytes, sizeof(gzipMagicBytes)) == 0) {
/* we found gzip magic bytes, do stuff here... */
fprintf(stdout, "gzip stream found at byte offset: %llu\n", testMagicOffset);
break;
}
testMagicOffset += testElemSize * testElemCount;
fseek(fp, testMagicOffset - testElemCount + 1, SEEK_SET);
testMagicOffset -= testElemCount + 1;
} while (fread(testMagicBuffer, testElemSize, testElemCount, fp));
}
fclose(fp);
获得偏移后,您可以执行复制和粘贴操作,或覆盖其他字节等。