Karlovsky120 Karlovsky120 - 1 year ago 207
C++ Question

Using minizip to decompress a char array

I have a vector (which is just a wrapper over a char array) that is the input. The pkzip was created using c# sharpZipLib.

I stored the data into a file which I ran through a hex editor zip template that checked out. The input is good, it's not malformed. This all but the compressed data:

50 4B 03 04 14 00 00 00 08 00 51 B2 8B 4A B3 B6
6C B0 F6 18 00 00 40 07 01 00 07 00 00 00 2D 33
31 2F 31 32 38

<compressed data (6390 bytes)>

50 4B 01 02 14 00 14 00 00 00 08 00 51 B2 8B 4A
B3 B6 6C B0 F6 18 00 00 40 07 01 00 07 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 2D 33
31 2F 31 32 38 50 4B 05 06 00 00 00 00 01 00 01
00 35 00 00 00 1B 19 00 00 00 00


I have another vector which is to be the output. The inflated data will have about 67-68k, so I know it fits into the buffer.

For the life of me, I cannot get the minizip to inflate the former and store it into latter.

This is what I have so far:

#include "minizip\zlib.h"

#define ZLIB_WINAPI

std::vector<unsigned char> data;

/*...*/

std::vector<unsigned char> outBuffer(1024 * 1024);

z_stream stream;

stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;

stream.data_type = Z_BINARY;

stream.avail_in = data.size();
stream.avail_out = outBuffer.size();

stream.next_in = &data[0];
stream.next_out = &outBuffer[0];

int ret = inflateInit(&stream);
ret = inflate(&stream, 1);
ret = inflateEnd(&stream);


I used the debugger to step through the method and monitor the
ret
.
inflate
returned value -3 with message
"incorrect header check"
.

This is a
pkzip
, which is a wrapper around
zlib
, but
minizip
should be a wrapper library around
zlib
that should support
pkzip
, shouldn't it be?
How do I have to modify this to work?

Answer Source

Since it starts with 50 4B 03 04 it is a PKZIP file, according to https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip.html

If these are zip files, then inflate is the wrong function. The zlib, gzip and zip formats are all different. You can read zip with zlib, if you use the right functions to do so. If you don't have the contrib, maybe download and rebuild zlib.

Here's some old code I have which works for zip files, using the zlib library. I might have moved some headers around, because the official zlib has them under zlib/contrib/minizip.

The arguments are filenames, so you'll have to modify it, or write your array to a file.

// #include <zlib/unzip.h>
#include <zlib/contrib/minizip/unzip.h>

/// return list of filenames in zip archive
std::list<std::string> GetZipFilenames(const char *szZipArchive){
    std::list<std::string> results;
    unzFile zip = unzOpen(szZipArchive);
    if (zip){
        unz_global_info info;
        int rv = unzGetGlobalInfo(zip, &info);

        if (UNZ_OK == unzGoToFirstFile(zip)){
            do {
                char szFilename[BUFSIZ];
                if (UNZ_OK == unzGetCurrentFileInfo(zip, NULL, szFilename, sizeof(szFilename), NULL, 0, NULL, 0))
                    results.push_back(std::string(szFilename));
            } while (UNZ_OK == unzGoToNextFile(zip));
        }
    }
    return results;
}

/// extract the contents of szFilename inside szZipArchive
bool ExtractZipFileContents(const char *szZipArchive, const char *szFilename, std::string &contents){
    bool result = false;
    unzFile zip = unzOpen(szZipArchive);
    if (zip){
        if (UNZ_OK == unzLocateFile(zip, szFilename, 0)){
            if (UNZ_OK == unzOpenCurrentFile(zip)){
                char buffer[BUFSIZ];
                size_t bytes;
                while (0 < (bytes = unzReadCurrentFile(zip, buffer, sizeof(buffer)))){
                    contents += std::string(buffer, bytes);
                }
                unzCloseCurrentFile(zip);
                result = (bytes == 0);
            }
        }
        unzClose(zip);
    }
    return result;
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download