Base64: Implement the "base64url" encoding and the stripping of '='
The "base64url" encoding is defined in RFC 4648, which is the newest version of Base64. There are also a few situations where the ending '=' is not desired. Change-Id: I9bb9fa55817b57d125189e4e795d6fde97caea6d Reviewed-by: Richard J. Moore <rich@kde.org>bb10
parent
3154e1ccaa
commit
cc74159702
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -66,6 +66,11 @@
|
|||
\title RFC 2045
|
||||
*/
|
||||
|
||||
/*!
|
||||
\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
|
||||
|
|
|
|||
|
|
@ -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,11 +3986,33 @@ 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;
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Reference in New Issue