42 #include <QtCore/private/qbytearray_p.h>
43 #include <QtCore/qiodevice.h>
44 #include <QtCore/qcoreapplication.h>
50 # include <brotli/decode.h>
93 BrotliDecoderState *toBrotliPointer(
void *ptr)
95 return static_cast<BrotliDecoderState *
>(ptr);
100 ZSTD_DStream *toZstandardPointer(
void *ptr)
102 return static_cast<ZSTD_DStream *
>(ptr);
134 qWarning(
"Encoding is already set.");
151 contentEncoding = ce;
152 switch (contentEncoding) {
159 memset(inflateStream, 0,
sizeof(
z_stream));
164 delete inflateStream;
165 inflateStream =
nullptr;
167 decoderPointer = inflateStream;
171 #if QT_CONFIG(brotli)
172 decoderPointer = BrotliDecoderCreateInstance(
nullptr,
nullptr,
nullptr);
179 decoderPointer = ZSTD_createDStream();
185 if (!decoderPointer) {
187 "Failed to initialize the compression decoder.");
204 return countDecompressed;
226 countDecompressed = shouldCount;
247 auto totalUncompressed =
248 countHelper && countHelper->totalUncompressedBytes > totalUncompressedBytes
249 ? countHelper->totalUncompressedBytes
250 : totalUncompressedBytes;
251 return totalUncompressed - totalBytesRead;
275 totalCompressedBytes +=
data.size();
277 if (!countInternal(compressedDataBuffer[compressedDataBuffer.
bufferCount() - 1]))
288 totalCompressedBytes +=
buffer.byteAmount();
290 if (!countInternal(
buffer))
301 totalCompressedBytes +=
buffer.byteAmount();
304 if (!countInternal(copy))
322 bool QDecompressHelper::countInternal()
325 while (hasDataInternal()
326 && decompressedDataBuffer.
byteAmount() < MaxDecompressedDataBufferSize) {
332 buffer.truncate(bytesRead);
335 if (!hasDataInternal())
338 while (countHelper->hasData()) {
339 std::array<char, 1024> temp;
340 qsizetype bytesRead = countHelper->read(temp.data(), temp.size());
353 if (countDecompressed) {
355 countHelper = std::make_unique<QDecompressHelper>();
356 countHelper->setDecompressedSafetyCheckThreshold(archiveBombCheckThreshold);
357 countHelper->setEncoding(contentEncoding);
359 countHelper->feed(
data);
360 return countInternal();
371 if (countDecompressed) {
373 countHelper = std::make_unique<QDecompressHelper>();
374 countHelper->setDecompressedSafetyCheckThreshold(archiveBombCheckThreshold);
375 countHelper->setEncoding(contentEncoding);
377 countHelper->feed(
buffer);
378 return countInternal();
395 if (!decompressedDataBuffer.
isEmpty()) {
396 cachedRead = decompressedDataBuffer.
read(
data, maxSize);
398 maxSize -= cachedRead;
404 totalBytesRead += bytesRead + cachedRead;
405 return bytesRead + cachedRead;
420 if (!hasDataInternal())
424 switch (contentEncoding) {
430 bytesRead = readZLib(
data, maxSize);
433 bytesRead = readBrotli(
data, maxSize);
436 bytesRead = readZstandard(
data, maxSize);
442 totalUncompressedBytes += bytesRead;
443 if (isPotentialArchiveBomb()) {
446 "The decompressed output exceeds the limits specified by "
447 "QNetworkRequest::decompressedSafetyCheckThreshold()");
463 threshold = std::numeric_limits<qint64>::max();
464 archiveBombCheckThreshold = threshold;
467 bool QDecompressHelper::isPotentialArchiveBomb()
const
469 if (totalCompressedBytes == 0)
472 if (totalUncompressedBytes <= archiveBombCheckThreshold)
477 double ratio = double(totalUncompressedBytes) / double(totalCompressedBytes);
478 switch (contentEncoding) {
512 return hasDataInternal() || !decompressedDataBuffer.
isEmpty();
520 bool QDecompressHelper::hasDataInternal()
const
522 return encodedBytesAvailable() || decoderHasData;
525 qint64 QDecompressHelper::encodedBytesAvailable()
const
539 return contentEncoding !=
None;
555 switch (contentEncoding) {
563 delete inflateStream;
567 #if QT_CONFIG(brotli)
568 BrotliDecoderState *brotliDecoderState = toBrotliPointer(decoderPointer);
569 if (brotliDecoderState)
570 BrotliDecoderDestroyInstance(brotliDecoderState);
576 ZSTD_DStream *zstdStream = toZstandardPointer(decoderPointer);
578 ZSTD_freeDStream(zstdStream);
583 decoderPointer =
nullptr;
584 contentEncoding =
None;
586 compressedDataBuffer.
clear();
587 decompressedDataBuffer.
clear();
588 decoderHasData =
false;
590 countDecompressed =
false;
593 totalUncompressedBytes = 0;
594 totalCompressedBytes = 0;
601 bool triedRawDeflate =
false;
604 static const size_t zlibMaxSize =
605 size_t(std::numeric_limits<decltype(inflateStream->
avail_in)>::max());
608 if (
size_t(
input.size()) > zlibMaxSize)
612 inflateStream->
next_in =
reinterpret_cast<Bytef *
>(
const_cast<char *
>(
input.data()));
614 bool bigMaxSize = (zlibMaxSize < size_t(maxSize));
616 inflateStream->
avail_out = adjustedAvailableOut;
621 auto previous_avail_out = inflateStream->
avail_out;
629 triedRawDeflate =
true;
641 reinterpret_cast<Bytef *
>(
const_cast<char *
>(
input.data()));
660 delete inflateStream;
661 decoderPointer =
nullptr;
666 inflateStream->
next_in = next_in;
677 if (bigMaxSize && inflateStream->
avail_out == 0) {
680 bigMaxSize = (zlibMaxSize < size_t(maxSize - bytesDecoded));
681 inflateStream->
avail_out = bigMaxSize ?
qsizetype(zlibMaxSize) : maxSize - bytesDecoded;
689 if (
size_t(
input.size()) > zlibMaxSize)
693 reinterpret_cast<Bytef *
>(
const_cast<char *
>(
input.data()));
704 #if !QT_CONFIG(brotli)
711 BrotliDecoderState *brotliDecoderState = toBrotliPointer(decoderPointer);
713 while (decoderHasData && bytesDecoded < maxSize) {
714 Q_ASSERT(brotliUnconsumedDataPtr || BrotliDecoderHasMoreOutput(brotliDecoderState));
715 if (brotliUnconsumedDataPtr) {
717 size_t toRead = std::min(
size_t(maxSize - bytesDecoded), brotliUnconsumedAmount);
718 memcpy(
data + bytesDecoded, brotliUnconsumedDataPtr, toRead);
719 bytesDecoded += toRead;
720 brotliUnconsumedAmount -= toRead;
721 brotliUnconsumedDataPtr += toRead;
722 if (brotliUnconsumedAmount == 0) {
723 brotliUnconsumedDataPtr =
nullptr;
724 decoderHasData =
false;
727 if (BrotliDecoderHasMoreOutput(brotliDecoderState) == BROTLI_TRUE) {
728 brotliUnconsumedDataPtr =
729 BrotliDecoderTakeOutput(brotliDecoderState, &brotliUnconsumedAmount);
730 decoderHasData =
true;
733 if (bytesDecoded == maxSize)
738 const uint8_t *encodedPtr =
reinterpret_cast<const uint8_t *
>(
input.data());
739 size_t encodedBytesRemaining =
input.
size();
741 uint8_t *decodedPtr =
reinterpret_cast<uint8_t *
>(
data + bytesDecoded);
742 size_t unusedDecodedSize = size_t(maxSize - bytesDecoded);
743 while (unusedDecodedSize > 0) {
744 auto previousUnusedDecodedSize = unusedDecodedSize;
745 BrotliDecoderResult
result = BrotliDecoderDecompressStream(
746 brotliDecoderState, &encodedBytesRemaining, &encodedPtr, &unusedDecodedSize,
747 &decodedPtr,
nullptr);
748 bytesDecoded += previousUnusedDecodedSize - unusedDecodedSize;
751 case BROTLI_DECODER_RESULT_ERROR:
754 BrotliDecoderGetErrorCode(brotliDecoderState))));
756 case BROTLI_DECODER_RESULT_SUCCESS:
757 BrotliDecoderDestroyInstance(brotliDecoderState);
758 decoderPointer =
nullptr;
759 compressedDataBuffer.
clear();
761 case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:
764 if (!
input.isEmpty()) {
765 encodedPtr =
reinterpret_cast<const uint8_t *
>(
input.constData());
770 case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:
772 decoderHasData = BrotliDecoderHasMoreOutput(brotliDecoderState);
789 ZSTD_DStream *zstdStream = toZstandardPointer(decoderPointer);
794 ZSTD_outBuffer outBuf {
data, size_t(maxSize), 0 };
797 while (outBuf.pos < outBuf.size && (inBuf.pos < inBuf.size || decoderHasData)) {
798 size_t retValue = ZSTD_decompressStream(zstdStream, &outBuf, &inBuf);
799 if (ZSTD_isError(retValue)) {
804 decoderHasData =
false;
805 bytesDecoded = outBuf.pos;
807 if (outBuf.pos == outBuf.size) {
808 decoderHasData =
true;
809 }
else if (inBuf.pos == inBuf.size) {
The QByteArray class provides an array of bytes.
The QByteArrayList class provides a list of byte arrays.
constexpr QByteArrayView sliced(qsizetype pos) const
constexpr qsizetype size() const noexcept
constexpr const_pointer data() const noexcept
constexpr const_pointer constData() const noexcept
void append(const QByteDataBuffer &other)
void advanceReadPointer(qint64 distance)
QByteArrayView readPointer() const
qint64 byteAmount() const
static QString translate(const char *context, const char *key, const char *disambiguation=nullptr, int n=-1)
void setCountingBytesEnabled(bool shouldCount)
void feed(const QByteArray &data)
qint64 uncompressedSize() const
static QByteArrayList acceptedEncoding()
bool setEncoding(const QByteArray &contentEncoding)
qsizetype read(char *data, qsizetype maxSize)
void setDecompressedSafetyCheckThreshold(qint64 threshold)
static bool isSupportedEncoding(const QByteArray &encoding)
bool isCountingBytes() const
QString errorString() const
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
QString arg(Args &&...args) const
The QString class provides a Unicode character string.
static QString fromUtf8(QByteArrayView utf8)
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=QLatin1Char(' ')) const
#define inflateInit2(strm, windowBits)
struct z_stream_s z_stream
constexpr ContentEncodingMapping contentEncodingMapping[]
QDecompressHelper::ContentEncoding encodingFromByteArray(const QByteArray &ce) noexcept
z_stream * toZlibPointer(void *ptr)
constexpr Initialization Uninitialized
PCRE2_SIZE PRIV() strlen(PCRE2_SPTR str)
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLenum GLenum GLenum mapping
GLenum GLenum GLenum input
QDecompressHelper::ContentEncoding encoding
int ZEXPORT inflate(z_streamp strm, int flush)
int ZEXPORT inflateEnd(z_streamp strm)