diff options
-rw-r--r-- | src/corelib/doc/snippets/code/src_corelib_tools_qbytearray.cpp | 13 | ||||
-rw-r--r-- | src/corelib/doc/src/external-resources.qdoc | 5 | ||||
-rw-r--r-- | src/corelib/tools/qbytearray.cpp | 95 | ||||
-rw-r--r-- | src/corelib/tools/qbytearray.h | 17 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp | 35 |
5 files changed, 151 insertions, 14 deletions
diff --git a/src/corelib/doc/snippets/code/src_corelib_tools_qbytearray.cpp b/src/corelib/doc/snippets/code/src_corelib_tools_qbytearray.cpp index c2a375f498..003fce580b 100644 --- a/src/corelib/doc/snippets/code/src_corelib_tools_qbytearray.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_tools_qbytearray.cpp @@ -352,6 +352,14 @@ QByteArray text("Qt is great!"); text.toBase64(); // returns "UXQgaXMgZ3JlYXQh" //! [39] +//! [39bis] +QByteArray text("<p>Hello?</p>"); +text.toBase64(QByteArray::Base64 | QByteArray::OmitTrailingEquals); // returns "PHA+SGVsbG8/PC9wPg" +text.toBase64(QByteArray::Base64); // returns "PHA+SGVsbG8/PC9wPg==" +text.toBase64(QByteArray::Base64Url); // returns "PHA-SGVsbG8_PC9wPg==" +text.toBase64(QByteArray::Base64Url | QByteArray::OmitTrailingEquals); // returns "PHA-SGVsbG8_PC9wPg" +//! [39bis] + //! [40] QByteArray ba; @@ -394,6 +402,11 @@ QByteArray text = QByteArray::fromBase64("UXQgaXMgZ3JlYXQh"); text.data(); // returns "Qt is great!" //! [44] +//! [44bis] +QByteArray::fromBase64("PHA+SGVsbG8/PC9wPg==", QByteArray::Base64Encoding); // returns "<p>Hello?</p>" +QByteArray::fromBase64("PHA-SGVsbG8_PC9wPg==", QByteArray::Base64UrlEncoding); // returns "<p>Hello?</p>" +//! [44bis] + //! [45] QByteArray text = QByteArray::fromHex("517420697320677265617421"); diff --git a/src/corelib/doc/src/external-resources.qdoc b/src/corelib/doc/src/external-resources.qdoc index 86df385d9e..d1c7eb5d1b 100644 --- a/src/corelib/doc/src/external-resources.qdoc +++ b/src/corelib/doc/src/external-resources.qdoc @@ -67,6 +67,11 @@ */ /*! + \externalpage http://www.ietf.org/rfc/rfc4648.txt + \title RFC 4648 +*/ + +/*! \externalpage http://www.iana.org/assignments/character-sets/character-sets.xml \title IANA character-sets encoding file */ diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp index 7ec7333054..975894a516 100644 --- a/src/corelib/tools/qbytearray.cpp +++ b/src/corelib/tools/qbytearray.cpp @@ -795,6 +795,27 @@ static inline char qToLower(char c) \sa QString, QBitArray */ +/*! + \enum QByteArray::Base64Option + \since 5.2 + + This enum contains the options available for encoding and decoding Base64. + Base64 is defined by \l{RFC 4648}, with the following options: + + \value Base64Encoding (default) The regular Base64 alphabet, called simply "base64" + \value Base64UrlEncoding An alternate alphabet, called "base64url", which replaces two + characters in the alphabet to be more friendly to URLs. + \value KeepTrailingEquals (default) Keeps the trailing padding equal signs at the end + of the encoded data, so the data is always a size multiple of + 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. +*/ + /*! \fn QByteArray::iterator QByteArray::begin() \internal @@ -3539,14 +3560,34 @@ float QByteArray::toFloat(bool *ok) const \snippet code/src_corelib_tools_qbytearray.cpp 39 - The algorithm used to encode Base64-encoded data is defined in \l{RFC 2045}. + The algorithm used to encode Base64-encoded data is defined in \l{RFC 4648}. \sa fromBase64() */ QByteArray QByteArray::toBase64() const { - const char alphabet[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef" - "ghijklmn" "opqrstuv" "wxyz0123" "456789+/"; + return toBase64(Base64Encoding); +} + +/*! + \since 5.2 + \overload + + Returns a copy of the byte array, encoded using the options \a options. + + \snippet code/src_corelib_tools_qbytearray.cpp 39bis + + The algorithm used to encode Base64-encoded data is defined in \l{RFC 4648}. + + \sa fromBase64() +*/ +QByteArray QByteArray::toBase64(Base64Options options) const +{ + const char alphabet_base64[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef" + "ghijklmn" "opqrstuv" "wxyz0123" "456789+/"; + const char alphabet_base64url[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef" + "ghijklmn" "opqrstuv" "wxyz0123" "456789-_"; + const char *const alphabet = options & Base64UrlEncoding ? alphabet_base64url : alphabet_base64; const char padchar = '='; int padlen = 0; @@ -3575,14 +3616,18 @@ QByteArray QByteArray::toBase64() const *out++ = alphabet[j]; *out++ = alphabet[k]; - if (padlen > 1) - *out++ = padchar; - else + if (padlen > 1) { + if ((options & OmitTrailingEquals) == 0) + *out++ = padchar; + } else { *out++ = alphabet[l]; - if (padlen > 0) - *out++ = padchar; - else + } + if (padlen > 0) { + if ((options & OmitTrailingEquals) == 0) + *out++ = padchar; + } else { *out++ = alphabet[m]; + } } tmp.truncate(out - tmp.data()); @@ -3941,12 +3986,34 @@ QByteArray &QByteArray::setRawData(const char *data, uint size) \snippet code/src_corelib_tools_qbytearray.cpp 44 - The algorithm used to decode Base64-encoded data is defined in \l{RFC 2045}. + The algorithm used to decode Base64-encoded data is defined in \l{RFC 4648}. \sa toBase64() */ QByteArray QByteArray::fromBase64(const QByteArray &base64) { + return fromBase64(base64, Base64Encoding); +} + +/*! + \since 5.2 + \overload + + 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 44bis + + The algorithm used to decode Base64-encoded data is defined in \l{RFC 4648}. + + \sa toBase64() +*/ +QByteArray QByteArray::fromBase64(const QByteArray &base64, Base64Options options) +{ unsigned int buf = 0; int nbits = 0; QByteArray tmp((base64.size() * 3) / 4, Qt::Uninitialized); @@ -3962,9 +4029,13 @@ QByteArray QByteArray::fromBase64(const QByteArray &base64) d = ch - 'a' + 26; else if (ch >= '0' && ch <= '9') d = ch - '0' + 52; - else if (ch == '+') + else if (ch == '+' && (options & Base64UrlEncoding) == 0) d = 62; - else if (ch == '/') + else if (ch == '-' && (options & Base64UrlEncoding) != 0) + d = 62; + else if (ch == '/' && (options & Base64UrlEncoding) == 0) + d = 63; + else if (ch == '_' && (options & Base64UrlEncoding) != 0) d = 63; else d = -1; diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h index 85d1f0ab90..ae8166db81 100644 --- a/src/corelib/tools/qbytearray.h +++ b/src/corelib/tools/qbytearray.h @@ -173,6 +173,15 @@ private: typedef QTypedArrayData<char> Data; public: + enum Base64Option { + Base64Encoding = 0, + Base64UrlEncoding = 1, + + KeepTrailingEquals = 0, + OmitTrailingEquals = 2 + }; + Q_DECLARE_FLAGS(Base64Options, Base64Option) + inline QByteArray(); QByteArray(const char *, int size = -1); QByteArray(int size, char c); @@ -317,7 +326,8 @@ public: qulonglong toULongLong(bool *ok = 0, int base = 10) const; float toFloat(bool *ok = 0) const; double toDouble(bool *ok = 0) const; - QByteArray toBase64() const; + QByteArray toBase64(Base64Options options) const; + QByteArray toBase64() const; // ### Qt6 merge with previous QByteArray toHex() const; QByteArray toPercentEncoding(const QByteArray &exclude = QByteArray(), const QByteArray &include = QByteArray(), @@ -339,7 +349,8 @@ public: static QByteArray number(qulonglong, int base = 10); static QByteArray number(double, char f = 'g', int prec = 6); static QByteArray fromRawData(const char *, int size); - static QByteArray fromBase64(const QByteArray &base64); + static QByteArray fromBase64(const QByteArray &base64, Base64Options options); + static QByteArray fromBase64(const QByteArray &base64); // ### Qt6 merge with previous static QByteArray fromHex(const QByteArray &hexEncoded); static QByteArray fromPercentEncoding(const QByteArray &pctEncoded, char percent = '%'); @@ -392,6 +403,8 @@ public: inline DataPtr &data_ptr() { return d; } }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QByteArray::Base64Options) + inline QByteArray::QByteArray(): d(Data::sharedNull()) { } inline QByteArray::~QByteArray() { if (!d->ref.deref()) Data::deallocate(d); } inline int QByteArray::size() const diff --git a/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp b/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp index 933807c525..d7cc92e6c0 100644 --- a/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp +++ b/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp @@ -614,6 +614,24 @@ void tst_QByteArray::base64() QByteArray arr64 = rawdata.toBase64(); QCOMPARE(arr64, base64); + + arr64 = rawdata.toBase64(QByteArray::Base64Encoding); + QCOMPARE(arr64, base64); + + QByteArray base64noequals = base64; + base64noequals.replace('=', ""); + arr64 = rawdata.toBase64(QByteArray::Base64Encoding | QByteArray::OmitTrailingEquals); + QCOMPARE(arr64, base64noequals); + + QByteArray base64url = base64; + base64url.replace('/', '_').replace('+', '-'); + arr64 = rawdata.toBase64(QByteArray::Base64UrlEncoding); + QCOMPARE(arr64, base64url); + + QByteArray base64urlnoequals = base64url; + base64urlnoequals.replace('=', ""); + arr64 = rawdata.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); + QCOMPARE(arr64, base64urlnoequals); } //different from the previous test as the input are invalid @@ -662,6 +680,23 @@ void tst_QByteArray::fromBase64() QByteArray arr = QByteArray::fromBase64(base64); QCOMPARE(arr, rawdata); + + arr = QByteArray::fromBase64(base64, QByteArray::Base64Encoding); + QCOMPARE(arr, rawdata); + + // try "base64url" encoding + QByteArray base64url = base64; + base64url.replace('/', '_').replace('+', '-'); + arr = QByteArray::fromBase64(base64url, QByteArray::Base64UrlEncoding); + QCOMPARE(arr, rawdata); + + if (base64 != base64url) { + // check that the invalid decodings fail + arr = QByteArray::fromBase64(base64, QByteArray::Base64UrlEncoding); + QVERIFY(arr != rawdata); + arr = QByteArray::fromBase64(base64url, QByteArray::Base64Encoding); + QVERIFY(arr != rawdata); + } } void tst_QByteArray::qvsnprintf() |