From 66e533f5057bb56b68cfddb429e40b4a4be44b29 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Tue, 4 Jul 2023 14:04:41 +0800 Subject: [PATCH] Avoid redundant buffer copying PR #19272. --- src/base/utils/gzip.cpp | 60 +++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 38 deletions(-) diff --git a/src/base/utils/gzip.cpp b/src/base/utils/gzip.cpp index 4a9b15bbf..91c850442 100644 --- a/src/base/utils/gzip.cpp +++ b/src/base/utils/gzip.cpp @@ -31,6 +31,7 @@ #include +#include #include #ifndef ZLIB_CONST @@ -40,63 +41,46 @@ QByteArray Utils::Gzip::compress(const QByteArray &data, const int level, bool *ok) { - if (ok) *ok = false; + if (ok) + *ok = false; if (data.isEmpty()) return {}; - const int BUFSIZE = 128 * 1024; - std::vector tmpBuf(BUFSIZE); - z_stream strm {}; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; strm.next_in = reinterpret_cast(data.constData()); - strm.avail_in = uInt(data.size()); - strm.next_out = reinterpret_cast(tmpBuf.data()); - strm.avail_out = BUFSIZE; + strm.avail_in = static_cast(data.size()); // windowBits = 15 + 16 to enable gzip // From the zlib manual: windowBits can also be greater than 15 for optional gzip encoding. Add 16 to windowBits // to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper. - int result = deflateInit2(&strm, level, Z_DEFLATED, (15 + 16), 9, Z_DEFAULT_STRATEGY); - if (result != Z_OK) + const int initResult = deflateInit2(&strm, level, Z_DEFLATED, (15 + 16), 9, Z_DEFAULT_STRATEGY); + if (initResult != Z_OK) return {}; - QByteArray output; - output.reserve(deflateBound(&strm, data.size())); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) + QByteArray ret {static_cast(deflateBound(&strm, data.size())), Qt::Uninitialized}; +#else + QByteArray ret {static_cast(deflateBound(&strm, data.size())), Qt::Uninitialized}; +#endif + strm.next_out = reinterpret_cast(ret.data()); + strm.avail_out = ret.size(); - // feed to deflate - while (strm.avail_in > 0) - { - result = deflate(&strm, Z_NO_FLUSH); - - if (result != Z_OK) - { - deflateEnd(&strm); - return {}; - } - - output.append(tmpBuf.data(), (BUFSIZE - strm.avail_out)); - strm.next_out = reinterpret_cast(tmpBuf.data()); - strm.avail_out = BUFSIZE; - } - - // flush the rest from deflate - while (result != Z_STREAM_END) - { - result = deflate(&strm, Z_FINISH); - - output.append(tmpBuf.data(), (BUFSIZE - strm.avail_out)); - strm.next_out = reinterpret_cast(tmpBuf.data()); - strm.avail_out = BUFSIZE; - } + // From the zlib manual: Z_FINISH can be used in the first deflate call after deflateInit if all the compression + // is to be done in a single step. In order to complete in one call, avail_out must be at least the value + // returned by deflateBound (see below). Then deflate is guaranteed to return Z_STREAM_END. + const int deflateResult = deflate(&strm, Z_FINISH); + Q_ASSERT(deflateResult == Z_STREAM_END); deflateEnd(&strm); + ret.truncate(strm.total_out); - if (ok) *ok = true; - return output; + if (ok) + *ok = true; + return ret; } QByteArray Utils::Gzip::decompress(const QByteArray &data, bool *ok)