简体   繁体   中英

zlib deflateInit always returns Z_STREAM_ERROR

I'm using a snippet from https://panthema.net/2007/0328-ZLibString.html to compress strings. My problem is that deflateInit() always returns Z_STREAM_ERROR.

According to the zlib manual , that means that the compression level was wrong.

deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if level is not a valid compression level

The right compression level according to the manual is a value between 0-9.

The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: 1 gives best speed, 9 gives best compression, 0 gives no compression at all (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION requests a default compromise between speed and compression (currently equivalent to level 6).

But no matter what value I put for compression, it always returns -2(Z_STREAM_ERROR) .

#include <string>
#include <stdexcept>
#include <iostream>
#include <iomanip>
#include <sstream>

#include "zlib.h"

std::string compress_string(const std::string& str, int compressionlevel)
{
    z_stream zs;                        // z_stream is zlib's control structure
    memset(&zs, 0, sizeof(zs));

    //std::cout << deflateInit(&zs, 9); //Always returns -2, no matter if the value is between 0-9
    if (deflateInit(&zs, compressionlevel) != Z_OK)
        throw(std::runtime_error("deflateInit failed while compressing."));

    zs.next_in = (Bytef*)str.data();
    zs.avail_in = str.size();           // set the z_stream's input

    int ret;
    char outbuffer[32768];
    std::string outstring;

    // retrieve the compressed bytes blockwise
    do {
        zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
        zs.avail_out = sizeof(outbuffer);

        ret = deflate(&zs, Z_FINISH);

        if (outstring.size() < zs.total_out) {
            // append the block to the output string
            outstring.append(outbuffer,
                zs.total_out - outstring.size());
        }
    } while (ret == Z_OK);

    deflateEnd(&zs);

    if (ret != Z_STREAM_END) {          // an error occurred that was not EOF
        std::ostringstream oss;
        oss << "Exception during zlib compression: (" << ret << ") " << zs.msg;
        throw(std::runtime_error(oss.str()));
    }

    return outstring;
}

I'm using zlib 1.2.3 that I got from the Windows GnuWin32 installer. I made a change in zconf.h and commented out #if 1 and put #if HAVE_UNISTD_H instead because I'm not on Linux and do not have unistd.h .

So that looks like

//#if 1           /* HAVE_UNISTD_H -- this line is updated by ./configure */
#if HAVE_UNISTD_H
#  include <sys/types.h> /* for off_t */
#  include <unistd.h>    /* for SEEK_* and off_t */

Extra note: I do not have Z_SOLO defined.

There are only two ways to get Z_STREAM_ERROR from deflateInit() . They are if the first argument is NULL, or if the second argument is not in the range -1..9. By inspection and your claims on the passed compressionLevel, it does not appear that your code could violate either condition.

The only guess I can hazard is that your compile and link of zlib got messed up somewhere, and the types being passed do not match what the routine is expecting, resulting in the routine receiving a different level than what you sent.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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