Revise Utils::Gzip::decompress

Rename from uncompress to decompress
Change signature
Use proper casting
Use larger buffer for the output of inflate()
Reserve 1 MBytes for output buffer
Change function signature
This commit is contained in:
Chocobo1 2017-04-17 17:37:37 +08:00
parent 302c8ba850
commit 617f19e599
4 changed files with 44 additions and 40 deletions

View file

@ -92,8 +92,8 @@ void DownloadHandler::processFinishedDownload()
// Success // Success
QByteArray replyData = m_reply->readAll(); QByteArray replyData = m_reply->readAll();
if (m_reply->rawHeader("Content-Encoding") == "gzip") { if (m_reply->rawHeader("Content-Encoding") == "gzip") {
// uncompress gzip reply // decompress gzip reply
Utils::Gzip::uncompress(replyData, replyData); replyData = Utils::Gzip::decompress(replyData);
} }
if (m_saveToFile) { if (m_saveToFile) {

View file

@ -416,8 +416,10 @@ void GeoIPManager::downloadFinished(const QString &url, QByteArray data)
{ {
Q_UNUSED(url); Q_UNUSED(url);
if (!Utils::Gzip::uncompress(data, data)) { bool ok = false;
Logger::instance()->addMessage(tr("Could not uncompress GeoIP database file."), Log::WARNING); data = Utils::Gzip::decompress(data, &ok);
if (!ok) {
Logger::instance()->addMessage(tr("Could not decompress GeoIP database file."), Log::WARNING);
return; return;
} }

View file

@ -94,54 +94,56 @@ QByteArray Utils::Gzip::compress(const QByteArray &data, const int level, bool *
return output; return output;
} }
bool Utils::Gzip::uncompress(QByteArray src, QByteArray &dest) QByteArray Utils::Gzip::decompress(const QByteArray &data, bool *ok)
{ {
dest.clear(); if (ok) *ok = false;
if (src.size() <= 4) { if (data.isEmpty())
qWarning("uncompress: Input data is truncated"); return {};
return false;
} const int BUFSIZE = 1024 * 1024;
char tmpBuf[BUFSIZE] = {0};
z_stream strm; z_stream strm;
static const int CHUNK_SIZE = 1024;
char out[CHUNK_SIZE];
/* allocate inflate state */
strm.zalloc = Z_NULL; strm.zalloc = Z_NULL;
strm.zfree = Z_NULL; strm.zfree = Z_NULL;
strm.opaque = Z_NULL; strm.opaque = Z_NULL;
strm.avail_in = static_cast<uint>(src.size()); strm.next_in = reinterpret_cast<const Bytef *>(data.constData());
strm.next_in = reinterpret_cast<uchar *>(src.data()); strm.avail_in = uInt(data.size());
strm.next_out = reinterpret_cast<Bytef *>(tmpBuf);
strm.avail_out = BUFSIZE;
const int windowBits = 15; // windowBits must be greater than or equal to the windowBits value provided to deflateInit2() while compressing
const int ENABLE_ZLIB_GZIP = 32; // Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection
int result = inflateInit2(&strm, (15 + 32));
if (result != Z_OK)
return {};
int ret = inflateInit2(&strm, windowBits | ENABLE_ZLIB_GZIP); // gzip decoding QByteArray output;
if (ret != Z_OK) // from lzbench, level 9 average compression ratio is: 31.92%, which decompression ratio is: 1 / 0.3192 = 3.13
return false; output.reserve(data.size() * 3);
// run inflate() // run inflate
do { while (true) {
strm.avail_out = CHUNK_SIZE; result = inflate(&strm, Z_NO_FLUSH);
strm.next_out = reinterpret_cast<uchar *>(out);
ret = inflate(&strm, Z_NO_FLUSH); if (result == Z_STREAM_END) {
Q_ASSERT(ret != Z_STREAM_ERROR); // state not clobbered output.append(tmpBuf, (BUFSIZE - strm.avail_out));
break;
}
switch (ret) { if (result != Z_OK) {
case Z_NEED_DICT:
case Z_DATA_ERROR:
case Z_MEM_ERROR:
inflateEnd(&strm); inflateEnd(&strm);
return false; return {};
} }
dest.append(out, CHUNK_SIZE - strm.avail_out); output.append(tmpBuf, (BUFSIZE - strm.avail_out));
strm.next_out = reinterpret_cast<Bytef *>(tmpBuf);
strm.avail_out = BUFSIZE;
} }
while (!strm.avail_out);
// clean up and return
inflateEnd(&strm); inflateEnd(&strm);
return true;
if (ok) *ok = true;
return output;
} }

View file

@ -37,7 +37,7 @@ namespace Utils
namespace Gzip namespace Gzip
{ {
QByteArray compress(const QByteArray &data, int level = 6, bool *ok = nullptr); QByteArray compress(const QByteArray &data, int level = 6, bool *ok = nullptr);
bool uncompress(QByteArray src, QByteArray &dest); QByteArray decompress(const QByteArray &data, bool *ok = nullptr);
} }
} }