一直没找到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. 【推理,贪心】UVa 1319 - Maximum

    看到了大神的代码.理解了好久...真是差距. 题意:给出m, p, a, b,然后xi满足已下两个公式, 求 xp1 + xp2 +...+ xpm 的最大值. 1.-1/sqrt(a) <= ...

  2. RestEasy传值方式

    一.@pathparam    @PathParam 是一个参数注解,可以将一个 URL 上的参数映射到方法的参数上,它可以映射到方法参数的类型有基本类型.字符串.或者任何有一个字符串作为构造方法参数 ...

  3. Delphi7使用ADO直接连接Excel读取数据

    我之前是连接成功的,现在不知道为什么怎样连都失败.最后才知道是Office版本的问题,office2007已经是基于xml的.和以前的不一样. Excel2003的连接字符串: 'Provider=M ...

  4. java-分页之页面分页

    import java.util.ArrayList; import java.util.List; /** * * @author cheney * * @date Aug 31, 2012 */ ...

  5. css3 盒模型记

    css3 盒模型 css假定每个元素都会生成一个或多个矩形框,这称为元素框.各元素框中心有一个内容区.这个内容区周围有可选的内边距,边框和外边距.这些项之所以被认为是可选的,原因是它们的宽度可以设置为 ...

  6. New MVC World

    Note: /Controllers:controllers respond to input from the browser,decide what to do with it,and retur ...

  7. MYSQL 排行类的相关SQL写法,仅供参考

    SELECT * FROM () )) b

  8. PullToRefreshListView手动刷新问题

    1.第一次进入界面刷新无效,需要延时刷新 new Handler().postDelayed(new Runnable() { @Override public void run() { // TOD ...

  9. Learn Python The Hard Way学习笔记001

    今天搜索了一下raw_input() 和 input()的区别,引用下原文部分内容 两个函数均能接收 字符串 ,但 raw_input() 直接读取控制台的输入(任何类型的输入它都可以接收).而对于 ...

  10. SQL中CONVERT()函数用法详解

    SQL中CONVERT函数格式: CONVERT(data_type,expression[,style]) 参数说明: expression 是任何有效的 Microsoft® SQL Server ...