繁体   English   中英

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

[英]Uncompress a gzip File in Memory Using zlib Version 1.1.3

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

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

gzip文件格式表示有10个字节的标头,可选的标头,数据和页脚。 是否有可能确定数据从何处开始并去除该部分? 我对此主题进行了搜索,有几个人建议使用inflateInit2()。 但是,在我的zlib版本中,该函数被奇怪地注释掉了。 还有其他选择吗?

我遇到了相同的问题,其他zlib版本(1.2.7)
我不知道为什么inflateInit2()被注释掉。

在不调用inflateInit2的情况下,您可以执行以下操作:

err = inflateInit(&d_stream);
err = inflateReset2(&d_stream, 31);

inflateInit也调用inflateReset2。 在inflateInit内部,WindowBits设置为15(二进制1111)。 但是您必须将它们设置为31(11111)才能使gzip工作。

原因在这里:

在inflateReset2内部完成以下操作:

wrap = (windowBits >> 4) + 1;

如果窗口位设置为15(1111二进制),则结果为1;如果窗口位设置为31(11111),结果为2。

现在,如果您调用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

是否有可能确定数据从何处开始并去除该部分?

Gzip具有以下魔术数字

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

一旦有了偏移量,就可以执行复制和粘贴操作,或覆盖其他字节等。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM