From e38cc1d480fdcf3ad08829688fe1a61961612e36 Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Mon, 14 Sep 2015 02:25:47 +0200 Subject: GH-1227 add GZip compress function and a unit test fo GZip --- logic/GZip.cpp | 76 +++++++++++++++++++++++++++++++++++++++++++++++----------- logic/GZip.h | 1 + 2 files changed, 63 insertions(+), 14 deletions(-) (limited to 'logic') diff --git a/logic/GZip.cpp b/logic/GZip.cpp index 5207f3f0..d38d06e2 100644 --- a/logic/GZip.cpp +++ b/logic/GZip.cpp @@ -2,12 +2,6 @@ #include #include -// HACK: workaround for terrible macro crap on Windows -int wrap_inflate (z_streamp strm, int flush) -{ - return inflate(strm, flush); -} - bool GZip::decompress(const QByteArray &compressedBytes, QByteArray &uncompressedBytes) { if (compressedBytes.size() == 0) @@ -17,16 +11,13 @@ bool GZip::decompress(const QByteArray &compressedBytes, QByteArray &uncompresse } unsigned uncompLength = compressedBytes.size(); - unsigned half_length = compressedBytes.size() / 2; uncompressedBytes.clear(); uncompressedBytes.resize(uncompLength); z_stream strm; + memset(&strm, 0, sizeof(strm)); strm.next_in = (Bytef *)compressedBytes.data(); strm.avail_in = compressedBytes.size(); - strm.total_out = 0; - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; bool done = false; @@ -35,20 +26,22 @@ bool GZip::decompress(const QByteArray &compressedBytes, QByteArray &uncompresse return false; } + int err = Z_OK; + while (!done) { // If our output buffer is too small if (strm.total_out >= uncompLength) { - uncompressedBytes.resize(uncompLength + half_length); - uncompLength += half_length; + uncompressedBytes.resize(uncompLength * 2); + uncompLength *= 2; } strm.next_out = (Bytef *)(uncompressedBytes.data() + strm.total_out); strm.avail_out = uncompLength - strm.total_out; // Inflate another chunk. - int err = wrap_inflate(&strm, Z_SYNC_FLUSH); + err = inflate(&strm, Z_SYNC_FLUSH); if (err == Z_STREAM_END) done = true; else if (err != Z_OK) @@ -57,7 +50,7 @@ bool GZip::decompress(const QByteArray &compressedBytes, QByteArray &uncompresse } } - if (inflateEnd(&strm) != Z_OK) + if (inflateEnd(&strm) != Z_OK || !done) { return false; } @@ -65,3 +58,58 @@ bool GZip::decompress(const QByteArray &compressedBytes, QByteArray &uncompresse uncompressedBytes.resize(strm.total_out); return true; } + +bool GZip::compress(const QByteArray &uncompressedBytes, QByteArray &compressedBytes) +{ + if (uncompressedBytes.size() == 0) + { + compressedBytes = uncompressedBytes; + return true; + } + + unsigned compLength = std::min(uncompressedBytes.size(), 16); + compressedBytes.clear(); + compressedBytes.resize(compLength); + + z_stream zs; + memset(&zs, 0, sizeof(zs)); + + if (deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (16 + MAX_WBITS), 8, Z_DEFAULT_STRATEGY) != Z_OK) + { + return false; + } + + zs.next_in = (Bytef*)uncompressedBytes.data(); + zs.avail_in = uncompressedBytes.size(); + + int ret; + compressedBytes.resize(uncompressedBytes.size()); + + unsigned offset = 0; + unsigned temp = 0; + do + { + auto remaining = compressedBytes.size() - offset; + if(remaining < 1) + { + compressedBytes.resize(compressedBytes.size() * 2); + } + zs.next_out = (Bytef *) (compressedBytes.data() + offset); + temp = zs.avail_out = compressedBytes.size() - offset; + ret = deflate(&zs, Z_FINISH); + offset += temp - zs.avail_out; + } while (ret == Z_OK); + + compressedBytes.resize(offset); + + if (deflateEnd(&zs) != Z_OK) + { + return false; + } + + if (ret != Z_STREAM_END) + { + return false; + } + return true; +} \ No newline at end of file diff --git a/logic/GZip.h b/logic/GZip.h index 30f4f9b5..51be5ca1 100644 --- a/logic/GZip.h +++ b/logic/GZip.h @@ -7,5 +7,6 @@ class MULTIMC_LOGIC_EXPORT GZip { public: static bool decompress(const QByteArray &compressedBytes, QByteArray &uncompressedBytes); + static bool compress(const QByteArray &uncompressedBytes, QByteArray &compressedBytes); }; -- cgit