Qt quncompress gzip data

前端 未结 3 2036
遥遥无期
遥遥无期 2020-12-10 04:51

I stumble upon a problem, and can\'t find a solution.

So what I want to do is uncompress data in qt, using qUncompress(QByteArray), send from www in gzip format. I

相关标签:
3条回答
  • 2020-12-10 05:11

    Directly using zlib is not that hard.

    I've been doing it like this:

    QByteArray gUncompress(const QByteArray &data)
    {
        if (data.size() <= 4) {
            qWarning("gUncompress: Input data is truncated");
            return QByteArray();
        }
    
        QByteArray result;
    
        int ret;
        z_stream strm;
        static const int CHUNK_SIZE = 1024;
        char out[CHUNK_SIZE];
    
        /* allocate inflate state */
        strm.zalloc = Z_NULL;
        strm.zfree = Z_NULL;
        strm.opaque = Z_NULL;
        strm.avail_in = data.size();
        strm.next_in = (Bytef*)(data.data());
    
        ret = inflateInit2(&strm, 15 +  32); // gzip decoding
        if (ret != Z_OK)
            return QByteArray();
    
        // run inflate()
        do {
            strm.avail_out = CHUNK_SIZE;
            strm.next_out = (Bytef*)(out);
    
            ret = inflate(&strm, Z_NO_FLUSH);
            Q_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 QByteArray();
            }
    
            result.append(out, CHUNK_SIZE - strm.avail_out);
        } while (strm.avail_out == 0);
    
        // clean up and return
        inflateEnd(&strm);
        return result;
    }
    

    The code is monstly copied from the zlib code example page. You will need to include <zlib.h>

    0 讨论(0)
  • 2020-12-10 05:15

    Here is my contribution... I've developed a class (QCompressor), based on zlib for easily compress/decompress QByteArray using GZIP.

    qcompressor.h:

    #ifndef QCOMPRESSOR_H
    #define QCOMPRESSOR_H
    
    #include <zlib.h>
    #include <QByteArray>
    
    #define GZIP_WINDOWS_BIT 15 + 16
    #define GZIP_CHUNK_SIZE 32 * 1024
    
    class QCompressor
    {
    public:
        static bool gzipCompress(QByteArray input, QByteArray &output, int level = -1);
        static bool gzipDecompress(QByteArray input, QByteArray &output);
    };
    
    #endif // QCOMPRESSOR_H
    

    qcompressor.cpp:

    #include "qcompressor.h"
    
    /**
     * @brief Compresses the given buffer using the standard GZIP algorithm
     * @param input The buffer to be compressed
     * @param output The result of the compression
     * @param level The compression level to be used (@c 0 = no compression, @c 9 = max, @c -1 = default)
     * @return @c true if the compression was successful, @c false otherwise
     */
    bool QCompressor::gzipCompress(QByteArray input, QByteArray &output, int level)
    {
        // Prepare output
        output.clear();
    
        // Is there something to do?
        if(input.length())
        {
            // Declare vars
            int flush = 0;
    
            // Prepare deflater status
            z_stream strm;
            strm.zalloc = Z_NULL;
            strm.zfree = Z_NULL;
            strm.opaque = Z_NULL;
            strm.avail_in = 0;
            strm.next_in = Z_NULL;
    
            // Initialize deflater
            int ret = deflateInit2(&strm, qMax(-1, qMin(9, level)), Z_DEFLATED, GZIP_WINDOWS_BIT, 8, Z_DEFAULT_STRATEGY);
    
            if (ret != Z_OK)
                return(false);
    
            // Prepare output
            output.clear();
    
            // Extract pointer to input data
            char *input_data = input.data();
            int input_data_left = input.length();
    
            // Compress data until available
            do {
                // Determine current chunk size
                int chunk_size = qMin(GZIP_CHUNK_SIZE, input_data_left);
    
                // Set deflater references
                strm.next_in = (unsigned char*)input_data;
                strm.avail_in = chunk_size;
    
                // Update interval variables
                input_data += chunk_size;
                input_data_left -= chunk_size;
    
                // Determine if it is the last chunk
                flush = (input_data_left <= 0 ? Z_FINISH : Z_NO_FLUSH);
    
                // Deflate chunk and cumulate output
                do {
    
                    // Declare vars
                    char out[GZIP_CHUNK_SIZE];
    
                    // Set deflater references
                    strm.next_out = (unsigned char*)out;
                    strm.avail_out = GZIP_CHUNK_SIZE;
    
                    // Try to deflate chunk
                    ret = deflate(&strm, flush);
    
                    // Check errors
                    if(ret == Z_STREAM_ERROR)
                    {
                        // Clean-up
                        deflateEnd(&strm);
    
                        // Return
                        return(false);
                    }
    
                    // Determine compressed size
                    int have = (GZIP_CHUNK_SIZE - strm.avail_out);
    
                    // Cumulate result
                    if(have > 0)
                        output.append((char*)out, have);
    
                } while (strm.avail_out == 0);
    
            } while (flush != Z_FINISH);
    
            // Clean-up
            (void)deflateEnd(&strm);
    
            // Return
            return(ret == Z_STREAM_END);
        }
        else
            return(true);
    }
    
    /**
     * @brief Decompresses the given buffer using the standard GZIP algorithm
     * @param input The buffer to be decompressed
     * @param output The result of the decompression
     * @return @c true if the decompression was successfull, @c false otherwise
     */
    bool QCompressor::gzipDecompress(QByteArray input, QByteArray &output)
    {
        // Prepare output
        output.clear();
    
        // Is there something to do?
        if(input.length() > 0)
        {
            // Prepare inflater status
            z_stream strm;
            strm.zalloc = Z_NULL;
            strm.zfree = Z_NULL;
            strm.opaque = Z_NULL;
            strm.avail_in = 0;
            strm.next_in = Z_NULL;
    
            // Initialize inflater
            int ret = inflateInit2(&strm, GZIP_WINDOWS_BIT);
    
            if (ret != Z_OK)
                return(false);
    
            // Extract pointer to input data
            char *input_data = input.data();
            int input_data_left = input.length();
    
            // Decompress data until available
            do {
                // Determine current chunk size
                int chunk_size = qMin(GZIP_CHUNK_SIZE, input_data_left);
    
                // Check for termination
                if(chunk_size <= 0)
                    break;
    
                // Set inflater references
                strm.next_in = (unsigned char*)input_data;
                strm.avail_in = chunk_size;
    
                // Update interval variables
                input_data += chunk_size;
                input_data_left -= chunk_size;
    
                // Inflate chunk and cumulate output
                do {
    
                    // Declare vars
                    char out[GZIP_CHUNK_SIZE];
    
                    // Set inflater references
                    strm.next_out = (unsigned char*)out;
                    strm.avail_out = GZIP_CHUNK_SIZE;
    
                    // Try to inflate chunk
                    ret = inflate(&strm, Z_NO_FLUSH);
    
                    switch (ret) {
                    case Z_NEED_DICT:
                        ret = Z_DATA_ERROR;
                    case Z_DATA_ERROR:
                    case Z_MEM_ERROR:
                    case Z_STREAM_ERROR:
                        // Clean-up
                        inflateEnd(&strm);
    
                        // Return
                        return(false);
                    }
    
                    // Determine decompressed size
                    int have = (GZIP_CHUNK_SIZE - strm.avail_out);
    
                    // Cumulate result
                    if(have > 0)
                        output.append((char*)out, have);
    
                } while (strm.avail_out == 0);
    
            } while (ret != Z_STREAM_END);
    
            // Clean-up
            inflateEnd(&strm);
    
            // Return
            return (ret == Z_STREAM_END);
        }
        else
            return(true);
    }
    

    and here the main() of my test program:

    #include <QDebug>
    #include "qcompressor.h"
    
    int main(int argc, char *argv[])
    {
        Q_UNUSED(argc);
        Q_UNUSED(argv);
    
        QString initialPlainText = "This is a test program for verifying that the QCompressor class works fine!";
    
        qDebug() << "Initial plain text is: " << initialPlainText;
    
        QByteArray compressed;
    
        if(QCompressor::gzipCompress(initialPlainText.toLatin1(), compressed))
        {
            qDebug() << "Compressed text length is:" << compressed.length();
    
            QByteArray decompressed;
    
            if(QCompressor::gzipDecompress(compressed, decompressed))
            {
                qDebug() << "Decompressed text is: " << QString::fromLatin1(decompressed);
            }
            else
                qDebug() << "Can't decompress";
        }
        else
            qDebug() << "Can't compress";
    }
    

    For let this work, you need to add a line LIBS += -lz to your .pro file for linking against zlib.

    0 讨论(0)
  • 2020-12-10 05:17

    You also forgot dataPlusSize.append(data);. However, that won't solve your problem. The problem is that while gzip and zlib have the same compressed data format, their headers and trailers are different. See: http://www.zlib.net/zlib_faq.html#faq18

    qUncompress uses the zlib uncompress, so it can only handle the zlib format, not the gzip format. It would need to call the gzXXXX functions to handle the gzip format.

    The reason that qUncompress can handle output from PHP's gzcompress is that gzcompress compresses the given string using the ZLIB data format. See: http://php.net/manual/en/function.gzcompress.php

    As CiscoIPPhone mentioned, you'll need to write your own to functions to handle gzip data.

    0 讨论(0)
提交回复
热议问题