2012-06-14 09:06:06 -04:00
// StringCompression.cpp
// Implements the wrapping functions for compression and decompression using AString as their data
# include "Globals.h"
# include "StringCompression.h"
2014-05-08 14:16:35 -04:00
int CompressString ( const char * a_Data , size_t a_Length , AString & a_Compressed , int a_Factor )
2012-06-14 09:06:06 -04:00
{
2015-07-29 11:04:03 -04:00
uLongf CompressedSize = compressBound ( static_cast < uLong > ( a_Length ) ) ;
2012-06-14 09:06:06 -04:00
// HACK: We're assuming that AString returns its internal buffer in its data() call and we're overwriting that buffer!
// It saves us one allocation and one memcpy of the entire compressed data
// It may not work on some STL implementations! (Confirmed working on MSVC 2008 & 2010)
a_Compressed . resize ( CompressedSize ) ;
2015-07-29 11:04:03 -04:00
int errorcode = compress2 ( reinterpret_cast < Bytef * > ( const_cast < char * > ( a_Compressed . data ( ) ) ) , & CompressedSize , reinterpret_cast < const Bytef * > ( a_Data ) , static_cast < uLong > ( a_Length ) , a_Factor ) ;
2012-06-14 09:06:06 -04:00
if ( errorcode ! = Z_OK )
{
return errorcode ;
}
a_Compressed . resize ( CompressedSize ) ;
return Z_OK ;
}
2014-05-08 14:16:35 -04:00
int UncompressString ( const char * a_Data , size_t a_Length , AString & a_Uncompressed , size_t a_UncompressedSize )
2012-06-14 09:06:06 -04:00
{
// HACK: We're assuming that AString returns its internal buffer in its data() call and we're overwriting that buffer!
// It saves us one allocation and one memcpy of the entire compressed data
// It may not work on some STL implementations! (Confirmed working on MSVC 2008 & 2010)
a_Uncompressed . resize ( a_UncompressedSize ) ;
2015-07-29 11:04:03 -04:00
uLongf UncompressedSize = static_cast < uLongf > ( a_UncompressedSize ) ; // On some architectures the uLongf is different in size to int, that may be the cause of the -5 error
int errorcode = uncompress ( reinterpret_cast < Bytef * > ( const_cast < char * > ( a_Uncompressed . data ( ) ) ) , & UncompressedSize , reinterpret_cast < const Bytef * > ( a_Data ) , static_cast < uLong > ( a_Length ) ) ;
2012-06-14 09:06:06 -04:00
if ( errorcode ! = Z_OK )
{
return errorcode ;
}
a_Uncompressed . resize ( UncompressedSize ) ;
return Z_OK ;
}
2013-06-02 06:40:20 -04:00
2014-04-02 05:56:10 -04:00
int CompressStringGZIP ( const char * a_Data , size_t a_Length , AString & a_Compressed )
2013-06-02 06:40:20 -04:00
{
// Compress a_Data into a_Compressed using GZIP; return Z_XXX error constants same as zlib's compress2()
a_Compressed . reserve ( a_Length ) ;
char Buffer [ 64 KiB ] ;
z_stream strm ;
memset ( & strm , 0 , sizeof ( strm ) ) ;
2015-07-29 11:04:03 -04:00
strm . next_in = reinterpret_cast < Bytef * > ( const_cast < char * > ( a_Data ) ) ;
strm . avail_in = static_cast < uInt > ( a_Length ) ;
strm . next_out = reinterpret_cast < Bytef * > ( Buffer ) ;
2013-06-02 06:40:20 -04:00
strm . avail_out = sizeof ( Buffer ) ;
int res = deflateInit2 ( & strm , 9 , Z_DEFLATED , 31 , 9 , Z_DEFAULT_STRATEGY ) ;
if ( res ! = Z_OK )
{
LOG ( " %s: compression initialization failed: %d ( \" %s \" ). " , __FUNCTION__ , res , strm . msg ) ;
return res ;
}
2014-01-07 10:00:19 -05:00
for ( ; ; )
2013-06-02 06:40:20 -04:00
{
res = deflate ( & strm , Z_FINISH ) ;
switch ( res )
{
case Z_OK :
{
// Some data has been compressed. Consume the buffer and continue compressing
a_Compressed . append ( Buffer , sizeof ( Buffer ) - strm . avail_out ) ;
2015-07-29 11:04:03 -04:00
strm . next_out = reinterpret_cast < Bytef * > ( Buffer ) ;
2013-06-02 06:40:20 -04:00
strm . avail_out = sizeof ( Buffer ) ;
if ( strm . avail_in = = 0 )
{
// All data has been compressed
deflateEnd ( & strm ) ;
return Z_OK ;
}
break ;
}
case Z_STREAM_END :
{
// Finished compressing. Consume the rest of the buffer and return
a_Compressed . append ( Buffer , sizeof ( Buffer ) - strm . avail_out ) ;
deflateEnd ( & strm ) ;
return Z_OK ;
}
default :
{
// An error has occurred, log it and return the error value
LOG ( " %s: compression failed: %d ( \" %s \" ). " , __FUNCTION__ , res , strm . msg ) ;
deflateEnd ( & strm ) ;
return res ;
}
} // switch (res)
} // while (true)
}
2014-04-02 05:56:10 -04:00
extern int UncompressStringGZIP ( const char * a_Data , size_t a_Length , AString & a_Uncompressed )
2013-06-02 06:40:20 -04:00
{
// Uncompresses a_Data into a_Uncompressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib
a_Uncompressed . reserve ( a_Length ) ;
char Buffer [ 64 KiB ] ;
z_stream strm ;
memset ( & strm , 0 , sizeof ( strm ) ) ;
2015-07-29 11:04:03 -04:00
strm . next_in = reinterpret_cast < Bytef * > ( const_cast < char * > ( a_Data ) ) ;
strm . avail_in = static_cast < uInt > ( a_Length ) ;
strm . next_out = reinterpret_cast < Bytef * > ( Buffer ) ;
2013-06-02 06:40:20 -04:00
strm . avail_out = sizeof ( Buffer ) ;
int res = inflateInit2 ( & strm , 31 ) ; // Force GZIP decoding
if ( res ! = Z_OK )
{
LOG ( " %s: uncompression initialization failed: %d ( \" %s \" ). " , __FUNCTION__ , res , strm . msg ) ;
return res ;
}
2014-01-07 10:00:19 -05:00
for ( ; ; )
2013-06-02 06:40:20 -04:00
{
2014-04-02 05:56:10 -04:00
res = inflate ( & strm , Z_NO_FLUSH ) ;
2013-06-02 06:40:20 -04:00
switch ( res )
{
case Z_OK :
{
// Some data has been uncompressed. Consume the buffer and continue uncompressing
a_Uncompressed . append ( Buffer , sizeof ( Buffer ) - strm . avail_out ) ;
2015-07-29 11:04:03 -04:00
strm . next_out = reinterpret_cast < Bytef * > ( Buffer ) ;
2013-06-02 06:40:20 -04:00
strm . avail_out = sizeof ( Buffer ) ;
if ( strm . avail_in = = 0 )
{
// All data has been uncompressed
inflateEnd ( & strm ) ;
return Z_OK ;
}
break ;
}
case Z_STREAM_END :
{
// Finished uncompressing. Consume the rest of the buffer and return
a_Uncompressed . append ( Buffer , sizeof ( Buffer ) - strm . avail_out ) ;
inflateEnd ( & strm ) ;
return Z_OK ;
}
default :
{
// An error has occurred, log it and return the error value
LOG ( " %s: uncompression failed: %d ( \" %s \" ). " , __FUNCTION__ , res , strm . msg ) ;
inflateEnd ( & strm ) ;
return res ;
}
} // switch (res)
} // while (true)
}
2014-09-03 13:36:53 -04:00
extern int InflateString ( const char * a_Data , size_t a_Length , AString & a_Uncompressed )
{
a_Uncompressed . reserve ( a_Length ) ;
char Buffer [ 64 KiB ] ;
z_stream strm ;
memset ( & strm , 0 , sizeof ( strm ) ) ;
2015-07-29 11:04:03 -04:00
strm . next_in = reinterpret_cast < Bytef * > ( const_cast < char * > ( a_Data ) ) ;
strm . avail_in = static_cast < uInt > ( a_Length ) ;
strm . next_out = reinterpret_cast < Bytef * > ( Buffer ) ;
2014-09-03 13:36:53 -04:00
strm . avail_out = sizeof ( Buffer ) ;
int res = inflateInit ( & strm ) ; // Force GZIP decoding
if ( res ! = Z_OK )
{
LOG ( " %s: inflation initialization failed: %d ( \" %s \" ). " , __FUNCTION__ , res , strm . msg ) ;
return res ;
}
for ( ; ; )
{
res = inflate ( & strm , Z_NO_FLUSH ) ;
switch ( res )
{
case Z_OK :
{
// Some data has been uncompressed. Consume the buffer and continue uncompressing
a_Uncompressed . append ( Buffer , sizeof ( Buffer ) - strm . avail_out ) ;
2015-07-29 11:04:03 -04:00
strm . next_out = reinterpret_cast < Bytef * > ( Buffer ) ;
2014-09-03 13:36:53 -04:00
strm . avail_out = sizeof ( Buffer ) ;
if ( strm . avail_in = = 0 )
{
// All data has been uncompressed
inflateEnd ( & strm ) ;
return Z_OK ;
}
break ;
}
case Z_STREAM_END :
{
// Finished uncompressing. Consume the rest of the buffer and return
a_Uncompressed . append ( Buffer , sizeof ( Buffer ) - strm . avail_out ) ;
inflateEnd ( & strm ) ;
return Z_OK ;
}
default :
{
// An error has occurred, log it and return the error value
LOG ( " %s: inflation failed: %d ( \" %s \" ). " , __FUNCTION__ , res , strm . msg ) ;
inflateEnd ( & strm ) ;
return res ;
}
} // switch (res)
} // while (true)
}