243 lines
5.3 KiB
C++
243 lines
5.3 KiB
C++
/*
|
|
* 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 <assert.h>
|
|
#include <stdlib.h>
|
|
|
|
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 );
|
|
}
|
|
|