您的位置:首页 > 其它

Gzip压缩数据解压

2016-03-02 11:23 375 查看
在进行微博数据解析的过程中,遇到了gzip格式的压缩数据,要从这些数据中得到微博信息就首先需要对gzip数据进行解压。

这里采用的解压工具是zlib(http://www.zlib.net/),关于zlib的技术细节参考http://www.zlib.net/zlib_tech.html

重组后的微博TCP会话中的压缩数据:



从上图可以看出,gzip数据的开始是从两个换行“\r\n”开始的,即从“65c”这行数据后边开始的,是以“0”这一行结束的。”65c“表示的是其下面那段压缩数据的长度;上图中gzip数据仅分了65c这么长的一段,而某次压缩的数据可能分多个段,那么每段数据均以类似"65c"这么一个表示长度的值开始,后跟本段压缩数据。

下面这个函数是将一段一段的压缩gzip数据进行合并:

//第一个参数是待处理的http数据,第二个参数是数据的长度
//该函数处理重组后的http数据中的gzip压缩数据:
//gzip数据是以一个或多个chunked的形式存在的,该函数将提取,合并并解压出所有chunk的数据(解压
//出的gzip数据是是json格式的,函数返回的解压内容,在后续处理中会提取出json的“html”字段,进一步得到微博id)
void ProcessGzipData(char *source, int len, char *decompression) {
char result_gzip[65530];
char pattern[] = "\r\n\r\n";
int begin_pos = KmpSearch(source, len, pattern) + strlen(pattern);
if (begin_pos == -1)
return;
int offset = 0;
int gzip_len = 0;
while (memcmp(source + begin_pos + offset, "0\r\n", 3) != 0) {
char pattern2[] = "\r\n";
int len1 = KmpSearch(source + begin_pos + offset, len - begin_pos - offset, pattern2);
if (len1 == -1) //压缩数据出错,返回
break;
char temp1[10] = {'\0'};
memcpy(temp1, source + begin_pos + offset, len1);
offset += (len1 + strlen("\r\n"));
int len2 = KmpSearch(source + begin_pos + offset, len - begin_pos - offset, pattern2);
memmove(result_gzip + gzip_len, source + begin_pos + offset, len2);
gzip_len += len2;
offset += (len2 + strlen("\r\n"));
}
/*
fstream myfile("/home/yang/test/zlib.file", fstream::in | fstream::out | fstream::app);
if (!myfile)
cout << "open file error" << endl;

int i;
cout << "gzip len: " << gzip_len << endl;
for (i = 0; i < gzip_len; ++i)
myfile << result_gzip[i];
myfile.close();
*/
DecompressGzip(result_gzip, gzip_len + 1000, decompression); //调用下面的函数对合并的gzip数据解压
}

解压gzip数据的代码如下:

//该函数解压gzip数据
//参数:source是指向待解压数据的指针;len是待解压数据的长度;destination用于存放解压后的数据
int DecompressGzip(char *source, int len, char *destination) {
int result, have;
int offset = 0;
z_stream d_stream;

unsigned char compression[SEGMENT_SIZE] = {'\0'}, decompression[SEGMENT_SIZE] = {'\0'};
memcpy(compression, (Byte*)source, len);
unsigned int compression_len = len, decompression_len = SEGMENT_SIZE * 4;
strcpy((char*)decompression, "garbage");
d_stream.zalloc = Z_NULL;
d_stream.zfree = Z_NULL;
d_stream.opaque = Z_NULL;
d_stream.next_in = Z_NULL;
d_stream.avail_in = 0;

result = inflateInit2(&d_stream, 47);
if (result != Z_OK) {
printf("inflateInit2 error: %d\n", result);
return result;
}

d_stream.next_in = compression;
d_stream.avail_in = compression_len;

do {
d_stream.next_out = decompression;
d_stream.avail_out = SEGMENT_SIZE;
result = inflate(&d_stream, Z_NO_FLUSH);

assert(result != Z_STREAM_ERROR);

switch (result) {
case Z_NEED_DICT:
result = Z_DATA_ERROR;
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void)inflateEnd(&d_stream);
return result;
}
have = SEGMENT_SIZE - d_stream.avail_out;
memcpy(destination + offset, decompression, have);

offset += have;
} while (d_stream.avail_out == 0);

inflateEnd(&d_stream);
memcpy(destination + offset, "\0", 1);
return result;
}
参考:

zlib and gzip

获取http的gzip内容并解压相关问题

gzip 使用zlib解压http中gzip内容

zlib库解压http报文中的gzip数据

RFC:GZIP file format specification version 4.3
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: