C++ ZLib GZipStream 解压缩 NULL 终止
C++ ZLib GZipStream Decompression NULL terminated
有很多围绕 zlib 和 GZipStreams 的问题,但 none 我找到了这个问题的答案。我正在使用 C# GZipStream 将压缩数据发送到客户端。它完全读取压缩数据,然后尝试解压缩它。但是,每次在循环中调用 inflate() 时,它只会获得以 NULL 结尾的字符串。发送二进制文件时,这是一个非常大的问题。
在向您展示代码之前,我只想说,如果我将接收到的压缩字节写入 .gz 文件并使用 gzFile/gzopen/gzread/gzclose,一切都会完美无缺。这意味着所有数据都正确输入。我想读入压缩后的数据,在内存中解压,然后把内容放在一个变量中。
我认为问题在于 inflate() 正在写入以 NULL 终止的 char*。我只是不知道如何让它成为一个字符串。我确实完全预料到这是一个重大疏忽和一个简单的修复。感谢您的帮助!
解压代码如下:
bool DecompressString(const std::string& message, std::string& dMsg)
{
int bufferSize = 512;
int messageSize = message.size() + 1;
//decompress string
z_stream zs;
memset(&zs, 0, sizeof(zs));
zs.zalloc = Z_NULL;
zs.zfree = Z_NULL;
zs.opaque = Z_NULL;
zs.next_in = (Bytef*)message.data();
zs.avail_in = messageSize;
int ret = Z_OK;
unsigned char* outbuffer = new unsigned char[bufferSize];
if (inflateInit2(&zs, 16+MAX_WBITS) == Z_OK)
{
do {
zs.next_out = outbuffer;
zs.avail_out = bufferSize;
ret = inflate(&zs, Z_NO_FLUSH);
if (ret < 0) return false;
std::stringstream tmpString;
tmpString << outbuffer;
if (dMsg.size() < zs.total_out) {
dMsg.append(tmpString.str().substr(0, zs.total_out - dMsg.size()));
}
} while (ret == Z_OK);
}
inflateEnd(&zs);
delete[] outbuffer;
//"\n<EOF>" is appended by sender to signify the end of file. This removes it
if (dMsg.find("\n<EOF>") != -1)
dMsg = dMsg.substr(0, dMsg.find("\n<EOF>"));
return true;
}
解决方案的工作代码:
bool DecompressString(const std::string& message, std::string& dMsg)
{
int bufferSize = 512;
int messageSize = message.size() + 1;
//decompress string
z_stream zs;
memset(&zs, 0, sizeof(zs));
zs.zalloc = Z_NULL;
zs.zfree = Z_NULL;
zs.opaque = Z_NULL;
zs.next_in = (Bytef*)message.data();
zs.avail_in = messageSize;
int ret = Z_OK;
unsigned char* outbuffer = new unsigned char[bufferSize];
if (inflateInit2(&zs, 16+MAX_WBITS) == Z_OK)
{
// get the decompressed bytes blockwise using repeated calls to inflate
do {
zs.next_out = outbuffer;
zs.avail_out = bufferSize;
ret = inflate(&zs, Z_NO_FLUSH);
if (ret < 0) return false;
//Here's the difference
if (dMsg.size() < zs.total_out)
dMsg.append(reinterpret_cast<char*>(outbuffer), bufferSize);
//End
} while (ret == Z_OK);
}
inflateEnd(&zs);
delete[] outbuffer;
if (dMsg.find("\n<EOF>") != -1)
dMsg = dMsg.substr(0, dMsg.find("\n<EOF>"));
return true;
}
string
本身没有问题,可以处理二进制数据。
正是这一行假设 zero-terminated c-string:
tmpString << outbuffer;
替换为
tmpString.append(outbuffer, bufferSize);
有很多围绕 zlib 和 GZipStreams 的问题,但 none 我找到了这个问题的答案。我正在使用 C# GZipStream 将压缩数据发送到客户端。它完全读取压缩数据,然后尝试解压缩它。但是,每次在循环中调用 inflate() 时,它只会获得以 NULL 结尾的字符串。发送二进制文件时,这是一个非常大的问题。
在向您展示代码之前,我只想说,如果我将接收到的压缩字节写入 .gz 文件并使用 gzFile/gzopen/gzread/gzclose,一切都会完美无缺。这意味着所有数据都正确输入。我想读入压缩后的数据,在内存中解压,然后把内容放在一个变量中。
我认为问题在于 inflate() 正在写入以 NULL 终止的 char*。我只是不知道如何让它成为一个字符串。我确实完全预料到这是一个重大疏忽和一个简单的修复。感谢您的帮助!
解压代码如下:
bool DecompressString(const std::string& message, std::string& dMsg)
{
int bufferSize = 512;
int messageSize = message.size() + 1;
//decompress string
z_stream zs;
memset(&zs, 0, sizeof(zs));
zs.zalloc = Z_NULL;
zs.zfree = Z_NULL;
zs.opaque = Z_NULL;
zs.next_in = (Bytef*)message.data();
zs.avail_in = messageSize;
int ret = Z_OK;
unsigned char* outbuffer = new unsigned char[bufferSize];
if (inflateInit2(&zs, 16+MAX_WBITS) == Z_OK)
{
do {
zs.next_out = outbuffer;
zs.avail_out = bufferSize;
ret = inflate(&zs, Z_NO_FLUSH);
if (ret < 0) return false;
std::stringstream tmpString;
tmpString << outbuffer;
if (dMsg.size() < zs.total_out) {
dMsg.append(tmpString.str().substr(0, zs.total_out - dMsg.size()));
}
} while (ret == Z_OK);
}
inflateEnd(&zs);
delete[] outbuffer;
//"\n<EOF>" is appended by sender to signify the end of file. This removes it
if (dMsg.find("\n<EOF>") != -1)
dMsg = dMsg.substr(0, dMsg.find("\n<EOF>"));
return true;
}
解决方案的工作代码:
bool DecompressString(const std::string& message, std::string& dMsg)
{
int bufferSize = 512;
int messageSize = message.size() + 1;
//decompress string
z_stream zs;
memset(&zs, 0, sizeof(zs));
zs.zalloc = Z_NULL;
zs.zfree = Z_NULL;
zs.opaque = Z_NULL;
zs.next_in = (Bytef*)message.data();
zs.avail_in = messageSize;
int ret = Z_OK;
unsigned char* outbuffer = new unsigned char[bufferSize];
if (inflateInit2(&zs, 16+MAX_WBITS) == Z_OK)
{
// get the decompressed bytes blockwise using repeated calls to inflate
do {
zs.next_out = outbuffer;
zs.avail_out = bufferSize;
ret = inflate(&zs, Z_NO_FLUSH);
if (ret < 0) return false;
//Here's the difference
if (dMsg.size() < zs.total_out)
dMsg.append(reinterpret_cast<char*>(outbuffer), bufferSize);
//End
} while (ret == Z_OK);
}
inflateEnd(&zs);
delete[] outbuffer;
if (dMsg.find("\n<EOF>") != -1)
dMsg = dMsg.substr(0, dMsg.find("\n<EOF>"));
return true;
}
string
本身没有问题,可以处理二进制数据。
正是这一行假设 zero-terminated c-string:
tmpString << outbuffer;
替换为
tmpString.append(outbuffer, bufferSize);