6#include <QtCore/private/qbytearray_p.h>
7#include <QtCore/qiodevice.h>
8#include <QtCore/qcoreapplication.h>
14# include <brotli/decode.h>
53 return static_cast<z_stream_s *
>(
ptr);
57BrotliDecoderState *toBrotliPointer(
void *
ptr)
59 return static_cast<BrotliDecoderState *
>(
ptr);
64ZSTD_DStream *toZstandardPointer(
void *
ptr)
66 return static_cast<ZSTD_DStream *
>(
ptr);
80 list.
reserve(
sizeof(contentEncodingMapping) /
sizeof(contentEncodingMapping[0]));
81 for (
const auto &
mapping : contentEncodingMapping) {
98 qWarning(
"Encoding is already set.");
115 contentEncoding = ce;
116 switch (contentEncoding) {
122 z_stream *inflateStream =
new z_stream;
123 memset(inflateStream, 0,
sizeof(z_stream));
127 if (inflateInit2(inflateStream, MAX_WBITS + 32) != Z_OK) {
128 delete inflateStream;
129 inflateStream =
nullptr;
131 decoderPointer = inflateStream;
136 decoderPointer = BrotliDecoderCreateInstance(
nullptr,
nullptr,
nullptr);
143 decoderPointer = ZSTD_createDStream();
149 if (!decoderPointer) {
151 "Failed to initialize the compression decoder.");
168 return countDecompressed;
190 countDecompressed = shouldCount;
211 auto totalUncompressed =
212 countHelper && countHelper->totalUncompressedBytes > totalUncompressedBytes
213 ? countHelper->totalUncompressedBytes
214 : totalUncompressedBytes;
215 return totalUncompressed - totalBytesRead;
239 totalCompressedBytes +=
data.size();
241 if (!countInternal(compressedDataBuffer[compressedDataBuffer.
bufferCount() - 1]))
252 totalCompressedBytes +=
buffer.byteAmount();
254 if (!countInternal(
buffer))
265 totalCompressedBytes +=
buffer.byteAmount();
268 if (!countInternal(
copy))
286bool QDecompressHelper::countInternal()
289 while (hasDataInternal()
290 && decompressedDataBuffer.
byteAmount() < MaxDecompressedDataBufferSize) {
296 buffer.truncate(bytesRead);
299 if (!hasDataInternal())
302 while (countHelper->hasData()) {
303 std::array<char, 1024> temp;
304 qsizetype bytesRead = countHelper->read(temp.data(), temp.size());
317 if (countDecompressed) {
319 countHelper = std::make_unique<QDecompressHelper>();
320 countHelper->setDecompressedSafetyCheckThreshold(archiveBombCheckThreshold);
321 countHelper->setEncoding(contentEncoding);
323 countHelper->feed(
data);
324 return countInternal();
335 if (countDecompressed) {
337 countHelper = std::make_unique<QDecompressHelper>();
338 countHelper->setDecompressedSafetyCheckThreshold(archiveBombCheckThreshold);
339 countHelper->setEncoding(contentEncoding);
341 countHelper->feed(
buffer);
342 return countInternal();
359 if (!decompressedDataBuffer.
isEmpty()) {
360 cachedRead = decompressedDataBuffer.
read(
data, maxSize);
362 maxSize -= cachedRead;
368 totalBytesRead += bytesRead + cachedRead;
369 return bytesRead + cachedRead;
384 if (!hasDataInternal())
388 switch (contentEncoding) {
394 bytesRead = readZLib(
data, maxSize);
397 bytesRead = readBrotli(
data, maxSize);
400 bytesRead = readZstandard(
data, maxSize);
406 totalUncompressedBytes += bytesRead;
407 if (isPotentialArchiveBomb()) {
410 "The decompressed output exceeds the limits specified by "
411 "QNetworkRequest::decompressedSafetyCheckThreshold()");
427 threshold = std::numeric_limits<qint64>::max();
428 archiveBombCheckThreshold = threshold;
431bool QDecompressHelper::isPotentialArchiveBomb()
const
433 if (totalCompressedBytes == 0)
436 if (totalUncompressedBytes <= archiveBombCheckThreshold)
441 double ratio = double(totalUncompressedBytes) / double(totalCompressedBytes);
442 switch (contentEncoding) {
476 return hasDataInternal() || !decompressedDataBuffer.
isEmpty();
484bool QDecompressHelper::hasDataInternal()
const
486 return encodedBytesAvailable() || decoderHasData;
489qint64 QDecompressHelper::encodedBytesAvailable()
const
503 return contentEncoding !=
None;
519 switch (contentEncoding) {
524 z_stream *inflateStream = toZlibPointer(decoderPointer);
526 inflateEnd(inflateStream);
527 delete inflateStream;
532 BrotliDecoderState *brotliDecoderState = toBrotliPointer(decoderPointer);
533 if (brotliDecoderState)
534 BrotliDecoderDestroyInstance(brotliDecoderState);
540 ZSTD_DStream *zstdStream = toZstandardPointer(decoderPointer);
542 ZSTD_freeDStream(zstdStream);
547 decoderPointer =
nullptr;
548 contentEncoding =
None;
550 compressedDataBuffer.
clear();
551 decompressedDataBuffer.
clear();
552 decoderHasData =
false;
554 countDecompressed =
false;
557 totalUncompressedBytes = 0;
558 totalCompressedBytes = 0;
565 bool triedRawDeflate =
false;
567 z_stream *inflateStream = toZlibPointer(decoderPointer);
568 static const size_t zlibMaxSize =
569 size_t(std::numeric_limits<
decltype(inflateStream->avail_in)>::max());
572 if (
size_t(
input.size()) > zlibMaxSize)
576 inflateStream->next_in =
reinterpret_cast<Bytef *
>(
const_cast<char *
>(
input.data()));
578 bool bigMaxSize = (zlibMaxSize < size_t(maxSize));
580 inflateStream->avail_out = adjustedAvailableOut;
581 inflateStream->next_out =
reinterpret_cast<Bytef *
>(
data);
585 auto previous_avail_out = inflateStream->avail_out;
591 if (
ret == Z_DATA_ERROR && !triedRawDeflate) {
592 inflateEnd(inflateStream);
593 triedRawDeflate =
true;
594 inflateStream->zalloc = Z_NULL;
595 inflateStream->zfree = Z_NULL;
596 inflateStream->opaque = Z_NULL;
597 inflateStream->avail_in = 0;
598 inflateStream->next_in = Z_NULL;
599 int ret = inflateInit2(inflateStream, -MAX_WBITS);
603 inflateStream->avail_in =
input.size();
604 inflateStream->next_in =
605 reinterpret_cast<Bytef *
>(
const_cast<char *
>(
input.data()));
608 }
else if (
ret < 0 ||
ret == Z_NEED_DICT) {
611 bytesDecoded +=
qsizetype(previous_avail_out - inflateStream->avail_out);
612 if (
ret == Z_STREAM_END) {
616 if (inflateStream->avail_in != 0) {
617 inflateEnd(inflateStream);
618 Bytef *next_in = inflateStream->next_in;
619 uInt avail_in = inflateStream->avail_in;
620 inflateStream->zalloc = Z_NULL;
621 inflateStream->zfree = Z_NULL;
622 inflateStream->opaque = Z_NULL;
623 if (inflateInit2(inflateStream, MAX_WBITS + 32) != Z_OK) {
624 delete inflateStream;
625 decoderPointer =
nullptr;
630 inflateStream->next_in = next_in;
631 inflateStream->avail_in = avail_in;
641 if (bigMaxSize && inflateStream->avail_out == 0) {
644 bigMaxSize = (zlibMaxSize < size_t(maxSize - bytesDecoded));
645 inflateStream->avail_out = bigMaxSize ?
qsizetype(zlibMaxSize) : maxSize - bytesDecoded;
646 inflateStream->next_out =
reinterpret_cast<Bytef *
>(
data + bytesDecoded);
649 if (inflateStream->avail_in == 0 && inflateStream->avail_out > 0) {
653 if (
size_t(
input.size()) > zlibMaxSize)
656 inflateStream->next_in =
657 reinterpret_cast<Bytef *
>(
const_cast<char *
>(
input.data()));
659 }
while (inflateStream->avail_out > 0 && inflateStream->avail_in > 0);
668#if !QT_CONFIG(brotli)
675 BrotliDecoderState *brotliDecoderState = toBrotliPointer(decoderPointer);
677 while (decoderHasData && bytesDecoded < maxSize) {
678 Q_ASSERT(brotliUnconsumedDataPtr || BrotliDecoderHasMoreOutput(brotliDecoderState));
679 if (brotliUnconsumedDataPtr) {
681 size_t toRead = std::min(
size_t(maxSize - bytesDecoded), brotliUnconsumedAmount);
682 memcpy(
data + bytesDecoded, brotliUnconsumedDataPtr, toRead);
683 bytesDecoded += toRead;
684 brotliUnconsumedAmount -= toRead;
685 brotliUnconsumedDataPtr += toRead;
686 if (brotliUnconsumedAmount == 0) {
687 brotliUnconsumedDataPtr =
nullptr;
688 decoderHasData =
false;
691 if (BrotliDecoderHasMoreOutput(brotliDecoderState) == BROTLI_TRUE) {
692 brotliUnconsumedDataPtr =
693 BrotliDecoderTakeOutput(brotliDecoderState, &brotliUnconsumedAmount);
694 decoderHasData =
true;
697 if (bytesDecoded == maxSize)
702 const uint8_t *encodedPtr =
reinterpret_cast<const uint8_t *
>(
input.data());
703 size_t encodedBytesRemaining =
input.
size();
705 uint8_t *decodedPtr =
reinterpret_cast<uint8_t *
>(
data + bytesDecoded);
706 size_t unusedDecodedSize = size_t(maxSize - bytesDecoded);
707 while (unusedDecodedSize > 0) {
708 auto previousUnusedDecodedSize = unusedDecodedSize;
709 BrotliDecoderResult
result = BrotliDecoderDecompressStream(
710 brotliDecoderState, &encodedBytesRemaining, &encodedPtr, &unusedDecodedSize,
711 &decodedPtr,
nullptr);
712 bytesDecoded += previousUnusedDecodedSize - unusedDecodedSize;
715 case BROTLI_DECODER_RESULT_ERROR:
718 BrotliDecoderGetErrorCode(brotliDecoderState))));
720 case BROTLI_DECODER_RESULT_SUCCESS:
721 BrotliDecoderDestroyInstance(brotliDecoderState);
722 decoderPointer =
nullptr;
723 compressedDataBuffer.
clear();
725 case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:
728 if (!
input.isEmpty()) {
729 encodedPtr =
reinterpret_cast<const uint8_t *
>(
input.constData());
734 case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:
736 decoderHasData = BrotliDecoderHasMoreOutput(brotliDecoderState);
753 ZSTD_DStream *zstdStream = toZstandardPointer(decoderPointer);
758 ZSTD_outBuffer outBuf {
data, size_t(maxSize), 0 };
761 while (outBuf.pos < outBuf.size && (inBuf.pos < inBuf.size || decoderHasData)) {
762 size_t retValue = ZSTD_decompressStream(zstdStream, &outBuf, &inBuf);
763 if (ZSTD_isError(retValue)) {
768 decoderHasData =
false;
769 bytesDecoded = outBuf.pos;
771 if (outBuf.pos == outBuf.size) {
772 decoderHasData =
true;
773 }
else if (inBuf.pos == inBuf.size) {
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
qsizetype bufferCount() const
qint64 byteAmount() const
static QString translate(const char *context, const char *key, const char *disambiguation=nullptr, int n=-1)
\threadsafe
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
QString arg(Args &&...args) const
void reserve(qsizetype size)
\macro QT_RESTRICTED_CAST_FROM_ASCII
void clear()
Clears the contents of the string and makes it null.
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Combined button and popup list for selecting options.
constexpr ContentEncodingMapping contentEncodingMapping[]
QDecompressHelper::ContentEncoding encodingFromByteArray(const QByteArray &ce) noexcept
z_stream * toZlibPointer(void *ptr)
constexpr Initialization Uninitialized
static jboolean copy(JNIEnv *, jobject)
static ControlElement< T > * ptr(QWidget *widget)
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLenum GLenum GLenum mapping
GLenum GLenum GLenum input
QLatin1StringView QLatin1String
static int inflate(Bytef *dest, ulong *destLen, const Bytef *source, ulong sourceLen)
QDecompressHelper::ContentEncoding encoding