1
votes

I am trying to use zlib for decompression. Im look at a tutorial at zlib site and inflate codes produce different size output.

int CZLib::Inflate() {
    int ret;
    unsigned int have;
    z_stream zstream;
    unsigned char in[CHUNK];
    unsigned char out[CHUNK];

    zstream.zalloc = Z_NULL;
    zstream.zfree = Z_NULL;
    zstream.opaque = Z_NULL;
    zstream.avail_in = 0;
    zstream.next_in = Z_NULL;
    ret = inflateInit(&zstream);
    if (ret != Z_OK)
        return ret;

    do {
        zstream.avail_in = fread(in, 1, CHUNK, fin);
        if (ferror(fin)) {
            (void)inflateEnd(&zstream);
            return Z_ERRNO;
        }
        if (zstream.avail_in == 0) break;
        zstream.next_in = in;

        do {
            zstream.avail_out = CHUNK;
            zstream.next_out = out;
            ret = inflate(&zstream, Z_NO_FLUSH);
            assert(ret != Z_STREAM_ERROR);
            switch (ret) {
                case Z_NEED_DICT:
                    ret = Z_DATA_ERROR;
                case Z_DATA_ERROR:
                case Z_MEM_ERROR:
                    (void)inflateEnd(&zstream);
                    return ret;
            }
            have = CHUNK - zstream.avail_out;
            if (fwrite(out, 1, have, fout) != have || ferror(fout)) {
                (void)inflateEnd(&zstream);
                return Z_ERRNO;
            }

        } while (zstream.avail_out == 0);
    } while (ret != Z_STREAM_END);

    (void)inflateEnd(&zstream);
    return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
}

and other

int CZLib::Inflate(const std::string& src) {
    std::vector<char> output;

    z_stream zstream;
    zstream.zalloc = Z_NULL;
    zstream.zfree = Z_NULL;
    zstream.opaque = Z_NULL;
    zstream.avail_in = 0;
    zstream.next_in = Z_NULL;

    int ret = inflateInit(&zstream);
    if (ret != Z_OK)
        return ret;

    unsigned char in[CHUNK];
    unsigned char out[CHUNK];

    int have = 0, nByte = CHUNK, off = 0, remaining = src.size();

    if (src.size() < CHUNK) nByte = src.size();
    do {
        memcpy(in, &src[off], nByte);
        off += nByte;
        remaining -= nByte;

        if (nByte > 0) zstream.avail_in = nByte;

        if (remaining > CHUNK) { nByte = CHUNK; }
        else { nByte = remaining; }

        if (zstream.avail_in == 0) break;
        zstream.next_in = in;

        do {
            zstream.avail_out = CHUNK;
            zstream.next_out = out;

            ret = inflate(&zstream, Z_NO_FLUSH);
            have = CHUNK - zstream.avail_out;
            output.insert(output.end(), out, out + have);

        } while (zstream.avail_out == 0);
    } while (ret != Z_STREAM_END);

    CFile* file = new CFile("in.out", "wb");
    file->Write<char>(&output[0], output.size());
    delete file;
    return ret;
}

Its uses same data. One of them reads file on disk and other uses memory (buffer method). CHUNK size 16384. First code produce 524288(0x80000) and other 524800 (0x80200) byte. The difference are 512 bytes. Why is it happening ?

1

1 Answers

0
votes

In the first code example you have this line

zstream.avail_in = fread(in, 1, CHUNK, fin);

and then you have

if (zstream.avail_in == 0) break;

to stop the loop.

In the second code example, you have the same line to stop the loop but you also have this line:

    if (nByte > 0) zstream.avail_in = nByte;
        ^^^^^^^^^
        So you only assign to zstream.avail_in when nByte > 0

    ....
    ....

    if (zstream.avail_in == 0) break;
        ^^^^^^^^^^^^^^^^
        Consequently this will not be true when nByte is zero and the
        code will not exit

Try this instead:

    zstream.avail_in = nByte;  // Unconditional assignment

    ....

    if (zstream.avail_in <= 0) break;  // Less or equal to zero