/*==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 . 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