Zlib库对网页中deflate压缩数据的解压

来源:互联网 发布:unity3d计算机图形学 编辑:程序博客网 时间:2024/05/24 11:14

    一般情况下网页请求的头里会有一个Content-Encoding字段来表示该网页启用了压缩算法来提高网页传输效率。一般情况下都是以Gzip或deflate为字段值,实际上是以deflate压缩算法来压缩的数据。工作中偶尔碰见了这样的页面内容没有一个解压的代码还挺麻烦的。
    deflate 是最基础的算法,gzip在deflate的rawdata前增加了10个字节的 gzheader,尾部添加了8个字节的校验字节(可选 crc32 和 adler32) 和长度标识字节。
    zlib库是一个C++常用的解压zip文件的库,提供了各种各样的接口以供调用。其中,deflate使用inflateInit(),而gzip使用inflateInit2()进行初始化,比 inflateInit()多一个参数: -MAX_WBITS,表示处理raw deflate数据。因为gzip数据中的zlib压缩数据块没有zlib header的两个字节。使用inflateInit2时要求zlib库忽略zlib header。
    zlib提供了很多接口,在这些复杂的操作之上封装了最简单的两个接口,compress和uncompress。我们一般直接调用就可以了。
简单介绍下常用的函数:
1、 deflateInit() + deflate() + deflateEnd()
3个函数结合使用完成压缩功能,具体用法看 example.c 的 test_deflate()函数. 其实 compress() 函数内部就是用这3个函数实现的(工程 zlib 的 compress.c 文件)
2、 inflateInit() + inflate() + inflateEnd()
和上面的类似,完成解压缩功能,uncompress()函数的内部实现使用的就是它们
3、uLong compressBound(uLong sourceLen);
计算需要的缓冲区长度,这个函数并不精确的计算压缩后的数据有多长,但是可以保证压缩后的长度不会这个结果还长,便于分配空间。
接下来就是我们最常用的一对函数
4、int compress (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
压缩数据,要注意的是压缩后的BUF和大小是要预先分配好的,这也是我们为什么要使用compressBound这个函数的原因。
5、int uncompress (Bytef *dest, uLongf *destLen,const Bytef *source, uLong sourceLen);
解压缩数据,同样的,解压后的BUF大小要预先知道,太小了会解压失败。
一般情况下,compress和uncompress函数足以满足我们的要求。
最后附上解压一个从网页中获取的存有压缩数据的文件的代码:

/*************************************************************************    > File Name: un_zip.cpp    > Author:zeus     > Mail:zuixuewosha@163.com     > Created Time: 2017年06月09日 星期五 16时32分28秒    > useage: a.out src_file  dst_file ************************************************************************/#include <stdlib.h>#include <stdio.h>#include <zlib.h>int main(int argc, char* argv[]){    FILE* file;    unsigned char* src_buf = NULL;    unsigned char* ubuf = NULL;    int failed_number = 0;    /* 通过命令行参数将srcfile文件的数据解压缩后存放到dstfile文件中 */    if(argc < 3)    {        printf("Usage: a.out srcfile dstfile\n");        return -1;    }    if((file = fopen(argv[1], "rb")) == NULL)    {        printf("Can\'t open %s!\n", argv[1]);        return -1;    }    /* 装载源文件数据到缓冲区 */    fseek(file,0,SEEK_END);    unsigned long src_length = ftell(file);    unsigned long dst_length = 65536;    rewind(file);    printf("src_length is %d\n",src_length);    if((src_buf = (unsigned char*)malloc(sizeof(unsigned char) * src_length)) == NULL)    {        printf("No enough memory!\n");        fclose(file);        return -1;    }    fread(src_buf, sizeof(unsigned char), src_length, file);    /* 解压缩数据,失败后分配更大的空间,最大失败次数 10 */    while(failed_number < 10)    {        if((ubuf = (unsigned char*)malloc(sizeof(unsigned char) * dst_length)) == NULL)        {            printf("No enough memory!\n");            fclose(file);            return -1;        }        if(uncompress(ubuf, &dst_length, src_buf, src_length) != Z_OK)        {            printf("Uncompress %s failed,try allocate more space!\n", argv[1]);            free(ubuf);            ubuf = NULL;            /*失败后分配两倍空间*/            dst_length *=2;             failed_number++;        }        else        {            break;        }    }    fclose(file);    if((file = fopen(argv[2], "wb")) == NULL)    {        printf("Can\'t create %s!\n", argv[2]);        return -1;    }    /* 保存解压缩后的数据到目标文件 */    fwrite(ubuf, sizeof(unsigned char), dst_length, file);    fclose(file);    free(src_buf);    free(ubuf);    return 0;}