ZLib Inflate() failing with -3 Z_DATA_ERROR

Megan picture Megan · Sep 9, 2013 · Viewed 15.6k times · Source

I am trying to unzip a file by calling the inflate function but it always fails with Z_DATA_ERROR even when I use the example program from the website. I am thinking that maybe the zip file I have is not supported. I have attached a picture of the zip header below.

enter image description here

And here is the function that I wrote to perform the unzipping. I read in the whole file at once (about 34KB) and pass it into this function. Note I have tried passing the whole zip file with the zip header as well as skipping over the zip file header and only passing the zipped data both fail with Z_DATA_ERROR when inflate() is called.

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

So my question is, is the type of zip file I am reading in not supported by ZLib's inflate() function? Or is there something wrong with my CHttpDownloader::unzip() function? Thanks for any help :)

Answer

Megan picture Megan · Sep 9, 2013

Inflate() was failing because it was looking for GZip headers which were not present. If you initialize the stream with:

ret = inflateInit2(&strm, -MAX_WBITS);

Passing a negative window bits value prevents inflate from checking for gzip or zlib headers and unzipping works as expected.