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内容并解压相关问题
这里采用的解压工具是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相关文章推荐
- Xcode Archive 不生成dsym文件的解决方法
- SpringMVC之异常处理
- NSnotificationCenter 正确使用姿势, removeObject 探索
- checkio-the flat dictionary
- android 混淆相关文件的输出地址
- stm32 + ARM GUN eclipse plug-in 实现 lib + app
- px4: actuators control, control group 和 mixer科普
- webview alert confirm 重写
- 数据可视化(二)
- KMP算法
- iOS实现从背景图中取色的代码
- hdu 1231 最大连续子序列
- 非ARC模式下内存管理总结
- uva 1451 Average 平均值
- Java中的Collection和Map(五)--PriorityQueue
- 0302关于就业的感想
- 史上最全前端面试题(含答案)
- 为什么是2MSL而不是MSL?
- Error using subsindex Function 'subsindex' is not defined for values of class 'struct'.
- 一个有趣的问题:怎么在JS的数组中去除重复元素?(JAVA实现吧..)