6#include <QtCore/qiodevice.h>
7#include <QtCore/qcoreapplication.h>
13# include <brotli/decode.h>
52 return static_cast<z_stream_s *
>(
ptr);
56BrotliDecoderState *toBrotliPointer(
void *
ptr)
58 return static_cast<BrotliDecoderState *
>(
ptr);
63ZSTD_DStream *toZstandardPointer(
void *
ptr)
65 return static_cast<ZSTD_DStream *
>(
ptr);
79 for (
const auto &
mapping : contentEncodingMapping) {
94 qWarning(
"Encoding is already set.");
111 contentEncoding = ce;
112 switch (contentEncoding) {
118 z_stream *inflateStream =
new z_stream;
119 memset(inflateStream, 0,
sizeof(z_stream));
123 if (inflateInit2(inflateStream, MAX_WBITS + 32) != Z_OK) {
124 delete inflateStream;
125 inflateStream =
nullptr;
127 decoderPointer = inflateStream;
132 decoderPointer = BrotliDecoderCreateInstance(
nullptr,
nullptr,
nullptr);
139 decoderPointer = ZSTD_createDStream();
145 if (!decoderPointer) {
147 "Failed to initialize the compression decoder.");
164 return countDecompressed;
186 countDecompressed = shouldCount;
207 auto totalUncompressed =
208 countHelper && countHelper->totalUncompressedBytes > totalUncompressedBytes
209 ? countHelper->totalUncompressedBytes
210 : totalUncompressedBytes;
211 return totalUncompressed - totalBytesRead;
235 totalCompressedBytes +=
data.size();
237 if (!countInternal(compressedDataBuffer[compressedDataBuffer.
bufferCount() - 1]))
248 totalCompressedBytes +=
buffer.byteAmount();
250 if (!countInternal(
buffer))
261 totalCompressedBytes +=
buffer.byteAmount();
264 if (!countInternal(
copy))
282bool QDecompressHelper::countInternal()
285 while (hasDataInternal()
286 && decompressedDataBuffer.
byteAmount() < MaxDecompressedDataBufferSize) {
292 buffer.truncate(bytesRead);
295 if (!hasDataInternal())
298 while (countHelper->hasData()) {
299 std::array<char, 1024> temp;
300 qsizetype bytesRead = countHelper->read(temp.data(), temp.size());
313 if (countDecompressed) {
315 countHelper = std::make_unique<QDecompressHelper>();
316 countHelper->setDecompressedSafetyCheckThreshold(archiveBombCheckThreshold);
317 countHelper->setEncoding(contentEncoding);
319 countHelper->feed(
data);
320 return countInternal();
331 if (countDecompressed) {
333 countHelper = std::make_unique<QDecompressHelper>();
334 countHelper->setDecompressedSafetyCheckThreshold(archiveBombCheckThreshold);
335 countHelper->setEncoding(contentEncoding);
337 countHelper->feed(
buffer);
338 return countInternal();
355 if (!decompressedDataBuffer.
isEmpty()) {
356 cachedRead = decompressedDataBuffer.
read(
data, maxSize);
358 maxSize -= cachedRead;
364 totalBytesRead += bytesRead + cachedRead;
365 return bytesRead + cachedRead;
380 if (!hasDataInternal())
384 switch (contentEncoding) {
390 bytesRead = readZLib(
data, maxSize);
393 bytesRead = readBrotli(
data, maxSize);
396 bytesRead = readZstandard(
data, maxSize);
402 totalUncompressedBytes += bytesRead;
403 if (isPotentialArchiveBomb()) {
406 "The decompressed output exceeds the limits specified by "
407 "QNetworkRequest::decompressedSafetyCheckThreshold()");
423 threshold = std::numeric_limits<qint64>::max();
424 archiveBombCheckThreshold = threshold;
427bool QDecompressHelper::isPotentialArchiveBomb()
const
429 if (totalCompressedBytes == 0)
432 if (totalUncompressedBytes <= archiveBombCheckThreshold)
437 double ratio = double(totalUncompressedBytes) / double(totalCompressedBytes);
438 switch (contentEncoding) {
472 return hasDataInternal() || !decompressedDataBuffer.
isEmpty();
480bool QDecompressHelper::hasDataInternal()
const
482 return encodedBytesAvailable() || decoderHasData;
485qint64 QDecompressHelper::encodedBytesAvailable()
const
499 return contentEncoding !=
None;
515 switch (contentEncoding) {
520 z_stream *inflateStream = toZlibPointer(decoderPointer);
522 inflateEnd(inflateStream);
523 delete inflateStream;
528 BrotliDecoderState *brotliDecoderState = toBrotliPointer(decoderPointer);
529 if (brotliDecoderState)
530 BrotliDecoderDestroyInstance(brotliDecoderState);
536 ZSTD_DStream *zstdStream = toZstandardPointer(decoderPointer);
538 ZSTD_freeDStream(zstdStream);
543 decoderPointer =
nullptr;
544 contentEncoding =
None;
546 compressedDataBuffer.
clear();
547 decompressedDataBuffer.
clear();
548 decoderHasData =
false;
550 countDecompressed =
false;
553 totalUncompressedBytes = 0;
554 totalCompressedBytes = 0;
561 bool triedRawDeflate =
false;
563 z_stream *inflateStream = toZlibPointer(decoderPointer);
564 static const size_t zlibMaxSize =
565 size_t(std::numeric_limits<
decltype(inflateStream->avail_in)>::max());
568 if (
size_t(
input.size()) > zlibMaxSize)
571 inflateStream->avail_in =
input.size();
572 inflateStream->next_in =
reinterpret_cast<Bytef *
>(
const_cast<char *
>(
input.data()));
574 bool bigMaxSize = (zlibMaxSize < size_t(maxSize));
576 inflateStream->avail_out = adjustedAvailableOut;
577 inflateStream->next_out =
reinterpret_cast<Bytef *
>(
data);
581 auto previous_avail_out = inflateStream->avail_out;
587 if (
ret == Z_DATA_ERROR && !triedRawDeflate) {
588 inflateEnd(inflateStream);
589 triedRawDeflate =
true;
590 inflateStream->zalloc = Z_NULL;
591 inflateStream->zfree = Z_NULL;
592 inflateStream->opaque = Z_NULL;
593 inflateStream->avail_in = 0;
594 inflateStream->next_in = Z_NULL;
595 int ret = inflateInit2(inflateStream, -MAX_WBITS);
599 inflateStream->avail_in =
input.size();
600 inflateStream->next_in =
601 reinterpret_cast<Bytef *
>(
const_cast<char *
>(
input.data()));
604 }
else if (
ret < 0 ||
ret == Z_NEED_DICT) {
607 bytesDecoded +=
qsizetype(previous_avail_out - inflateStream->avail_out);
608 if (
ret == Z_STREAM_END) {
612 if (inflateStream->avail_in != 0) {
613 inflateEnd(inflateStream);
614 Bytef *next_in = inflateStream->next_in;
615 uInt avail_in = inflateStream->avail_in;
616 inflateStream->zalloc = Z_NULL;
617 inflateStream->zfree = Z_NULL;
618 inflateStream->opaque = Z_NULL;
619 if (inflateInit2(inflateStream, MAX_WBITS + 32) != Z_OK) {
620 delete inflateStream;
621 decoderPointer =
nullptr;
626 inflateStream->next_in = next_in;
627 inflateStream->avail_in = avail_in;
637 if (bigMaxSize && inflateStream->avail_out == 0) {
640 bigMaxSize = (zlibMaxSize < size_t(maxSize - bytesDecoded));
641 inflateStream->avail_out = bigMaxSize ?
qsizetype(zlibMaxSize) : maxSize - bytesDecoded;
642 inflateStream->next_out =
reinterpret_cast<Bytef *
>(
data + bytesDecoded);
645 if (inflateStream->avail_in == 0 && inflateStream->avail_out > 0) {
649 if (
size_t(
input.size()) > zlibMaxSize)
651 inflateStream->avail_in =
input.size();
652 inflateStream->next_in =
653 reinterpret_cast<Bytef *
>(
const_cast<char *
>(
input.data()));
655 }
while (inflateStream->avail_out > 0 && inflateStream->avail_in > 0);
664#if !QT_CONFIG(brotli)
671 BrotliDecoderState *brotliDecoderState = toBrotliPointer(decoderPointer);
673 while (decoderHasData && bytesDecoded < maxSize) {
674 Q_ASSERT(brotliUnconsumedDataPtr || BrotliDecoderHasMoreOutput(brotliDecoderState));
675 if (brotliUnconsumedDataPtr) {
677 size_t toRead = std::min(
size_t(maxSize - bytesDecoded), brotliUnconsumedAmount);
678 memcpy(
data + bytesDecoded, brotliUnconsumedDataPtr, toRead);
679 bytesDecoded += toRead;
680 brotliUnconsumedAmount -= toRead;
681 brotliUnconsumedDataPtr += toRead;
682 if (brotliUnconsumedAmount == 0) {
683 brotliUnconsumedDataPtr =
nullptr;
684 decoderHasData =
false;
687 if (BrotliDecoderHasMoreOutput(brotliDecoderState) == BROTLI_TRUE) {
688 brotliUnconsumedDataPtr =
689 BrotliDecoderTakeOutput(brotliDecoderState, &brotliUnconsumedAmount);
690 decoderHasData =
true;
693 if (bytesDecoded == maxSize)
698 const uint8_t *encodedPtr =
reinterpret_cast<const uint8_t *
>(
input.data());
699 size_t encodedBytesRemaining =
input.
size();
701 uint8_t *decodedPtr =
reinterpret_cast<uint8_t *
>(
data + bytesDecoded);
702 size_t unusedDecodedSize = size_t(maxSize - bytesDecoded);
703 while (unusedDecodedSize > 0) {
704 auto previousUnusedDecodedSize = unusedDecodedSize;
705 BrotliDecoderResult
result = BrotliDecoderDecompressStream(
706 brotliDecoderState, &encodedBytesRemaining, &encodedPtr, &unusedDecodedSize,
707 &decodedPtr,
nullptr);
708 bytesDecoded += previousUnusedDecodedSize - unusedDecodedSize;
711 case BROTLI_DECODER_RESULT_ERROR:
714 BrotliDecoderGetErrorCode(brotliDecoderState))));
716 case BROTLI_DECODER_RESULT_SUCCESS:
717 BrotliDecoderDestroyInstance(brotliDecoderState);
718 decoderPointer =
nullptr;
719 compressedDataBuffer.
clear();
721 case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:
724 if (!
input.isEmpty()) {
725 encodedPtr =
reinterpret_cast<const uint8_t *
>(
input.constData());
730 case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:
732 decoderHasData = BrotliDecoderHasMoreOutput(brotliDecoderState);
749 ZSTD_DStream *zstdStream = toZstandardPointer(decoderPointer);
754 ZSTD_outBuffer outBuf {
data, size_t(maxSize), 0 };
757 while (outBuf.pos < outBuf.size && (inBuf.pos < inBuf.size || decoderHasData)) {
758 size_t retValue = ZSTD_decompressStream(zstdStream, &outBuf, &inBuf);
759 if (ZSTD_isError(retValue)) {
764 decoderHasData =
false;
765 bytesDecoded = outBuf.pos;
767 if (outBuf.pos == outBuf.size) {
768 decoderHasData =
true;
769 }
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)
bool setEncoding(QByteArrayView contentEncoding)
void feed(const QByteArray &data)
qint64 uncompressedSize() const
static QByteArrayList acceptedEncoding()
static bool isSupportedEncoding(QByteArrayView encoding)
qsizetype read(char *data, qsizetype maxSize)
void setDecompressedSafetyCheckThreshold(qint64 threshold)
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...
Combined button and popup list for selecting options.
constexpr ContentEncodingMapping contentEncodingMapping[]
QDecompressHelper::ContentEncoding encodingFromByteArray(QByteArrayView ce) noexcept
z_stream * toZlibPointer(void *ptr)
constexpr Initialization Uninitialized
static jboolean copy(JNIEnv *, jobject)
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
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