1
0
cuberite-2a/src/StringCompression.cpp
madmaxoft 44c1d9c248 Anvil: switched inflate to stream mode.
This removes the fixed-size buffer which could have caused #1307 and #1366.
2014-09-03 19:36:53 +02:00

245 lines
6.3 KiB
C++

// StringCompression.cpp
// Implements the wrapping functions for compression and decompression using AString as their data
#include "Globals.h"
#include "StringCompression.h"
/// Compresses a_Data into a_Compressed; returns Z_XXX error constants same as zlib's compress2()
int CompressString(const char * a_Data, size_t a_Length, AString & a_Compressed, int a_Factor)
{
uLongf CompressedSize = compressBound((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((Bytef*)a_Compressed.data(), &CompressedSize, (const Bytef *)a_Data, (uLong)a_Length, a_Factor);
if (errorcode != Z_OK)
{
return errorcode;
}
a_Compressed.resize(CompressedSize);
return Z_OK;
}
/// Uncompresses a_Data into a_Decompressed; returns Z_XXX error constants same as zlib's uncompress()
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 = (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((Bytef*)a_Uncompressed.data(), &UncompressedSize, (const Bytef*)a_Data, (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 = (Bytef *)a_Data;
strm.avail_in = (uInt)a_Length;
strm.next_out = (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 = (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 = (Bytef *)a_Data;
strm.avail_in = (uInt)a_Length;
strm.next_out = (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 = (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 = (Bytef *)a_Data;
strm.avail_in = (uInt)a_Length;
strm.next_out = (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 = (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)
}