Zlib Compression Help

Started by
4 comments, last by MichaelNett 12 years, 10 months ago
I'm continuing this from my other thread since it's starting to get (more than) a bit off topic from what I was originally asking. I'm trying to implement some basic compression/decompression in my game using zlib. I want to create a couple functions like this which simply take pointers to strings as arguments, and (de)compress the source string, and place the result into the destination string, then return any errors. My code compiles and runs, but when I run it, I don't get the desired output. Once the string has been compressed and then uncompressed, the uncompressed string is the original string followed by a bunch of characters, and I get the zlib error code Z_DATA_ERROR. I have no idea what I'm doing wrong. Here's the code that I have so far:

#include "zlib.h"
#include <stdio.h>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>

using namespace std;

int CompressString(string *source, string *destination) {
	//Define the source, destination, source length, and destination length
	char *src=(char*)source->c_str();
	int srcLen=strlen(src);
	int destLen=compressBound(srcLen);
	char *dest=new char[destLen];
	//Decompress the string in src and place it in dest
	int result=compress((unsigned char *)dest,(uLongf*)&destLen,(const unsigned char *)src,srcLen);
	//Return the results of the compression
	string resultStr(dest);
	*destination=resultStr;
	delete dest;
	return(result);
}

int DecompressString(string *source, string *destination, int destLen) {
	//Define the source, destination, source length, and destination length
	char *src=(char*)source->c_str();
	int srcLen=strlen(src);
	char *dest=new char[destLen];
	//Decompress the string in src and place it in dest
	int result=uncompress((unsigned char *)dest,(uLongf*)&destLen,(const unsigned char *)src,srcLen);
	//Return the results of the decompression
	string resultStr(dest);
	*destination=resultStr;
	delete dest;
	return(result);
}

int main(int argc, char *argv[]) {
	//Define the needed variables
	string src="bla bla bla lorum ipsum this is a test string yadda yadda yadda, etc. etc.";
	string compressed;
	string decompressed;
	int result;

	//Compress the string, and output the results
	cout << "Compressing string:   " << src.c_str() << "\n";
	result=CompressString(&src,&compressed);
	cout << "Error code: " << result << "\n";
	cout << "Compressed String:    " << compressed.c_str() << "\n\n";

	//Decompress the string, and output the results
	cout << "Decompressing String: " << compressed.c_str() << "\n";
	result=DecompressString(&compressed,&decompressed,src.length());
	cout << "Error code: " << result << "\n";
	cout << "Decompressed String:  " << decompressed.c_str() << "n\n";
}



Here's the output I'm getting:

Compressing string:   bla bla bla lorum ipsum this is a test string yadda yadda
yadda, etc. etc.
Error code: 0
Compressed String:    x£K╩ITHéΓ£ⁿó╥\à╠éb YÆæY¼

Decompressing String: x£K╩ITHéΓ£ⁿó╥\à╠éb YÆæY¼
Error code: -3
Decompressed String:  bla bla bla lorum ipsum this══════════════════════════════
════════════════²²²²▌▌↕n
Error code -3 is Z_DATA_ERROR. The website states that:
Quote:uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted.
I don't see anywhere in my code where the compressed data could become corrupted. If anyone could please help me out, it would be greatly appreciated.
God is not all-powerful, as he cannot build a wall he cannot jump.Stelimar Website: eddy999999.ed.funpic.org/Stelimar/index.html
Advertisement
A compressed string may have null character values in the result, and you construct your result string by simply passing a pointer value to the string constructor, which will terminate at the first null. You should instead use the compressed data length as part of the constructor.
Your problem is that you're using a string to store binary data. That binary data can have a byte in it that has the value 0. Which when interpreted as a string that 0 becomes the strings terminator. Hence you get a truncation.

Instead try something like (fyi, this is untested & uncompiled code):

