zoukankan      html  css  js  c++  java
  • Qt的gzip模块实现

    一直没找到Qt中方便的gzip模块,于是自己动手,调用zlib模块实现了一份.
    目标: 
    1.gzip的压缩与解压
    2.内存中操作
    3.方便的Qt接口
     
    实现分析:
    gzip 压缩算法为 deflate
    inflateInit2时要求zlib库忽略zlib header 
    gzip 在 deflate 的 raw data 前增加了 10 个字节的头,尾部添加了 8 个字节的校验字节(可选 crc32 和 adler32) 和长度标识字节
    gzip 的 magic number 是 0x1f, 0x8b
    zlib windowBits MAX_WBITS + 16 的时候,zlib 自己会产生一个 gzip 的头和尾,这种情况下 OS_CODE 被设置为 255(unknown),尾部校验使用 crc32
     
    接口:
    QByteArray gzipCompress(const QByteArray &in);
    bool gzipUncompress(const QByteArray &data, QByteArray &out);
    QByteArray gzipUncompress(const QByteArray &data); 
     
    实现:
    int httpgzdecompress(Byte *zdata, uLong nzdata, Byte *data, uLong *ndata)
    {
        int err = 0;
        z_stream d_stream = {0}; /* decompression stream */
        static char dummy_head[2] =
        {
            0x8 + 0x7 * 0x10,
            (((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,
        };
        d_stream.zalloc = (alloc_func)0;
        d_stream.zfree = (free_func)0;
        d_stream.opaque = (voidpf)0;
        d_stream.next_in  = zdata;
        d_stream.avail_in = 0;
        d_stream.next_out = data;
        if(inflateInit2(&d_stream, 47) != Z_OK) return -1;
        while (d_stream.total_out < *ndata && d_stream.total_in < nzdata) {
            d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */
            if((err = inflate(&d_stream, Z_NO_FLUSH)) == Z_STREAM_END) break;
            if(err != Z_OK )
            {
                if(err == Z_DATA_ERROR)
                {
                    d_stream.next_in = (Bytef*) dummy_head;
                    d_stream.avail_in = sizeof(dummy_head);
                    if((err = inflate(&d_stream, Z_NO_FLUSH)) != Z_OK)
                    {
                        return -1;
                    }
                }
                else return -1;
            }
        }
        if(inflateEnd(&d_stream) != Z_OK) return -1;
        *ndata = d_stream.total_out;
        return 0;
    }
     
    int httpgzcompress(Bytef *data, uLong ndata, Bytef *zdata, uLong *nzdata)
    {
        z_stream c_stream;
        int err = 0;
     
        if(data && ndata > 0)
        {
            c_stream.zalloc = (alloc_func)0;
            c_stream.zfree = (free_func)0;
            c_stream.opaque = (voidpf)0;
            if(deflateInit2(&c_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
                            MAX_WBITS + 16, 8, Z_DEFAULT_STRATEGY) != Z_OK) return -1;
            c_stream.next_in  = data;
            c_stream.avail_in  = ndata;
            c_stream.next_out = zdata;
            c_stream.avail_out  = *nzdata;
            while (c_stream.avail_in != 0 && c_stream.total_out < *nzdata)
            {
                if(deflate(&c_stream, Z_NO_FLUSH) != Z_OK) return -1;
            }
            if(c_stream.avail_in != 0) return c_stream.avail_in;
            for (;;) {
                if((err = deflate(&c_stream, Z_FINISH)) == Z_STREAM_END) break;
                if(err != Z_OK) return -1;
            }
            if(deflateEnd(&c_stream) != Z_OK) return -1;
            *nzdata = c_stream.total_out;
            return 0;
        }
        return -1;
    }
     
    QByteArray gzipCompress(const QByteArray &in)
    {
        QByteArray dest(compressBound(in.size()) + 7, 0);
        uLongf destLen = dest.size();
        int r1 = httpgzcompress((Bytef*)in.data(), in.size(), (Bytef*)dest.data(),&destLen);
        dest.resize(destLen);
        return dest;
    }
     
     
    bool gzipUncompress(const QByteArray &data, QByteArray &out)
    {
        if (data.size()<=8)
        {
            return false;
        }
     
        ulong orign_crc = *((ulong*)(data.data() + data.length() - 8));
        ulong len =*((ulong*)(data.data() + data.length() - 4));
     
        out.resize(len);
        int ret = httpgzdecompress((Bytef *)data.data(), data.length(),(Bytef *)out.data(), &len); //(Bytef *)(data.data()+10), data.length()-10-8);
        if (ret!=Z_OK)
        {
            qWarning("gzipUncompress error: %d", ret);
            return false;
        }
        uLong crc = crc32(0L, Z_NULL, 0);
        crc = crc32(crc, (Bytef *)(out.data()), out.length());
     
        if (crc==orign_crc)
        {
            return true;
        }
        else{
            qWarning("gzipUncompress crc check sum fail");
            out.clear();
            return false;
        }
    }
     
    QByteArray gzipUncompress(const QByteArray &data)
    {
        QByteArray out;
        gzipUncompress(out);
        return out;
    }
     
    还有一份之前使用的qCompress的压缩实现(效率比较低)
    QByteArray gzip(const QByteArray &in)
    {
        QByteArray uncompress=qCompress(in);
        uncompress.remove(0,4);//去除qCompress头
        uncompress.remove(0, 2); //去除zlib头
        uncompress.remove(uncompress.size() - 4, 4); //去除zlib尾
        uint len=in.size();
        unsigned long crc=GetCrc32((unsigned char *)in.data(),len);
        const unsigned char gzipheader[10]={0x1f,0x8b,8,0,0,0,0,0,2,255};
        QByteArray out;
        out.append((char *)gzipheader,10);
        out.append(uncompress);
        out.append((char *)&crc,4);
        out.append((char *)&len,4);
        return out;
    }
  • 相关阅读:
    洛谷T44252 线索_分治线段树_思维题
    css 迷惑的position
    【二次元的CSS】—— 用 DIV + CSS3 画大白(详解步骤)
    直接使用sublime编译stylus
    w3schools网站的HTML教程之HTML编辑器
    【二次元的CSS】—— 纯CSS3做的能换挡的电扇
    《JavaScript Dom编程艺术》读书笔记(二)
    JQuery基础修炼-样式篇
    Vue.js 开发实践:实现精巧的无限加载与分页功能
    web前端教程《每日一题》(1-99)完结
  • 原文地址:https://www.cnblogs.com/danju/p/3691636.html
Copyright © 2011-2022 走看看