一直没找到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. hdu 4606 简单计算几何+floyd+最小路径覆盖

    思路:将所有的直线的两个端点和城市混在一起,将能直接到达的两个点连线,求一次floyd最短路径.二分枚举bag容量,然后按给的要先后占领的城市由前向后,把能到一步到达的建一条边.然后求一次最小路径覆盖 ...

  2. 转:java 类名 this 的使用

    转自: http://www.cnblogs.com/PengLee/p/3993033.html 类名.class与类名.this详解   类名.class      我们知道在java中,一个类在 ...

  3. 关闭“编辑窗体”后, 主窗体的DatagridView刷新数据的问题

    问题:在关闭一个窗体2后,要刷新窗体1内的datagridview的数据,直接窗体1.datagridview.datasource=dt 是没用的. 解决办法如下: 在主窗体里 创建编辑窗体时 加上 ...

  4. 第二十八篇、自定义的UITableViewCell上有图片需要显示,要求网络网络状态为WiFi时,显示图片高清图;网络状态为蜂窝移动网络时,显示图片缩略图

    1)SDWebImage会自动帮助开发者缓存图片(包括内存缓存,沙盒缓存),所以我们需要设置用户在WiFi环境下下载的高清图,下次在蜂窝网络状态下打开应用也应显示高清图,而不是去下载缩略图. 2)许多 ...

  5. CSS样式三

    CSS表格样式 border-collapse:表格边线合并 caption-side: 属性值: top:设置表格的标题在表格的上方(默认效果) bottom:设置表格的标题在表格的下方 样式代码: ...

  6. 将一个应用程序添加做成windows服务

    需求来源: 在服务器端运行的一个应用程序,为完成客户端路径分析等功能: 此应用程序只需要运行着就可以,没有界面等要求: 因此,考虑把此应用程序添加到服务器端电脑管理的服务中,可以启动和停止. 这里添加 ...

  7. pure virtual、impure virtual、non-virtual函数的接口继承和实现继承

    1.abstract class 拥有pure virtual函数的class是abstract class. 不能创建abstract class的实体. 2.pure virtual 函数 他们必 ...

  8. Access数据库一种树形结构的实现和子节点查询

    BOOL CManageDataBase::GetDepTreeAllSons( int rootItem ) { CADORecordset Rst(&m_DataBase); BOOL b ...

  9. [转]PHP错误日志

    对 于PHP开发者来说,一旦某个产品投入使用,应该立即将display_errors选项关闭,以免因为这些错误所透露的路径.数据库连接.数据表等信息 而遭到黑客攻击.但是,任何一个产品在投入使用后,都 ...

  10. echarts.js(图表插件)2.0版会导致 ZeroClipboard.js(复制插件)失效,3.0版未知。

    解决方法:ZeroClipboard.js先于echarts.js加载.