zlib inflate函数解压缩gzip数据总是失败
本帖最后由 qianguozheng 于 2016-04-13 16:16 编辑网上找了很多解压缩到例子,法总总是Z_DATA_ERROR,不知道是什么原因。
目的是解压缩http gzip压缩到body, 我获取利body,通过gzip -d xxx.gz可以解压, 但是我的程序就是不行。
希望大神能帮忙看看哪里出问题了。
测试用到test.gz已经上传到附件。
程序代码如下:
#include <zlib.h>
#include <string>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <zlib.h>
using namespace std;
class CUncompress
{
public:
CUncompress(string & sUncompressData);
~CUncompress();
public:
int Init(const char * pszCompressed, int nCompressedLen, bool bIsGzip=false);
int UncompressData();
char * GetErrMsg()
{
return m_szErrMsg;
}
private:
string & m_sData;
char * m_pszDataChunk;
z_stream m_objStream;
char m_szErrMsg;
bool m_bIsGzip;
};
//-----------CPP
static const int DSIZE = 0x10000;
CUncompress::CUncompress(string & sUncompressData):m_sData(sUncompressData)
{
memset(m_szErrMsg, 0, 1024);
m_pszDataChunk = new char;
m_bIsGzip = false;
}
CUncompress::~CUncompress()
{
if (m_pszDataChunk != NULL)
{
delete [] m_pszDataChunk;
}
}
int CUncompress::Init(const char * pszCompressed, int nCompressedLen, bool bIsGzip)
{
int nErrCode = 0;
m_objStream.zalloc = (alloc_func)Z_NULL;
m_objStream.zfree = (free_func)Z_NULL;
m_objStream.opaque = 0;
m_objStream.next_in = NULL;
m_objStream.avail_in = 0;
if (bIsGzip)
{
m_bIsGzip = true;
if (strcmp(zlibVersion(), "1.2.0.4") < 0)
{
snprintf(m_szErrMsg, 1024, "zlib version < 1.2.0.4");
return -1;
}
//if ((nErrCode = inflateInit2(&m_objStream, MAX_WBITS + 32)) != Z_OK)
if ((nErrCode = inflateInit2(&m_objStream, 31)) != Z_OK)
{
snprintf(m_szErrMsg, 1024, "inflateInit2 failed, err code=%d", nErrCode);
return -2;
}
}
else
{
if ((nErrCode = inflateInit(&m_objStream)) != Z_OK)
{
snprintf(m_szErrMsg, 1024, "inflateInit failed, err code=%d", nErrCode);
return -3;
}
}
m_objStream.next_in = (Bytef*)pszCompressed;
m_objStream.avail_in = (uInt)nCompressedLen;
return 0;
}
int CUncompress::UncompressData()
{
bool bRetry = true;
uInt unRead = m_objStream.avail_in;
Bytef * pszInData = m_objStream.next_in;
int nStatus = 0;
for (;;)
{
m_objStream.next_out = (Bytef*)m_pszDataChunk;
m_objStream.avail_out = DSIZE;
nStatus = inflate(&m_objStream, Z_SYNC_FLUSH);
if (nStatus == Z_OK || nStatus == Z_STREAM_END)
{
bRetry = false;
if (DSIZE - m_objStream.avail_out)
{
m_sData.append(m_pszDataChunk, DSIZE - m_objStream.avail_out);
}
if (nStatus == Z_STREAM_END || (nStatus == Z_OK && m_objStream.avail_in == 0))
{
if ((nStatus = inflateEnd(&m_objStream)) == Z_OK)
{
return 0;
}
else
{
snprintf(m_szErrMsg, 1024, "inflateEnd failed, err code=%d", nStatus);
return -1;
}
}
}
else if ((!m_bIsGzip) && bRetry && nStatus == Z_DATA_ERROR)
{
//if has no zlib header, try another way
(void)inflateEnd(&m_objStream);
if ((nStatus = inflateInit2(&m_objStream, -MAX_WBITS)) != Z_OK)
{
snprintf(m_szErrMsg, 1024, "data has no zlib header, try another way inflateInit2 failed, err cod=%d", nStatus);
return -2;
}
m_objStream.next_in = pszInData;
m_objStream.avail_in = unRead;
bRetry = false;
continue;
}
else
{
(void)inflateEnd(&m_objStream);
snprintf(m_szErrMsg, 1024, "error when inflate compressed, err code=%d", nStatus);
return -3;
}
}
return 0;
}
/* Uncompress gzip data */
/* zdata 数据 nzdata 原数据长度 data 解压后数据 ndata 解压后长度 */
int gzdecompress(Byte *zdata, uLong nzdata,
Byte *data, uLong *ndata)
{
int err = 0;
z_stream d_stream = {0}; /* decompression stream */
static char dummy_head = {
0x8 + 0x7 * 0x10,
(((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,
};
d_stream.zalloc = NULL;
d_stream.zfree = NULL;
d_stream.opaque = NULL;
d_stream.next_in= zdata;
d_stream.avail_in = 0;
d_stream.next_out = data;
//只有设置为MAX_WBITS + 16才能在解压带header和trailer的文本
if(inflateInit2(&d_stream, MAX_WBITS + 16) != Z_OK) return -1;
//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) {
std::cout<<"Fuck"<<std::endl;
return -1;
}
} else{
std::cout<<"Fuckxxx"<<std::endl;
return -1;
}
}
}
if(inflateEnd(&d_stream) != Z_OK) return -1;
*ndata = d_stream.total_out;
return 0;
}
char *decompress(char *compressed, int wsize, int input_len, int bufsize)
{
printf("wsize=%d, input_len=%d, bufsize=%d\n", wsize, input_len, bufsize);
Byte *result_str;
Byte *input = (Byte *)compressed;
int length, err;
//int wsize=DEF_WBITS;
//Py_ssize_t r_strlen=DEFAULTALLOC;
int r_strlen = bufsize;
length = input_len;
z_stream zst;
//if (!PyArg_ParseTuple(args, "s#|in:decompress",
// &input, &length, &wsize, &r_strlen))
// return NULL;
if (r_strlen <= 0)
r_strlen = 1;
zst.avail_in = length;
zst.avail_out = r_strlen;
//if (!(result_str = PyString_FromStringAndSize(NULL, r_strlen)))
// return NULL;
result_str = (Byte *)malloc(r_strlen);
memset(result_str, 0, r_strlen)
;
zst.zalloc = (alloc_func)NULL;
zst.zfree = (free_func)Z_NULL;
zst.next_out = (Byte *)(result_str);
zst.next_in = (Byte *)input;
err = inflateInit2(&zst, wsize);
switch(err) {
case(Z_OK):
break;
case(Z_MEM_ERROR):
//PyErr_SetString(PyExc_MemoryError,
printf("Out of memory while decompressing data\n");
goto error;
default:
inflateEnd(&zst);
//zlib_error(zst, err, "while preparing to decompress data");
printf("while preparing to decompress data\n");
goto error;
}
do {
//Py_BEGIN_ALLOW_THREADS
//err=inflate(&zst, Z_FINISH);
err=inflate(&zst, Z_SYNC_FLUSH);
//Py_END_ALLOW_THREADS
printf(" inflate: err=%d\n", err);
switch(err) {
case(Z_STREAM_END):
break;
case(Z_BUF_ERROR):
/*
* If there is at least 1 byte of room according to zst.avail_out
* and we get this error, assume that it means zlib cannot
* process the inflate call() due to an error in the data.
*/
if (zst.avail_out > 0) {
//zlib_error(zst, err, "while decompressing data");
printf("while decompressing data\n");
inflateEnd(&zst);
goto error;
}
/* fall through */
case(Z_OK):
/* need more memory */
/*if (_PyString_Resize(&result_str, r_strlen << 1) < 0) {
inflateEnd(&zst);
goto error;
}*/
//zst.next_out = (unsigned char *)PyString_AS_STRING(result_str)
zst.next_out = (unsigned char *)(result_str) \
+ r_strlen;
zst.avail_out = r_strlen;
r_strlen = r_strlen << 1;
break;
default:
inflateEnd(&zst);
//zlib_error(zst, err, "while decompressing data");
printf("%d: while decompressing data, %d\n", __LINE__, err);
goto error;
}
} while (err != Z_STREAM_END);
err = inflateEnd(&zst);
if (err != Z_OK) {
//zlib_error(zst, err, "while finishing data decompression");
printf("while finishing data decompression\n");
goto error;
}
//_PyString_Resize(&result_str, zst.total_out);
//global_decompress_err = err;
return (char *)result_str;
error:
//Py_XDECREF(result_str);
if (result_str)
{
free(result_str);
}
return NULL;
}
int main(int argc, char *argv[])
{
std::ifstream f1;
std::string buffer;
f1.open("test.gz");
if(!f1)
{
std::cout <<"open test.gz file failed"<<std::endl;
return 0;
}
char c;
char buf;
memset(buf, 0, sizeof(buf));
int len = 0;
while(!f1.eof())
{
f1.read(c,80);
//std::string str(c);
//buffer += str;
len += f1.gcount();
std::cout<<"len="<<len<<" bufsize="<<buffer.size()<<std::endl;
memcpy(buf, c, f1.gcount());
}
f1.close();
//std::cout<<"buffer size="<<buffer.size()<<std::endl;
#if 0
std::string uncompress;
CUncompress dcp(uncompress);
//CUncompress::Init(char * pszCompressed, int nCompressedLen, bool bIsGzip)
dcp.Init((const char *)buf, len, true);
dcp.UncompressData();
std::cout<<"Error:"<<dcp.GetErrMsg()<<std::endl;
std::cout<<"Uncompressed Data="<<uncompress<<std::endl;
char rawdata;
int rawlen = 1200000;
gzdecompress((Byte *)buf, len, (Byte *)rawdata, (long unsigned int*) &rawlen);
std::cout<<"raw data="<<rawdata<<std::endl;
#else
// char *decompress(char *compressed, int wsize, int input_len, int bufsize)
char *result = NULL;
result = decompress(buf, MAX_WBITS+16, len, 1200000);
printf("result=%s", result);
#endif
}
网上找到了两三个函数, 测试都不行 没必要压缩,真正吃流量的是图片视频,你还压缩不鸟
文字这些又不伤多少流量的 回复 3# shang2010
没人要压缩,这是解压缩,看清问题再回答。 搞定了。 看你代码写得蛮多的,感觉还是高级语言方便,
c/cpp太复杂了:outu::outu: 回复 5# shang2010
写多了就习惯了,早就想搞高级语言了,没人腰阿 本帖最后由 wlmqgzm 于 2016-05-17 08:35 编辑
回复 4# qianguozheng
怎么搞定的?我猜是文件开头的几个字节不同, 就是文件方式前面有增加的额外的特殊字段(用于说明文件一些属性的).
回复 7# wlmqgzm
我上面的代码就可以正常解压缩。 测试失败的原因是我的读取函数有问题。
页:
[1]