QtBase  v6.3.1
qdecompresshelper.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2020 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qdecompresshelper_p.h"
41 
42 #include <QtCore/private/qbytearray_p.h>
43 #include <QtCore/qiodevice.h>
44 #include <QtCore/qcoreapplication.h>
45 
46 #include <limits>
47 #include <zlib.h>
48 
49 #if QT_CONFIG(brotli)
50 # include <brotli/decode.h>
51 #endif
52 
53 #if QT_CONFIG(zstd)
54 # include <zstd.h>
55 #endif
56 
57 #include <array>
58 
60 namespace {
62 {
63  char name[8];
65 };
66 
68 #if QT_CONFIG(zstd)
69  { "zstd", QDecompressHelper::Zstandard },
70 #endif
71 #if QT_CONFIG(brotli)
72  { "br", QDecompressHelper::Brotli },
73 #endif
74  { "gzip", QDecompressHelper::GZip },
75  { "deflate", QDecompressHelper::Deflate },
76 };
77 
79 {
80  for (const auto &mapping : contentEncodingMapping) {
81  if (ce.compare(QByteArrayView(mapping.name, strlen(mapping.name)), Qt::CaseInsensitive) == 0)
82  return mapping.encoding;
83  }
85 }
86 
88 {
89  return static_cast<z_stream_s *>(ptr);
90 }
91 
92 #if QT_CONFIG(brotli)
93 BrotliDecoderState *toBrotliPointer(void *ptr)
94 {
95  return static_cast<BrotliDecoderState *>(ptr);
96 }
97 #endif
98 
99 #if QT_CONFIG(zstd)
100 ZSTD_DStream *toZstandardPointer(void *ptr)
101 {
102  return static_cast<ZSTD_DStream *>(ptr);
103 }
104 #endif
105 }
106 
108 {
110 }
111 
113 {
114  static QByteArrayList accepted = []() {
116  list.reserve(sizeof(contentEncodingMapping) / sizeof(contentEncodingMapping[0]));
117  for (const auto &mapping : contentEncodingMapping) {
118  list << QByteArray(mapping.name);
119  }
120  return list;
121  }();
122  return accepted;
123 }
124 
126 {
127  clear();
128 }
129 
131 {
132  Q_ASSERT(contentEncoding == QDecompressHelper::None);
133  if (contentEncoding != QDecompressHelper::None) {
134  qWarning("Encoding is already set.");
135  // This isn't an error, so it doesn't set errorStr, it's just wrong usage.
136  return false;
137  }
138  ContentEncoding ce = encodingFromByteArray(encoding);
139  if (ce == None) {
140  errorStr = QCoreApplication::translate("QHttp", "Unsupported content encoding: %1")
141  .arg(QLatin1String(encoding));
142  return false;
143  }
144  errorStr = QString(); // clear error
145  return setEncoding(ce);
146 }
147 
148 bool QDecompressHelper::setEncoding(ContentEncoding ce)
149 {
150  Q_ASSERT(contentEncoding == None);
151  contentEncoding = ce;
152  switch (contentEncoding) {
153  case None:
154  Q_UNREACHABLE();
155  break;
156  case Deflate:
157  case GZip: {
158  z_stream *inflateStream = new z_stream;
159  memset(inflateStream, 0, sizeof(z_stream));
160  // "windowBits can also be greater than 15 for optional gzip decoding.
161  // Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection"
162  // http://www.zlib.net/manual.html
163  if (inflateInit2(inflateStream, MAX_WBITS + 32) != Z_OK) {
164  delete inflateStream;
165  inflateStream = nullptr;
166  }
167  decoderPointer = inflateStream;
168  break;
169  }
170  case Brotli:
171 #if QT_CONFIG(brotli)
172  decoderPointer = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
173 #else
174  Q_UNREACHABLE();
175 #endif
176  break;
177  case Zstandard:
178 #if QT_CONFIG(zstd)
179  decoderPointer = ZSTD_createDStream();
180 #else
181  Q_UNREACHABLE();
182 #endif
183  break;
184  }
185  if (!decoderPointer) {
186  errorStr = QCoreApplication::translate("QHttp",
187  "Failed to initialize the compression decoder.");
188  contentEncoding = QDecompressHelper::None;
189  return false;
190  }
191  return true;
192 }
193 
203 {
204  return countDecompressed;
205 }
206 
221 {
222  // These are a best-effort check to ensure that no data has already been processed before this
223  // gets enabled
224  Q_ASSERT(compressedDataBuffer.byteAmount() == 0);
225  Q_ASSERT(contentEncoding == None);
226  countDecompressed = shouldCount;
227 }
228 
243 {
244  Q_ASSERT(countDecompressed);
245  // Use the 'totalUncompressedBytes' from the countHelper if it exceeds the amount of bytes
246  // that we know about.
247  auto totalUncompressed =
248  countHelper && countHelper->totalUncompressedBytes > totalUncompressedBytes
249  ? countHelper->totalUncompressedBytes
250  : totalUncompressedBytes;
251  return totalUncompressed - totalBytesRead;
252 }
253 
259 {
260  return feed(QByteArray(data));
261 }
262 
273 {
274  Q_ASSERT(contentEncoding != None);
275  totalCompressedBytes += data.size();
276  compressedDataBuffer.append(std::move(data));
277  if (!countInternal(compressedDataBuffer[compressedDataBuffer.bufferCount() - 1]))
278  clear(); // If our counting brother failed then so will we :|
279 }
280 
286 {
287  Q_ASSERT(contentEncoding != None);
288  totalCompressedBytes += buffer.byteAmount();
289  compressedDataBuffer.append(buffer);
290  if (!countInternal(buffer))
291  clear(); // If our counting brother failed then so will we :|
292 }
293 
299 {
300  Q_ASSERT(contentEncoding != None);
301  totalCompressedBytes += buffer.byteAmount();
302  const QByteDataBuffer copy(buffer);
303  compressedDataBuffer.append(std::move(buffer));
304  if (!countInternal(copy))
305  clear(); // If our counting brother failed then so will we :|
306 }
307 
322 bool QDecompressHelper::countInternal()
323 {
324  Q_ASSERT(countDecompressed);
325  while (hasDataInternal()
326  && decompressedDataBuffer.byteAmount() < MaxDecompressedDataBufferSize) {
327  const qsizetype toRead = 256 * 1024;
329  qsizetype bytesRead = readInternal(buffer.data(), buffer.size());
330  if (bytesRead == -1)
331  return false;
332  buffer.truncate(bytesRead);
333  decompressedDataBuffer.append(std::move(buffer));
334  }
335  if (!hasDataInternal())
336  return true; // handled all the data so far, just return
337 
338  while (countHelper->hasData()) {
339  std::array<char, 1024> temp;
340  qsizetype bytesRead = countHelper->read(temp.data(), temp.size());
341  if (bytesRead == -1)
342  return false;
343  }
344  return true;
345 }
346 
351 bool QDecompressHelper::countInternal(const QByteArray &data)
352 {
353  if (countDecompressed) {
354  if (!countHelper) {
355  countHelper = std::make_unique<QDecompressHelper>();
356  countHelper->setDecompressedSafetyCheckThreshold(archiveBombCheckThreshold);
357  countHelper->setEncoding(contentEncoding);
358  }
359  countHelper->feed(data);
360  return countInternal();
361  }
362  return true;
363 }
364 
369 bool QDecompressHelper::countInternal(const QByteDataBuffer &buffer)
370 {
371  if (countDecompressed) {
372  if (!countHelper) {
373  countHelper = std::make_unique<QDecompressHelper>();
374  countHelper->setDecompressedSafetyCheckThreshold(archiveBombCheckThreshold);
375  countHelper->setEncoding(contentEncoding);
376  }
377  countHelper->feed(buffer);
378  return countInternal();
379  }
380  return true;
381 }
382 
384 {
385  if (maxSize <= 0)
386  return 0;
387 
388  if (!isValid())
389  return -1;
390 
391  if (!hasData())
392  return 0;
393 
394  qsizetype cachedRead = 0;
395  if (!decompressedDataBuffer.isEmpty()) {
396  cachedRead = decompressedDataBuffer.read(data, maxSize);
397  data += cachedRead;
398  maxSize -= cachedRead;
399  }
400 
401  qsizetype bytesRead = readInternal(data, maxSize);
402  if (bytesRead == -1)
403  return -1;
404  totalBytesRead += bytesRead + cachedRead;
405  return bytesRead + cachedRead;
406 }
407 
413 qsizetype QDecompressHelper::readInternal(char *data, qsizetype maxSize)
414 {
415  Q_ASSERT(isValid());
416 
417  if (maxSize <= 0)
418  return 0;
419 
420  if (!hasDataInternal())
421  return 0;
422 
423  qsizetype bytesRead = -1;
424  switch (contentEncoding) {
425  case None:
426  Q_UNREACHABLE();
427  break;
428  case Deflate:
429  case GZip:
430  bytesRead = readZLib(data, maxSize);
431  break;
432  case Brotli:
433  bytesRead = readBrotli(data, maxSize);
434  break;
435  case Zstandard:
436  bytesRead = readZstandard(data, maxSize);
437  break;
438  }
439  if (bytesRead == -1)
440  clear();
441 
442  totalUncompressedBytes += bytesRead;
443  if (isPotentialArchiveBomb()) {
444  errorStr = QCoreApplication::translate(
445  "QHttp",
446  "The decompressed output exceeds the limits specified by "
447  "QNetworkRequest::decompressedSafetyCheckThreshold()");
448  return -1;
449  }
450 
451  return bytesRead;
452 }
453 
461 {
462  if (threshold == -1)
463  threshold = std::numeric_limits<qint64>::max();
464  archiveBombCheckThreshold = threshold;
465 }
466 
467 bool QDecompressHelper::isPotentialArchiveBomb() const
468 {
469  if (totalCompressedBytes == 0)
470  return false;
471 
472  if (totalUncompressedBytes <= archiveBombCheckThreshold)
473  return false;
474 
475  // Some protection against malicious or corrupted compressed files that expand far more than
476  // is reasonable.
477  double ratio = double(totalUncompressedBytes) / double(totalCompressedBytes);
478  switch (contentEncoding) {
479  case None:
480  Q_UNREACHABLE();
481  break;
482  case Deflate:
483  case GZip:
484  // This value is mentioned in docs for
485  // QNetworkRequest::setMinimumArchiveBombSize, keep synchronized
486  if (ratio > 40) {
487  return true;
488  }
489  break;
490  case Brotli:
491  case Zstandard:
492  // This value is mentioned in docs for
493  // QNetworkRequest::setMinimumArchiveBombSize, keep synchronized
494  if (ratio > 100) {
495  return true;
496  }
497  break;
498  }
499  return false;
500 }
501 
511 {
512  return hasDataInternal() || !decompressedDataBuffer.isEmpty();
513 }
514 
520 bool QDecompressHelper::hasDataInternal() const
521 {
522  return encodedBytesAvailable() || decoderHasData;
523 }
524 
525 qint64 QDecompressHelper::encodedBytesAvailable() const
526 {
527  return compressedDataBuffer.byteAmount();
528 }
529 
538 {
539  return contentEncoding != None;
540 }
541 
549 {
550  return errorStr;
551 }
552 
554 {
555  switch (contentEncoding) {
556  case None:
557  break;
558  case Deflate:
559  case GZip: {
560  z_stream *inflateStream = toZlibPointer(decoderPointer);
561  if (inflateStream)
562  inflateEnd(inflateStream);
563  delete inflateStream;
564  break;
565  }
566  case Brotli: {
567 #if QT_CONFIG(brotli)
568  BrotliDecoderState *brotliDecoderState = toBrotliPointer(decoderPointer);
569  if (brotliDecoderState)
570  BrotliDecoderDestroyInstance(brotliDecoderState);
571 #endif
572  break;
573  }
574  case Zstandard: {
575 #if QT_CONFIG(zstd)
576  ZSTD_DStream *zstdStream = toZstandardPointer(decoderPointer);
577  if (zstdStream)
578  ZSTD_freeDStream(zstdStream);
579 #endif
580  break;
581  }
582  }
583  decoderPointer = nullptr;
584  contentEncoding = None;
585 
586  compressedDataBuffer.clear();
587  decompressedDataBuffer.clear();
588  decoderHasData = false;
589 
590  countDecompressed = false;
591  countHelper.reset();
592  totalBytesRead = 0;
593  totalUncompressedBytes = 0;
594  totalCompressedBytes = 0;
595 
596  errorStr.clear();
597 }
598 
599 qsizetype QDecompressHelper::readZLib(char *data, const qsizetype maxSize)
600 {
601  bool triedRawDeflate = false;
602 
603  z_stream *inflateStream = toZlibPointer(decoderPointer);
604  static const size_t zlibMaxSize =
605  size_t(std::numeric_limits<decltype(inflateStream->avail_in)>::max());
606 
607  QByteArrayView input = compressedDataBuffer.readPointer();
608  if (size_t(input.size()) > zlibMaxSize)
609  input = input.sliced(zlibMaxSize);
610 
611  inflateStream->avail_in = input.size();
612  inflateStream->next_in = reinterpret_cast<Bytef *>(const_cast<char *>(input.data()));
613 
614  bool bigMaxSize = (zlibMaxSize < size_t(maxSize));
615  qsizetype adjustedAvailableOut = bigMaxSize ? qsizetype(zlibMaxSize) : maxSize;
616  inflateStream->avail_out = adjustedAvailableOut;
617  inflateStream->next_out = reinterpret_cast<Bytef *>(data);
618 
619  qsizetype bytesDecoded = 0;
620  do {
621  auto previous_avail_out = inflateStream->avail_out;
622  int ret = inflate(inflateStream, Z_NO_FLUSH);
623  // All negative return codes are errors, in the context of HTTP compression, Z_NEED_DICT is
624  // also an error.
625  // in the case where we get Z_DATA_ERROR this could be because we received raw deflate
626  // compressed data.
627  if (ret == Z_DATA_ERROR && !triedRawDeflate) {
628  inflateEnd(inflateStream);
629  triedRawDeflate = true;
630  inflateStream->zalloc = Z_NULL;
631  inflateStream->zfree = Z_NULL;
632  inflateStream->opaque = Z_NULL;
633  inflateStream->avail_in = 0;
634  inflateStream->next_in = Z_NULL;
635  int ret = inflateInit2(inflateStream, -MAX_WBITS);
636  if (ret != Z_OK) {
637  return -1;
638  } else {
639  inflateStream->avail_in = input.size();
640  inflateStream->next_in =
641  reinterpret_cast<Bytef *>(const_cast<char *>(input.data()));
642  continue;
643  }
644  } else if (ret < 0 || ret == Z_NEED_DICT) {
645  return -1;
646  }
647  bytesDecoded += qsizetype(previous_avail_out - inflateStream->avail_out);
648  if (ret == Z_STREAM_END) {
649 
650  // If there's more data after the stream then this is probably composed of multiple
651  // streams.
652  if (inflateStream->avail_in != 0) {
653  inflateEnd(inflateStream);
654  Bytef *next_in = inflateStream->next_in;
655  uInt avail_in = inflateStream->avail_in;
656  inflateStream->zalloc = Z_NULL;
657  inflateStream->zfree = Z_NULL;
658  inflateStream->opaque = Z_NULL;
659  if (inflateInit2(inflateStream, MAX_WBITS + 32) != Z_OK) {
660  delete inflateStream;
661  decoderPointer = nullptr;
662  // Failed to reinitialize, so we'll just return what we have
663  compressedDataBuffer.advanceReadPointer(input.size() - avail_in);
664  return bytesDecoded;
665  } else {
666  inflateStream->next_in = next_in;
667  inflateStream->avail_in = avail_in;
668  // Keep going to handle the other cases below
669  }
670  } else {
671  // No extra data, stream is at the end. We're done.
672  compressedDataBuffer.advanceReadPointer(input.size());
673  return bytesDecoded;
674  }
675  }
676 
677  if (bigMaxSize && inflateStream->avail_out == 0) {
678  // Need to adjust the next_out and avail_out parameters since we reached the end
679  // of the current range
680  bigMaxSize = (zlibMaxSize < size_t(maxSize - bytesDecoded));
681  inflateStream->avail_out = bigMaxSize ? qsizetype(zlibMaxSize) : maxSize - bytesDecoded;
682  inflateStream->next_out = reinterpret_cast<Bytef *>(data + bytesDecoded);
683  }
684 
685  if (inflateStream->avail_in == 0 && inflateStream->avail_out > 0) {
686  // Grab the next input!
687  compressedDataBuffer.advanceReadPointer(input.size());
688  input = compressedDataBuffer.readPointer();
689  if (size_t(input.size()) > zlibMaxSize)
690  input = input.sliced(zlibMaxSize);
691  inflateStream->avail_in = input.size();
692  inflateStream->next_in =
693  reinterpret_cast<Bytef *>(const_cast<char *>(input.data()));
694  }
695  } while (inflateStream->avail_out > 0 && inflateStream->avail_in > 0);
696 
697  compressedDataBuffer.advanceReadPointer(input.size() - inflateStream->avail_in);
698 
699  return bytesDecoded;
700 }
701 
702 qsizetype QDecompressHelper::readBrotli(char *data, const qsizetype maxSize)
703 {
704 #if !QT_CONFIG(brotli)
705  Q_UNUSED(data);
706  Q_UNUSED(maxSize);
707  Q_UNREACHABLE();
708 #else
709  qint64 bytesDecoded = 0;
710 
711  BrotliDecoderState *brotliDecoderState = toBrotliPointer(decoderPointer);
712 
713  while (decoderHasData && bytesDecoded < maxSize) {
714  Q_ASSERT(brotliUnconsumedDataPtr || BrotliDecoderHasMoreOutput(brotliDecoderState));
715  if (brotliUnconsumedDataPtr) {
716  Q_ASSERT(brotliUnconsumedAmount);
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;
725  }
726  }
727  if (BrotliDecoderHasMoreOutput(brotliDecoderState) == BROTLI_TRUE) {
728  brotliUnconsumedDataPtr =
729  BrotliDecoderTakeOutput(brotliDecoderState, &brotliUnconsumedAmount);
730  decoderHasData = true;
731  }
732  }
733  if (bytesDecoded == maxSize)
734  return bytesDecoded;
735  Q_ASSERT(bytesDecoded < maxSize);
736 
737  QByteArrayView input = compressedDataBuffer.readPointer();
738  const uint8_t *encodedPtr = reinterpret_cast<const uint8_t *>(input.data());
739  size_t encodedBytesRemaining = input.size();
740 
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;
749 
750  switch (result) {
751  case BROTLI_DECODER_RESULT_ERROR:
752  errorStr = QLatin1String("Brotli error: %1")
753  .arg(QString::fromUtf8(BrotliDecoderErrorString(
754  BrotliDecoderGetErrorCode(brotliDecoderState))));
755  return -1;
756  case BROTLI_DECODER_RESULT_SUCCESS:
757  BrotliDecoderDestroyInstance(brotliDecoderState);
758  decoderPointer = nullptr;
759  compressedDataBuffer.clear();
760  return bytesDecoded;
761  case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:
762  compressedDataBuffer.advanceReadPointer(input.size());
763  input = compressedDataBuffer.readPointer();
764  if (!input.isEmpty()) {
765  encodedPtr = reinterpret_cast<const uint8_t *>(input.constData());
766  encodedBytesRemaining = input.size();
767  break;
768  }
769  return bytesDecoded;
770  case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:
771  // Some data is leftover inside the brotli decoder, remember for next time
772  decoderHasData = BrotliDecoderHasMoreOutput(brotliDecoderState);
773  Q_ASSERT(unusedDecodedSize == 0);
774  break;
775  }
776  }
777  compressedDataBuffer.advanceReadPointer(input.size() - encodedBytesRemaining);
778  return bytesDecoded;
779 #endif
780 }
781 
782 qsizetype QDecompressHelper::readZstandard(char *data, const qsizetype maxSize)
783 {
784 #if !QT_CONFIG(zstd)
785  Q_UNUSED(data);
786  Q_UNUSED(maxSize);
787  Q_UNREACHABLE();
788 #else
789  ZSTD_DStream *zstdStream = toZstandardPointer(decoderPointer);
790 
791  QByteArrayView input = compressedDataBuffer.readPointer();
792  ZSTD_inBuffer inBuf { input.data(), size_t(input.size()), 0 };
793 
794  ZSTD_outBuffer outBuf { data, size_t(maxSize), 0 };
795 
796  qsizetype bytesDecoded = 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)) {
800  errorStr = QLatin1String("ZStandard error: %1")
801  .arg(QString::fromUtf8(ZSTD_getErrorName(retValue)));
802  return -1;
803  } else {
804  decoderHasData = false;
805  bytesDecoded = outBuf.pos;
806  // if pos == size then there may be data left over in internal buffers
807  if (outBuf.pos == outBuf.size) {
808  decoderHasData = true;
809  } else if (inBuf.pos == inBuf.size) {
810  compressedDataBuffer.advanceReadPointer(input.size());
811  input = compressedDataBuffer.readPointer();
812  inBuf = { input.constData(), size_t(input.size()), 0 };
813  }
814  }
815  }
816  compressedDataBuffer.advanceReadPointer(inBuf.pos);
817  return bytesDecoded;
818 #endif
819 }
820 
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
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
bool isEmpty() const
Definition: qbytedata_p.h:273
void append(const QByteDataBuffer &other)
Definition: qbytedata_p.h:82
int bufferCount() const
Definition: qbytedata_p.h:268
void advanceReadPointer(qint64 distance)
Definition: qbytedata_p.h:221
QByteArrayView readPointer() const
Definition: qbytedata_p.h:207
QByteArray read()
Definition: qbytedata_p.h:140
qint64 byteAmount() const
Definition: qbytedata_p.h:262
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.
Definition: qstring.h:84
QString arg(Args &&...args) const
The QString class provides a Unicode character string.
Definition: qstring.h:388
void clear()
Definition: qstring.h:1240
static QString fromUtf8(QByteArrayView utf8)
Definition: qstring.cpp:5632
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=QLatin1Char(' ')) const
Definition: qstring.cpp:8318
#define Z_NEED_DICT
Definition: zlib.h:134
#define inflateInit2(strm, windowBits)
Definition: zlib.h:822
#define Z_STREAM_END
Definition: zlib.h:133
#define Z_OK
Definition: zlib.h:132
#define Z_DATA_ERROR
Definition: zlib.h:137
struct z_stream_s z_stream
#define Z_NO_FLUSH
Definition: zlib.h:125
#define Z_NULL
Definition: zlib.h:164
unsigned int uInt
Definition: ftzconf.h:221
#define MAX_WBITS
Definition: ftzconf.h:124
Byte FAR Bytef
Definition: ftzconf.h:228
constexpr ContentEncodingMapping contentEncodingMapping[]
QDecompressHelper::ContentEncoding encodingFromByteArray(const QByteArray &ce) noexcept
z_stream * toZlibPointer(void *ptr)
@ CaseInsensitive
Definition: qnamespace.h:1283
constexpr Initialization Uninitialized
Definition: qnamespace.h:1613
#define QString()
Definition: parse-defines.h:51
PCRE2_SIZE PRIV() strlen(PCRE2_SPTR str)
#define Q_UNREACHABLE()
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
ptrdiff_t qsizetype
Definition: qglobal.h:308
long long qint64
Definition: qglobal.h:298
#define qWarning
Definition: qlogging.h:179
GLenum GLuint buffer
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint name
GLuint64EXT * result
[6]
Definition: qopenglext.h:10932
GLenum GLenum GLenum GLenum mapping
Definition: qopenglext.h:10816
GLenum GLenum GLenum input
Definition: qopenglext.h:10816
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
Q_UNUSED(salary)
[21]
QStringList list
[0]
QDecompressHelper::ContentEncoding encoding
uInt avail_in
Definition: zlib.h:70
Bytef * next_in
Definition: zlib.h:69
alloc_func zalloc
Definition: zlib.h:80
uInt avail_out
Definition: zlib.h:74
Bytef * next_out
Definition: zlib.h:73
free_func zfree
Definition: zlib.h:81
voidpf opaque
Definition: zlib.h:82
int ZEXPORT inflate(z_streamp strm, int flush)
Definition: inflate.c:623
int ZEXPORT inflateEnd(z_streamp strm)
Definition: inflate.c:1301