ZLib Inflate()函数失败,错误代码为-3,即Z_DATA_ERROR。

10

我正在尝试通过调用inflate函数来解压文件,但无论我使用网站上的示例程序,它都会始终失败并显示Z_DATA_ERROR。我认为可能是我拥有的zip文件不受支持。下面附上zip头的图片。

enter image description here

以下是我编写的执行解压缩的函数。我一次性读取整个文件(约34KB)并将其传递给此函数。请注意,我已经尝试过同时传递具有zip头和跳过zip文件头仅传递压缩数据,但两者在调用inflate()时均失败并显示Z_DATA_ERROR。

int CHttpDownloader::unzip(unsigned char * pDest, unsigned long * ulDestLen, unsigned char *  pSource, int iSourceLen){
    int ret = 0;
    unsigned int uiUncompressedBytes = 0; // Number of uncompressed bytes returned from inflate() function
    unsigned char * pPositionDestBuffer = pDest; // Current position in dest buffer
    unsigned char * pLastSource = &pSource[iSourceLen]; // Last position in source buffer
    z_stream strm;

    // Skip over local file header
    SLocalFileHeader * header = (SLocalFileHeader *) pSource;
    pSource += sizeof(SLocalFileHeader) + header->sFileNameLen + header->sExtraFieldLen;


    // We should now be at the beginning of the stream data
    /* allocate inflate state */
    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;
    strm.avail_in = 0;
    strm.next_in = Z_NULL;
    ret = inflateInit2(&strm, 16+MAX_WBITS);
    if (ret != Z_OK){
        return -1;
    }

    // Uncompress the data
    strm.avail_in = header->iCompressedSize; //iSourceLen;
    strm.next_in = pSource;

    do {
        strm.avail_out = *ulDestLen;
        strm.next_out = pPositionDestBuffer;
        ret = inflate(&strm, Z_NO_FLUSH);
        assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
        switch (ret) {
            case Z_NEED_DICT:
                ret = Z_DATA_ERROR;     /* and fall through */
            case Z_DATA_ERROR:
            case Z_MEM_ERROR:
                (void)inflateEnd(&strm);
                return -2;
        }
        uiUncompressedBytes = *ulDestLen - strm.avail_out;
        *ulDestLen -= uiUncompressedBytes; // ulDestSize holds number of free/empty bytes in buffer
        pPositionDestBuffer += uiUncompressedBytes;
    } while (strm.avail_out == 0);

    // Close the decompression stream
    inflateEnd(&strm);
    ASSERT(ret == Z_STREAM_END);

    return 0;
}
所以我的问题是,我读入的ZIP文件类型不被ZLib的inflate()函数支持吗?还是我的CHttpDownloader::unzip()函数有什么问题?感谢任何帮助 :)

所以我的问题是,我读入的ZIP文件类型是否不受ZLib的inflate()函数支持?还是我的CHttpDownloader::unzip()函数存在问题?感谢任何帮助 :)


你尝试过使用另一个你创建的简单压缩文件来运行这段代码吗? - Jonathon Reinhart
我刚刚尝试了一下,使用WinZip创建的一个简单的压缩文件,结果出现了相同的错误。 - Megan
看看Mark Adler的回答。他在这个话题上绝对是正确的 ;) Zlib不是ZIP。ZIP是建立在zlib压缩算法之上的存档文件格式。 - Nickolay Olshevsky
2个回答

21

Inflate()因为没有找到GZip标头而失败。如果你用以下方式初始化流:

ret = inflateInit2(&strm, -MAX_WBITS);

传递负的窗口位值可以防止inflate检查gzip或zlib头文件,并且解压缩按预期工作。


这就是你如何进行解压缩,如果你首先处理 zip 头信息,以便找到 deflate 流。 - Mark Adler
谢谢你的帮助。我没有使用Minizip,因为我要解压缩的文件是在内存中而不是写入磁盘。跳过本地文件头并使用负窗口位调用inflateinit2解决了这个问题。之前我并不太理解zip文件和deflate流的区别,但现在更清楚了。再次感谢 :) - Megan
2
哇,这太疯狂了吧?文档上真的一点线索都没有。我觉得这应该是zlib常见问题解答中的一部分。 - paulm
这太疯狂了。 - Fattie

7
那个以50 4B 03 04开头的文件是一个zip文件。zlib库不能直接处理zip文件,它能帮助实现压缩、解压和CRC计算。但是,你需要其他代码来处理zip文件格式。
你可以查看zlib分发中的contrib/minizip,或者使用libzip

1
看起来混合使用ZIP/zlib就像混合使用FTP和SFTP一样)。 - Nickolay Olshevsky
1
她已经考虑到这一点,并正在尝试解压缩压缩存档中的原始数据。 - David Menard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接