/* * Copyright (c) 2014, Oculus VR, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * RakNet License.txt file in the licenses directory of this source tree. An additional grant * of patent rights can be found in the RakNet Patents.txt file in the same directory. * */ // See http://www.bzip.org/1.0.3/bzip2-manual-1.0.3.html#low-level for docs on bzip #include "MemoryCompressor.h" #include #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() { compressedInputLength=0; } 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 < BZ_MAX_UNUSED) allocatedSize=BZ_MAX_UNUSED; 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; compressedInputLength+=inputLength; 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_out>0) // 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*=2; 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 < BZ_MAX_UNUSED) allocatedSize=BZ_MAX_UNUSED; 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 MemoryCompressor::GetCompressedInputLength(void) const { return compressedInputLength; } 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=compressedInputLength=0; } void MemoryDecompressor::Clear(void) { if (output) { free(output); output=0; } if (streamInited) BZ2_bzDecompressEnd( &stream ); }