使用zlib版本1.1.3解压缩内存中的gzip文件

问题描述:

我有一个内存中的gzip文件,我想使用zlib 1.1.3版解压缩它。 Uncompress()返回-3,Z_DATA_ERROR,表示源数据已损坏。使用zlib版本1.1.3解压缩内存中的gzip文件

我知道我的内存缓冲区是正确的 - 如果我将缓冲区写入文件,它与我的源gzip文件相同。

The gzip file format表示有一个10字节的标题,可选的标题,数据和页脚。是否有可能确定数据的起始位置,并将该部分去掉?我对这个主题进行了搜索,几个人建议使用inflateInit2()。但是,在我的zlib版本中,该函数被奇怪地注释掉了。还有其他的选择吗?

+4

你有什么特别的理由想要使用1.1.3版本吗?版本1.1.4于2002年3月发布,最新版本为1.2.5。 – ruakh 2012-01-07 03:04:28

+0

我知道我使用的版本比较陈旧,但这是一个不允许更新zlib的传统项目。 – gmletzkojr 2012-01-07 13:33:00

是否可以确定数据的起始位置,并将该部分去掉?

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); 

一旦失调,你可以做复制和粘贴操作或覆盖其他字节等。

我遇到了同样的问题,其他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二进制)和2,如果窗口位被设置,这导致1 31(11111)

现在如果调用充气()在HEAD状态以下行与幻数gzip的

if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ 
01沿着检查状态 - >包裹值

所以用下面的代码,我能够做内存的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