一直没找到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;
}

Qt的gzip模块实现的更多相关文章

  1. nginx gzip 模块配置

    #gzip模块设置 gzip on; #开启gzip压缩输出 gzip_min_length 1k; #最小压缩文件大小 gzip_buffers 4 16k; #压缩缓冲区 gzip_http_ve ...

  2. Qt框架及模块认识

    小白自工作就接触Qt,一直都在使用Qt5.3.1版本,所以没有经历过大牛们把项目从Qt4程序到Qt5的烦恼,没准以后会碰到.对Qt所有的丰富的API表示惊叹,对于Qt的框架及模块认识也是极为模糊的,文 ...

  3. nginx的gzip模块

    gzip模块是我们在nginx里面经常用到的,压缩响应的数据,这通常有助于将传输数据的大小减少一半甚至更多.可以让我们访问网站更为流畅. Syntax Default Context gzip on ...

  4. Gzip模块

    Gzip模块为python的压缩和解压缩模块,读写gzip 文件 一.使用gzip模块压缩文件: 1 import gzip #导入python gzip模块,注意名字为全小写 2 g = gzip. ...

  5. nginx的gzip模块详解以及配置

    文章来源 运维公会:nginx的gzip模块详解以及配置   1.gzip模块作用 gzip这个模块无论在测试环境还是生产环境都是必须要开启,这个模块能高效的将页面的内容,无论是html或者css.j ...

  6. python中gzip模块的使用

    gzip模块能够直接压缩和解压缩bytes-like类型的数据,同时也能实现对应格式文件的压缩与解压缩 一.数据压缩与解压缩 压缩 函数-gzip.compress(data, compresslev ...

  7. 飘逸的python - 简明gzip模块压缩教程

    压缩数据创建gzip文件 先看一个略麻烦的做法 import StringIO,gzip content = 'Life is short.I use python' zbuf = StringIO. ...

  8. nginix.conf 中的gzip模块设置

    gizp模块配置 gzip  on;    gzip_min_length  1k;    gzip_buffers     4 16k;    gzip_http_version 1.0;    g ...

  9. Qt之分模块log

    说明 对于一般的log,使用 qInstallMessageHandler 重定向到文件即可,甚至可以根据日志等级,分类存储.但是并不是适用所有情况,比如,程序运行时动态创建模块,而每个模块需要创建不 ...

随机推荐

  1. html5 js os build

    1.NodeJS6.6 install   https://nodejs.org/en/ c:\nodejs>npm install -g grunt-cliC:\Users\police\Ap ...

  2. AjaxForm

    近乎的Ajax控件介绍,代码下载:http://www.jinhusns.com/Products/Download?type=whp AjaxForm 概述 功能说明 基于 ajaxForm 插件进 ...

  3. zookeeper启动报错(数据目录权限不对)

    zookeeper启动报错日志: 2016-11-16 11:19:43,880 [myid:3] - INFO [WorkerReceiver[myid=3]:FastLeaderElection@ ...

  4. 如何设置win7任务栏的计算机快速启动

    win7默认会有一个资源管理器的快速启动栏,但是点击的时候会打开“库”,你可能一般不会用这个库,想打开计算机怎么办呢? 其实很简单,再按住shift的同时右键资源管理器的这个快速启动项,然后会出现菜单 ...

  5. 注意java的对象引用

    要注意,当前拿到的“对象引用”, 是不是 指向 最新的实例, 没有的话, 要重新 生成实例去指向. 代码例子: AnsweringRuleInfo bhRule = accountGenerator. ...

  6. iOS - 文件操作(File Operating)

    1. 沙盒 & NSData /*_______________________________获取沙盒路径_________________________________________* ...

  7. CentOS 7 下使用 Firewall

    在 CentOS 7 中,引入了一个新的服务,Firewalld,下面一张图,让大家明确的了解 Firewall 与 iptables 之间的关系与区别. 安装它,只需 yum install fir ...

  8. 深入探析koa之中间件流程控制篇

    koa被认为是第二代web后端开发框架,相比于前代express而言,其最大的特色无疑就是解决了回调金字塔的问题,让异步的写法更加的简洁.在使用koa的过程中,其实一直比较好奇koa内部的实现机理.最 ...

  9. 学习红帽企业版RHEL 6.4的两问

    (1)看了一晚上的RHEL 6.4,到现在也没分清楚服务器版和桌面版.都说两个版本是一个文件,那装上之后怎么判断这到底用的是服务器版还是桌面版?还有人说在安装过程中会要求选择,用虚拟机安装根本没看到有 ...

  10. Windows系统 环境变量

    用户变量与系统变量 用户变量只对当前用户有效,而系统变量对所有用户有效.在检索命令时,系统变量会排在用户变量的前面.也就是说,如果两个地方都包含同一个命令,则优先执行系统变量指示路径下的命令. set ...