You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

269 lines
6.2 KiB

/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plZlibCompress.h"
#include "zlib.h"
#include "hsMemory.h"
#include "hsStream.h"
hsBool plZlibCompress::Uncompress(UInt8* bufOut, UInt32* bufLenOut, const UInt8* bufIn, UInt32 bufLenIn)
{
return (uncompress(bufOut, bufLenOut, bufIn, bufLenIn) == Z_OK);
}
hsBool plZlibCompress::Compress(UInt8* bufOut, UInt32* bufLenOut, const UInt8* bufIn, UInt32 bufLenIn)
{
// according to compress doc, the bufOut buffer should be at least .1% larger than source buffer, plus 12 bytes.
hsAssert(*bufLenOut>=(int)(bufLenIn*1.1+12), "bufOut compress buffer is not large enough");
return (compress(bufOut, bufLenOut, bufIn, bufLenIn) == Z_OK);
}
//
// copy bufOut to bufIn, set bufLenIn=bufLenOut
//
hsBool plZlibCompress::ICopyBuffers(UInt8** bufIn, UInt32* bufLenIn, char* bufOut, UInt32 bufLenOut, int offset, bool ok)
{
if (ok)
{
*bufLenIn = bufLenOut+offset;
UInt8* newBuf = TRACKED_NEW UInt8[*bufLenIn]; // alloc new buffer
HSMemory::BlockMove(*bufIn, newBuf, offset); // copy offset (uncompressed) part
delete [] *bufIn; // delete original buffer
HSMemory::BlockMove(bufOut, newBuf+offset, bufLenOut); // copy compressed part
delete [] bufOut;
*bufIn = newBuf;
return true;
}
delete [] bufOut;
return false;
}
//
// In place version
// offset is how much to skip over when compressing
//
hsBool plZlibCompress::Compress(UInt8** bufIn, UInt32* bufLenIn, int offset)
{
UInt32 adjBufLenIn = *bufLenIn - offset;
UInt8* adjBufIn = *bufIn + offset;
// according to compress doc, the bufOut buffer should be at least .1% larger than source buffer, plus 12 bytes.
UInt32 bufLenOut = (int)(adjBufLenIn*1.1+12);
char* bufOut = TRACKED_NEW char[bufLenOut];
bool ok=(Compress((UInt8*)bufOut, &bufLenOut, (UInt8*)adjBufIn, adjBufLenIn) &&
bufLenOut < adjBufLenIn);
return ICopyBuffers(bufIn, bufLenIn, bufOut, bufLenOut, offset, ok);
}
//
// In place version
//
hsBool plZlibCompress::Uncompress(UInt8** bufIn, UInt32* bufLenIn, UInt32 bufLenOut, int offset)
{
UInt32 adjBufLenIn = *bufLenIn - offset;
UInt8* adjBufIn = *bufIn + offset;
char* bufOut = TRACKED_NEW char[bufLenOut];
bool ok=Uncompress((UInt8*)bufOut, &bufLenOut, (UInt8*)adjBufIn, adjBufLenIn) ? true : false;
return ICopyBuffers(bufIn, bufLenIn, bufOut, bufLenOut, offset, ok);
}
//// .gz File Versions ///////////////////////////////////////////////////////
#define kGzBufferSize 64 * 1024
#if 1
hsBool plZlibCompress::UncompressFile( const char *compressedPath, const char *destPath )
{
gzFile inFile;
FILE *outFile;
hsBool worked = false;
int length, err;
UInt8 buffer[ kGzBufferSize ];
outFile = fopen( destPath, "wb" );
if( outFile != nil )
{
inFile = gzopen( compressedPath, "rb" );
if( inFile != nil )
{
for( ;; )
{
length = gzread( inFile, buffer, sizeof( buffer ) );
if( length < 0 )
{
gzerror( inFile, &err );
break;
}
if( length == 0 )
{
worked = true;
break;
}
if( fwrite( buffer, 1, length, outFile ) != length )
break;
}
if( gzclose( inFile ) != Z_OK )
worked = false;
}
fclose( outFile );
}
return worked;
}
hsBool plZlibCompress::CompressFile( const char *uncompressedPath, const char *destPath )
{
FILE *inFile;
gzFile outFile;
hsBool worked = false;
int length, err;
UInt8 buffer[ kGzBufferSize ];
inFile = fopen( uncompressedPath, "rb" );
if( inFile != nil )
{
outFile = gzopen( destPath, "wb" );
if( outFile != nil )
{
for( ;; )
{
length = fread( buffer, 1, sizeof( buffer ), inFile );
if( ferror( inFile ) )
break;
if( length == 0 )
{
worked = true;
break;
}
if( gzwrite( outFile, buffer, (unsigned)length ) != length )
{
gzerror( outFile, &err );
break;
}
}
if( gzclose( outFile ) != Z_OK )
worked = false;
}
fclose( inFile );
}
return worked;
}
//// file <-> stream ///////////////////////////////////////////////////////
hsBool plZlibCompress::UncompressToStream( const char * filename, hsStream * s )
{
gzFile inFile;
hsBool worked = false;
int length, err;
UInt8 buffer[ kGzBufferSize ];
inFile = gzopen( filename, "rb" );
if( inFile != nil )
{
for( ;; )
{
length = gzread( inFile, buffer, sizeof( buffer ) );
if( length < 0 )
{
gzerror( inFile, &err );
break;
}
if( length == 0 )
{
worked = true;
break;
}
s->Write( length, buffer );
}
if( gzclose( inFile ) != Z_OK )
worked = false;
}
return worked;
}
hsBool plZlibCompress::CompressToFile( hsStream * s, const char * filename )
{
gzFile outFile;
hsBool worked = false;
int length, err;
UInt8 buffer[ kGzBufferSize ];
outFile = gzopen( filename, "wb" );
if( outFile != nil )
{
for( ;; )
{
int avail = s->GetEOF()-s->GetPosition();
int n = ( avail>sizeof( buffer ) ) ? sizeof( buffer ) : avail;
if( n == 0 )
{
worked = true;
break;
}
length = s->Read( n, buffer );
if( length == 0 )
{
worked = true;
break;
}
if( gzwrite( outFile, buffer, (unsigned)length ) != length )
{
gzerror( outFile, &err );
break;
}
}
if( gzclose( outFile ) != Z_OK )
worked = false;
}
return worked;
}
#endif