summaryrefslogblamecommitdiffstats
path: root/src/StringCompression.cpp
blob: a7f2db2a99ed3d47d306639a875152488640d018 (plain) (tree)
1
2
3
4
5
6
7






                                                                                                  




 
                                                                                              
 
                                                                            




                                                                                                                              
                                                                                                                                                                                                        











                                            
                                                                                                               




                                                                                                                              

                                                                                                                                                                                                   










                                                
 
                                                                                    







                                                                                                                


                                                                             








                                                                                                        
                







                                                                                                             
                                                                                  
































                                                                                                         
                                                                                               







                                                                                                                             


                                                                             








                                                                                                          
                
         
                                                 





                                                                                                                 
                                                                                  































                                                                                                           







                                                                                        


                                                                             

















                                                                                                                 
                                                                                  































                                                                                                       

// StringCompression.cpp

// Implements the wrapping functions for compression and decompression using AString as their data

#include "Globals.h"
#include "StringCompression.h"





int CompressString(const char * a_Data, size_t a_Length, AString & a_Compressed, int a_Factor)
{
	uLongf CompressedSize = compressBound(static_cast<uLong>(a_Length));
	
	// 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);
	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);
	if (errorcode != Z_OK)
	{
		return errorcode;
	}
	a_Compressed.resize(CompressedSize);
	return Z_OK;
}





int UncompressString(const char * a_Data, size_t a_Length, AString & a_Uncompressed, size_t a_UncompressedSize)
{
	// 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);
	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));
	if (errorcode != Z_OK)
	{
		return errorcode;
	}
	a_Uncompressed.resize(UncompressedSize);
	return Z_OK;
}





int CompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Compressed)
{
	// 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));
	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);
	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;
	}
	
	for (;;)
	{
		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);
				strm.next_out = reinterpret_cast<Bytef *>(Buffer);
				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)
}





extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Uncompressed)
{
	// 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));
	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);
	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;
	}
	
	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);
				strm.next_out = reinterpret_cast<Bytef *>(Buffer);
				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)
}





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));
	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);
	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);
				strm.next_out = reinterpret_cast<Bytef *>(Buffer);
				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)
}