// in this version our dest is a pointer to a pointer to a character// and we store the length of destination in the passed in parameter destLengthint CompressString(char* src, char** destination, size_t* destLength){	//Define the source, destination, source length, and destination length	int srcLen=strlen(src);	int destLen=compressBound(srcLen);	char *dest=new char[destLen];	//Decompress the string in src and place it in dest	int result=compress((unsigned char *)dest,(uLongf*)&destLen,(const unsigned char *)src,srcLen);	//Return the results of the compression	*destination = dest;	*destLength = destLen;	return(result);}// since src is not really a string, we must know how long in bytes it isint DecompressString(char* src, int srcLen, char** destination, int* destLen){	//Define the source, destination, source length, and destination length	char *dest=new char[destLen];	//Decompress the string in src and place it in dest	int result=uncompress((unsigned char *)dest,(uLongf*)destLen,(const unsigned char *)src,srcLen);	//Return the results of the decompression	*destination = dest;	return(result);}int main(int argc, char *argv[]) {	//Define the needed variables	string src="bla bla bla lorum ipsum this is a test string yadda yadda yadda, etc. etc.";	char* compressed;	char* decompressed;	int compressedLength;	int decompressedLength;	int result;	//Compress the string, and output the results	cout &lt;&lt; "Compressing string:   " &lt;&lt; src.c_str() &lt;&lt; "\n";	result=CompressString(src.c_str(), &compressed, &compressedLength);	cout &lt;&lt; "Error code: " &lt;&lt; result &lt;&lt; "\n";	// The best way to achieve this would be to print out each byte (in hex) in the string, for now lets just comment it out.	//cout &lt;&lt; "Compressed String:    " &lt;&lt; compressed.c_str() &lt;&lt; "\n\n";	//Decompress the string, and output the results	// The best way to achieve this would be to print out each byte (in hex) in the string, for now lets just comment it out.	//cout &lt;&lt; "Decompressing String: " &lt;&lt; compressed.c_str() &lt;&lt; "\n";	result=DecompressString(compressed, compressedLength, &decompressed, &decompressedLength);	cout &lt;&lt; "Error code: " &lt;&lt; result &lt;&lt; "\n";	// at this stage we have to buffers that have been allocated by 	// CompressString and DecompressString, the decompressed one does NOT 	// have a NULL terminator on it, so we must make a string to print out	string decompressedString(decompressed, decompressedLength);	cout &lt;&lt; "Decompressed String:  " &lt;&lt; decompressedString.c_str() &lt;&lt; "n\n";	// now free the memory we allocated earlier	delete[] compressed;	delete[] decompressed;}


There are a few other problems with your code. You were using delete instead of delete[] on memory you new[]. If you use the array new (new TYPE[count]) then you should use delete[] to delete that memory.

When dealing with sizes of things (in bytes especially) you should use size_t whenever possible. If I were to totally rewrite my example above I'd use size_t's for compressedLength, decompressedLength, etc.

As for printing out binary data, I'd recommend doing something like:

void printBytes(char* src, size_t count){	char* lim = src + count;	while(src &lt; lim)	{		// the C way of printing something out...		printf("%02x", *src);		// in c++ I think you can do something like, but I'm not 100% certain it'll work		std::cout &lt;&lt; std::hex &lt;&lt; int(*src);		src++;	}}


Hope this helps, and that my code isn't too buggy. :-)

[Edited by - smoret on March 4, 2008 7:31:47 PM]
-- Steve Moret
After minimal tweaking, the code you gave me works. Thanks a ton =D
God is not all-powerful, as he cannot build a wall he cannot jump.Stelimar Website: eddy999999.ed.funpic.org/Stelimar/index.html

After minimal tweaking, the code you gave me works. Thanks a ton =D


I know this post is a few years old, but any chance you could share your code? I'm having some trouble getting this to work.

Thanks!

[quote name='Eddy999999' timestamp='1204661067' post='4174232']
After minimal tweaking, the code you gave me works. Thanks a ton =D


I know this post is a few years old, but any chance you could share your code? I'm having some trouble getting this to work.

Thanks!
[/quote]

You've got mail.

This topic is closed to new replies.

Advertisement