Gzip壓縮資料解壓
阿新 • • 發佈:2019-01-11
在進行微博資料解析的過程中,遇到了gzip格式的壓縮資料,要從這些資料中得到微博資訊就首先需要對gzip資料進行解壓。
重組後的微博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; }
參考: