summaryrefslogtreecommitdiffstats
path: root/src/corelib/text/qbytearray.cpp
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2019-12-09 01:00:35 +0100
committerLars Knoll <lars.knoll@qt.io>2019-12-09 10:16:01 +0100
commitbef74b6c3a0a9c8649ea8eb333d80015f76863e4 (patch)
tree41cdf5b6776c90a6d04a1d6680f4d47a90593746 /src/corelib/text/qbytearray.cpp
parentf8d2975b6a8b36bf8dd304c99783947a72081b79 (diff)
parent4c3c63d4cbb81b38e88e06b72749e7e01497b6f1 (diff)
Merge remote-tracking branch 'origin/5.15' into dev
Diffstat (limited to 'src/corelib/text/qbytearray.cpp')
-rw-r--r--src/corelib/text/qbytearray.cpp269
1 files changed, 233 insertions, 36 deletions
diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp
index 3f5fef80e2..83182dbd93 100644
--- a/src/corelib/text/qbytearray.cpp
+++ b/src/corelib/text/qbytearray.cpp
@@ -2,6 +2,7 @@
**
** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2016 Intel Corporation.
+** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -41,6 +42,7 @@
#include "qbytearray.h"
#include "qbytearraymatcher.h"
#include "private/qtools_p.h"
+#include "qhashfunctions.h"
#include "qstring.h"
#include "qlist.h"
#include "qlocale.h"
@@ -986,10 +988,20 @@ QByteArray qUncompress(const uchar* data, int nbytes)
four.
\value OmitTrailingEquals Omits adding the padding equal signs at the end of the encoded
data.
-
- QByteArray::fromBase64() ignores the KeepTrailingEquals and
- OmitTrailingEquals options and will not flag errors in case they are
- missing or if there are too many of them.
+ \value IgnoreBase64DecodingErrors When decoding Base64-encoded data, ignores errors
+ in the input; invalid characters are simply skipped.
+ This enum value has been added in Qt 5.15.
+ \value AbortOnBase64DecodingErrors When decoding Base64-encoded data, stops at the first
+ decoding error.
+ This enum value has been added in Qt 5.15.
+
+ QByteArray::fromBase64Encoding() and QByteArray::fromBase64()
+ ignore the KeepTrailingEquals and OmitTrailingEquals options. If
+ the IgnoreBase64DecodingErrors option is specified, they will not
+ flag errors in case trailing equal signs are missing or if there
+ are too many of them. If instead the AbortOnBase64DecodingErrors is
+ specified, then the input must either have no padding or have the
+ correct amount of equal signs.
*/
/*! \fn QByteArray::iterator QByteArray::begin()
@@ -4411,63 +4423,166 @@ QByteArray &QByteArray::setRawData(const char *data, uint size)
return *this;
}
-/*!
- \since 5.2
-
- Returns a decoded copy of the Base64 array \a base64, using the alphabet
- defined by \a options. Input is not checked for validity; invalid
- characters in the input are skipped, enabling the decoding process to
- continue with subsequent characters.
-
- For example:
-
- \snippet code/src_corelib_tools_qbytearray.cpp 44
-
- The algorithm used to decode Base64-encoded data is defined in \l{RFC 4648}.
+namespace {
+struct fromBase64_helper_result {
+ qsizetype decodedLength;
+ QByteArray::Base64DecodingStatus status;
+};
- \sa toBase64()
-*/
-QByteArray QByteArray::fromBase64(const QByteArray &base64, Base64Options options)
+fromBase64_helper_result fromBase64_helper(const char *input, qsizetype inputSize,
+ char *output /* may alias input */,
+ QByteArray::Base64Options options)
{
+ fromBase64_helper_result result{ 0, QByteArray::Base64DecodingStatus::Ok };
+
unsigned int buf = 0;
int nbits = 0;
- QByteArray tmp((base64.size() * 3) / 4, Qt::Uninitialized);
- int offset = 0;
- for (int i = 0; i < base64.size(); ++i) {
- int ch = base64.at(i);
+ qsizetype offset = 0;
+ for (qsizetype i = 0; i < inputSize; ++i) {
+ int ch = input[i];
int d;
- if (ch >= 'A' && ch <= 'Z')
+ if (ch >= 'A' && ch <= 'Z') {
d = ch - 'A';
- else if (ch >= 'a' && ch <= 'z')
+ } else if (ch >= 'a' && ch <= 'z') {
d = ch - 'a' + 26;
- else if (ch >= '0' && ch <= '9')
+ } else if (ch >= '0' && ch <= '9') {
d = ch - '0' + 52;
- else if (ch == '+' && (options & Base64UrlEncoding) == 0)
+ } else if (ch == '+' && (options & QByteArray::Base64UrlEncoding) == 0) {
d = 62;
- else if (ch == '-' && (options & Base64UrlEncoding) != 0)
+ } else if (ch == '-' && (options & QByteArray::Base64UrlEncoding) != 0) {
d = 62;
- else if (ch == '/' && (options & Base64UrlEncoding) == 0)
+ } else if (ch == '/' && (options & QByteArray::Base64UrlEncoding) == 0) {
d = 63;
- else if (ch == '_' && (options & Base64UrlEncoding) != 0)
+ } else if (ch == '_' && (options & QByteArray::Base64UrlEncoding) != 0) {
d = 63;
- else
- d = -1;
+ } else {
+ if (options & QByteArray::AbortOnBase64DecodingErrors) {
+ if (ch == '=') {
+ // can have 1 or 2 '=' signs, in both cases padding base64Size to
+ // a multiple of 4. Any other case is illegal.
+ if ((inputSize % 4) != 0) {
+ result.status = QByteArray::Base64DecodingStatus::IllegalInputLength;
+ return result;
+ } else if ((i == inputSize - 1) ||
+ (i == inputSize - 2 && input[++i] == '=')) {
+ d = -1; // ... and exit the loop, normally
+ } else {
+ result.status = QByteArray::Base64DecodingStatus::IllegalPadding;
+ return result;
+ }
+ } else {
+ result.status = QByteArray::Base64DecodingStatus::IllegalCharacter;
+ return result;
+ }
+ } else {
+ d = -1;
+ }
+ }
if (d != -1) {
buf = (buf << 6) | d;
nbits += 6;
if (nbits >= 8) {
nbits -= 8;
- tmp[offset++] = buf >> nbits;
+ Q_ASSERT(offset < i);
+ output[offset++] = buf >> nbits;
buf &= (1 << nbits) - 1;
}
}
}
- tmp.truncate(offset);
- return tmp;
+ result.decodedLength = offset;
+ return result;
+}
+} // anonymous namespace
+
+/*!
+ \fn QByteArray::FromBase64Result QByteArray::fromBase64Encoding(QByteArray &&base64, Base64Options options)
+ \fn QByteArray::FromBase64Result QByteArray::fromBase64Encoding(const QByteArray &base64, Base64Options options)
+ \since 5.15
+ \overload
+
+ Decodes the Base64 array \a base64, using the options
+ defined by \a options. If \a options contains \c{IgnoreBase64DecodingErrors}
+ (the default), the input is not checked for validity; invalid
+ characters in the input are skipped, enabling the decoding process to
+ continue with subsequent characters. If \a options contains
+ \c{AbortOnBase64DecodingErrors}, then decoding will stop at the first
+ invalid character.
+
+ For example:
+
+ \snippet code/src_corelib_tools_qbytearray.cpp 44ter
+
+ The algorithm used to decode Base64-encoded data is defined in \l{RFC 4648}.
+
+ Returns a QByteArrayFromBase64Result object, containing the decoded
+ data and a flag telling whether decoding was successful. If the
+ \c{AbortOnBase64DecodingErrors} option was passed and the input
+ data was invalid, it is unspecified what the decoded data contains.
+
+ \sa toBase64()
+*/
+QByteArray::FromBase64Result QByteArray::fromBase64Encoding(QByteArray &&base64, Base64Options options)
+{
+ // try to avoid a detach when calling data(), as it would over-allocate
+ // (we need less space when decoding than the one required by the full copy)
+ if (base64.isDetached()) {
+ const auto base64result = fromBase64_helper(base64.data(),
+ base64.size(),
+ base64.data(), // in-place
+ options);
+ base64.truncate(int(base64result.decodedLength));
+ return { std::move(base64), base64result.status };
+ }
+
+ return fromBase64Encoding(base64, options);
+}
+
+
+QByteArray::FromBase64Result QByteArray::fromBase64Encoding(const QByteArray &base64, Base64Options options)
+{
+ const auto base64Size = base64.size();
+ QByteArray result((base64Size * 3) / 4, Qt::Uninitialized);
+ const auto base64result = fromBase64_helper(base64.data(),
+ base64Size,
+ const_cast<char *>(result.constData()),
+ options);
+ result.truncate(int(base64result.decodedLength));
+ return { std::move(result), base64result.status };
+}
+
+/*!
+ \since 5.2
+
+ Returns a decoded copy of the Base64 array \a base64, using the options
+ defined by \a options. If \a options contains \c{IgnoreBase64DecodingErrors}
+ (the default), the input is not checked for validity; invalid
+ characters in the input are skipped, enabling the decoding process to
+ continue with subsequent characters. If \a options contains
+ \c{AbortOnBase64DecodingErrors}, then decoding will stop at the first
+ invalid character.
+
+ For example:
+
+ \snippet code/src_corelib_tools_qbytearray.cpp 44
+
+ The algorithm used to decode Base64-encoded data is defined in \l{RFC 4648}.
+
+ Returns the decoded data, or, if the \c{AbortOnBase64DecodingErrors}
+ option was passed and the input data was invalid, an empty byte array.
+
+ \note The fromBase64Encoding() function is recommended in new code.
+
+ \sa toBase64(), fromBase64Encoding()
+*/
+QByteArray QByteArray::fromBase64(const QByteArray &base64, Base64Options options)
+{
+ if (auto result = fromBase64Encoding(base64, options))
+ return std::move(result.decoded);
+ return QByteArray();
}
/*!
@@ -4838,4 +4953,86 @@ QByteArray QByteArray::toPercentEncoding(const QByteArray &exclude, const QByteA
\sa QStringLiteral
*/
+/*!
+ \class QByteArray::FromBase64Result
+ \inmodule QtCore
+ \ingroup tools
+ \since 5.15
+
+ \brief The QByteArray::FromBase64Result class holds the result of
+ a call to QByteArray::fromBase64Encoding.
+
+ Objects of this class can be used to check whether the conversion
+ was successful, and if so, retrieve the decoded QByteArray. The
+ conversion operators defined for QByteArray::FromBase64Result make
+ its usage straightforward:
+
+ \snippet code/src_corelib_tools_qbytearray.cpp 44ter
+
+ In alternative, it is possible to access the conversion status
+ and the decoded data directly:
+
+ \snippet code/src_corelib_tools_qbytearray.cpp 44quater
+
+ \sa QByteArray::fromBase64
+*/
+
+/*!
+ \variable QByteArray::FromBase64Result::decoded
+
+ Contains the decoded byte array.
+*/
+
+/*!
+ \variable QByteArray::FromBase64Result::decodingStatus
+
+ Contains whether the decoding was successful, expressed as a value
+ of type QByteArray::Base64DecodingStatus.
+*/
+
+/*!
+ \fn QByteArray::FromBase64Result::operator bool() const
+
+ Returns whether the decoding was successful. This is equivalent
+ to checking whether the \c{decodingStatus} member is equal to
+ QByteArray::Base64DecodingStatus::Ok.
+*/
+
+/*!
+ \fn QByteArray::FromBase64Result::operator QByteArray() const
+
+ Returns the decoded byte array.
+*/
+
+/*!
+ \fn bool operator==(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept
+ \relates QByteArray::FromBase64Result
+
+ Compares \a lhs and \a rhs for equality. \a lhs and \a rhs are equal
+ if and only if they contain the same decoding status and, if the
+ status is QByteArray::Base64DecodingStatus::Ok, if and only if
+ they contain the same decoded data.
+*/
+
+/*!
+ \fn bool operator!=(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept
+ \relates QByteArray::FromBase64Result
+
+ Compares \a lhs and \a rhs for inequality.
+*/
+
+/*!
+ \relates QByteArray::FromBase64Result
+
+ Returns the hash value for \a key, using
+ \a seed to seed the calculation.
+*/
+uint qHash(const QByteArray::FromBase64Result &key, uint seed) noexcept
+{
+ QtPrivate::QHashCombine hash;
+ seed = hash(seed, key.decoded);
+ seed = hash(seed, static_cast<int>(key.decodingStatus));
+ return seed;
+}
+
QT_END_NAMESPACE