www.pudn.com > RakNet-2.52.zip > MemoryCompressor.cpp


// See http://www.bzip.org/1.0.3/bzip2-manual-1.0.3.html#low-level for docs on bzip 
#include "MemoryCompressor.h" 
#include  
 
CompressorBase::CompressorBase() 
{ 
	output=0; 
	allocatedSize=0; 
	streamInited=false; 
	stream.bzalloc=0; 
	stream.bzfree=0; 
	stream.opaque=0; 
	totalRead=totalWritten=0; 
} 
CompressorBase::~CompressorBase() 
{ 
} 
MemoryCompressor::~MemoryCompressor() 
{ 
	Clear(); 
} 
MemoryDecompressor::~MemoryDecompressor() 
{ 
	Clear(); 
} 
bool MemoryCompressor::Compress(char *input, const unsigned inputLength, bool finish) 
{ 
	int res; 
	unsigned inBefore,outBefore, read; 
	unsigned written; 
 
	if (output==0) 
	{ 
		allocatedSize=inputLength; 
		if (allocatedSize < 1024) 
			allocatedSize=1024; 
		output=(char*)malloc(allocatedSize); 
	} 
 
	if (streamInited==false) 
	{ 
		res = BZ2_bzCompressInit ( &stream,  
			9, // x 100K Block size.  Memory to use = 400k + ( 8 x block size ).  So this is 400K + 9 x 900K = 7.6 megabytes.  Larger sizes give better compression. 
			0, // Verbosity. 
			0 ); // Default work factor 
 
		streamInited=true; 
		if (res!=BZ_OK) 
			return false; 
	} 
 
	read=written=0; 
	unsigned readThisSession; 
	readThisSession=0; 
 
	if (totalWritten==allocatedSize) 
	{ 
		allocatedSize+=inputLength; 
		output=(char*)realloc(output, allocatedSize); 
	} 
 
	while(1) 
	{ 
		stream.next_out=output+totalWritten; 
		stream.avail_in=inputLength-readThisSession; 
		stream.avail_out=allocatedSize-totalWritten; 
		stream.next_in=input+readThisSession; 
		inBefore=stream.total_in_lo32; 
		outBefore=stream.total_out_lo32; 
		//printf("%i\n", stream.avail_in); 
		res = BZ2_bzCompress( &stream, finish ? BZ_FINISH : BZ_RUN ); 
		read=stream.total_in_lo32-inBefore; 
		written=stream.total_out_lo32-outBefore; 
		totalRead+=read; 
		totalWritten+=written; 
		readThisSession+=read; 
 
		if ((stream.avail_in==0 && stream.avail_out>0) || (read==0 && written==0)) 
		{ 
			if (finish) 
			{ 
				allocatedSize=GetTotalOutputSize(); 
				output=(char*)realloc(output,allocatedSize); 
				BZ2_bzCompressEnd( &stream ); 
				streamInited=false; 
			} 
			return true; 
		} 
 
		if (totalWritten==allocatedSize || read==0) 
		{ 
			allocatedSize+=inputLength; 
			output=(char*)realloc(output, allocatedSize); 
		} 
	} 
} 
bool MemoryDecompressor::Decompress(char *input, const unsigned inputLength, bool ignoreStreamEnd) 
{ 
	unsigned inBefore,outBefore, read; 
	unsigned written; 
 
	int res; 
	if (output==0) 
	{ 
		allocatedSize=inputLength*2; 
		if (allocatedSize < 1024) 
			allocatedSize=1024; 
		output=(char*)malloc(allocatedSize); 
	} 
 
	if (streamInited==false) 
	{ 
		res = BZ2_bzDecompressInit( &stream,  
			0, // Verbosity. 
			0 ); // Disable small memory usage 
 
		streamInited=true; 
 
		if (res!=BZ_OK) 
			return false; 
	} 
 
	unsigned readThisSession; 
	readThisSession=0; 
	read=written=0; 
 
	if (totalWritten==allocatedSize) 
	{ 
		allocatedSize+=inputLength*4; 
		output=(char*)realloc(output, allocatedSize); 
	} 
 
	while(1) 
	{ 
		stream.next_out=output+totalWritten; 
		stream.avail_in=inputLength-readThisSession; 
		stream.avail_out=allocatedSize-totalWritten; 
		stream.next_in=input+readThisSession; 
		inBefore=stream.total_in_lo32; 
		outBefore=stream.total_out_lo32; 
		res = BZ2_bzDecompress( &stream ); 
		read=stream.total_in_lo32-inBefore; 
		written=stream.total_out_lo32-outBefore; 
		readThisSession+=read; 
		totalRead+=read; 
		totalWritten+=written; 
 
		if (res==BZ_STREAM_END) 
		{ 
			BZ2_bzDecompressEnd( &stream ); 
			 
			if (ignoreStreamEnd==true) 
			{ 
				// Stream end marker but there is more data so just keep reading 
				res = BZ2_bzDecompressInit( &stream,  
					0, // Verbosity. 
					0 ); // Disable small memory usage 
			} 
			else 
			{ 
				streamInited=false; 
				return true; 
			} 
		} 
		else if ((stream.avail_in==0 && stream.avail_out>0) || (read==0 && written==0)) 
		{ 
			allocatedSize=GetTotalOutputSize(); 
			output=(char*)realloc(output,allocatedSize); 
			return true; 
		} 
		else if (res!=BZ_OK) 
		{ 
			Clear(); 
			return false; 
		} 
 
		if (totalWritten==allocatedSize || read==0) 
		{ 
			allocatedSize+=inputLength*4; 
			output=(char*)realloc(output, allocatedSize); 
		} 
	} 
} 
char *CompressorBase::GetOutput(void) const 
{ 
	return output; 
} 
unsigned CompressorBase::GetTotalOutputSize(void) const 
{ 
	return totalWritten; 
} 
unsigned CompressorBase::GetTotalInputSize(void) const 
{ 
	return totalRead; 
} 
void MemoryCompressor::Clear(void) 
{ 
	if (output) 
	{ 
		free(output); 
		output=0; 
	} 
 
	if (streamInited) 
		BZ2_bzCompressEnd( &stream ); 
 
	totalRead=totalWritten=0; 
} 
void MemoryDecompressor::Clear(void) 
{ 
	if (output) 
	{ 
		free(output); 
		output=0; 
	} 
 
	if (streamInited) 
		BZ2_bzDecompressEnd( &stream ); 
}