Sign in to follow this  

Zlib Compression Help

This topic is 2378 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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 destLength
int 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 is
int 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]

Share this post


Link to post
Share on other sites
[quote name='Eddy999999' timestamp='1204661067' post='4174232']
After minimal tweaking, the code you gave me works. Thanks a ton =D
[/quote]

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!

Share this post


Link to post
Share on other sites
[quote name='Sam Dutton' timestamp='1307542103' post='4820931']
[quote name='Eddy999999' timestamp='1204661067' post='4174232']
After minimal tweaking, the code you gave me works. Thanks a ton =D
[/quote]

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.

Share this post


Link to post
Share on other sites

This topic is 2378 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this