Implement support for '0b' prefix in toInt() etc

[ChangeLog][QtCore][QByteArray/QByteArrayView/QLatin1String/QString/QStringView]
The string-to-integer conversion functions (toInt() etc) now support
the 0b prefix for binary literals. That means that base = 0 will
recognize 0b to mean base = 2 and an explicit base = 2 argument will
make toInt() (etc) skip an optional 0b.

[ChangeLog][QtCore][Important Behavior Changes] Due to the
newly-introduced support for 0b (binary) prefixes in integer parsing,
some strings that were previously rejected as invalid now parse as
valid. E.g., Qt 6.3 with autodetected bases would have tried to parse
"0b1" as an octal value and fail, whereas 6.4 will parse it as the
binary literal and return 1.

Fixes: QTBUG-85002
Change-Id: Id4eff72d63619080e5afece4d059b6ffd52f28c8
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
bb10
Marc Mutz 2022-04-14 19:29:40 +02:00
parent 7a5d7e8440
commit e48b4d2b7c
4 changed files with 124 additions and 64 deletions

View File

@ -3564,8 +3564,9 @@ auto QtPrivate::toUnsignedInteger(QByteArrayView data, int base) -> ParsedNumber
If \a base is 0, the base is determined automatically using the following
rules: If the byte array begins with "0x", it is assumed to be hexadecimal
(base 16); otherwise, if it begins with "0", it is assumed to be octal (base
8); otherwise it is assumed to be decimal.
(base 16); otherwise, if it begins with "0b", it is assumed to be binary
(base 2); otherwise, if it begins with "0", it is assumed to be octal
(base 8); otherwise it is assumed to be decimal.
Returns 0 if the conversion fails.
@ -3576,6 +3577,8 @@ auto QtPrivate::toUnsignedInteger(QByteArrayView data, int base) -> ParsedNumber
regardless of the user's locale. Use QLocale to perform locale-aware
conversions between numbers and strings.
\note Support for the "0b" prefix was added in Qt 6.4.
\sa number()
*/
@ -3591,8 +3594,9 @@ qlonglong QByteArray::toLongLong(bool *ok, int base) const
If \a base is 0, the base is determined automatically using the following
rules: If the byte array begins with "0x", it is assumed to be hexadecimal
(base 16); otherwise, if it begins with "0", it is assumed to be octal (base
8); otherwise it is assumed to be decimal.
(base 16); otherwise, if it begins with "0b", it is assumed to be binary
(base 2); otherwise, if it begins with "0", it is assumed to be octal
(base 8); otherwise it is assumed to be decimal.
Returns 0 if the conversion fails.
@ -3603,6 +3607,8 @@ qlonglong QByteArray::toLongLong(bool *ok, int base) const
regardless of the user's locale. Use QLocale to perform locale-aware
conversions between numbers and strings.
\note Support for the "0b" prefix was added in Qt 6.4.
\sa number()
*/
@ -3618,8 +3624,9 @@ qulonglong QByteArray::toULongLong(bool *ok, int base) const
If \a base is 0, the base is determined automatically using the following
rules: If the byte array begins with "0x", it is assumed to be hexadecimal
(base 16); otherwise, if it begins with "0", it is assumed to be octal (base
8); otherwise it is assumed to be decimal.
(base 16); otherwise, if it begins with "0b", it is assumed to be binary
(base 2); otherwise, if it begins with "0", it is assumed to be octal
(base 8); otherwise it is assumed to be decimal.
Returns 0 if the conversion fails.
@ -3632,6 +3639,8 @@ qulonglong QByteArray::toULongLong(bool *ok, int base) const
regardless of the user's locale. Use QLocale to perform locale-aware
conversions between numbers and strings.
\note Support for the "0b" prefix was added in Qt 6.4.
\sa number()
*/
@ -3647,8 +3656,9 @@ int QByteArray::toInt(bool *ok, int base) const
If \a base is 0, the base is determined automatically using the following
rules: If the byte array begins with "0x", it is assumed to be hexadecimal
(base 16); otherwise, if it begins with "0", it is assumed to be octal (base
8); otherwise it is assumed to be decimal.
(base 16); otherwise, if it begins with "0b", it is assumed to be binary
(base 2); otherwise, if it begins with "0", it is assumed to be octal
(base 8); otherwise it is assumed to be decimal.
Returns 0 if the conversion fails.
@ -3659,6 +3669,8 @@ int QByteArray::toInt(bool *ok, int base) const
regardless of the user's locale. Use QLocale to perform locale-aware
conversions between numbers and strings.
\note Support for the "0b" prefix was added in Qt 6.4.
\sa number()
*/
@ -3676,8 +3688,9 @@ uint QByteArray::toUInt(bool *ok, int base) const
If \a base is 0, the base is determined automatically using the following
rules: If the byte array begins with "0x", it is assumed to be hexadecimal
(base 16); otherwise, if it begins with "0", it is assumed to be octal (base
8); otherwise it is assumed to be decimal.
(base 16); otherwise, if it begins with "0b", it is assumed to be binary
(base 2); otherwise, if it begins with "0", it is assumed to be octal
(base 8); otherwise it is assumed to be decimal.
Returns 0 if the conversion fails.
@ -3690,6 +3703,8 @@ uint QByteArray::toUInt(bool *ok, int base) const
regardless of the user's locale. Use QLocale to perform locale-aware
conversions between numbers and strings.
\note Support for the "0b" prefix was added in Qt 6.4.
\sa number()
*/
long QByteArray::toLong(bool *ok, int base) const
@ -3706,8 +3721,9 @@ long QByteArray::toLong(bool *ok, int base) const
If \a base is 0, the base is determined automatically using the following
rules: If the byte array begins with "0x", it is assumed to be hexadecimal
(base 16); otherwise, if it begins with "0", it is assumed to be octal (base
8); otherwise it is assumed to be decimal.
(base 16); otherwise, if it begins with "0b", it is assumed to be binary
(base 2); otherwise, if it begins with "0", it is assumed to be octal
(base 8); otherwise it is assumed to be decimal.
Returns 0 if the conversion fails.
@ -3718,6 +3734,8 @@ long QByteArray::toLong(bool *ok, int base) const
regardless of the user's locale. Use QLocale to perform locale-aware
conversions between numbers and strings.
\note Support for the "0b" prefix was added in Qt 6.4.
\sa number()
*/
ulong QByteArray::toULong(bool *ok, int base) const
@ -3731,9 +3749,10 @@ ulong QByteArray::toULong(bool *ok, int base) const
digits beyond 9; A is ten, B is eleven and so on.
If \a base is 0, the base is determined automatically using the following
rules: If the byte array begins with "0x", it is assumed to be hexadecimal;
otherwise, if it begins with "0", it is assumed to be octal; otherwise it is
assumed to be decimal.
rules: If the byte array begins with "0x", it is assumed to be hexadecimal
(base 16); otherwise, if it begins with "0b", it is assumed to be binary
(base 2); otherwise, if it begins with "0", it is assumed to be octal
(base 8); otherwise it is assumed to be decimal.
Returns 0 if the conversion fails.
@ -3744,6 +3763,8 @@ ulong QByteArray::toULong(bool *ok, int base) const
regardless of the user's locale. Use QLocale to perform locale-aware
conversions between numbers and strings.
\note Support for the "0b" prefix was added in Qt 6.4.
\sa number()
*/
@ -3758,9 +3779,10 @@ short QByteArray::toShort(bool *ok, int base) const
letters for digits beyond 9; A is ten, B is eleven and so on.
If \a base is 0, the base is determined automatically using the following
rules: If the byte array begins with "0x", it is assumed to be hexadecimal;
otherwise, if it begins with "0", it is assumed to be octal; otherwise it is
assumed to be decimal.
rules: If the byte array begins with "0x", it is assumed to be hexadecimal
(base 16); otherwise, if it begins with "0b", it is assumed to be binary
(base 2); otherwise, if it begins with "0", it is assumed to be octal
(base 8); otherwise it is assumed to be decimal.
Returns 0 if the conversion fails.
@ -3771,6 +3793,8 @@ short QByteArray::toShort(bool *ok, int base) const
regardless of the user's locale. Use QLocale to perform locale-aware
conversions between numbers and strings.
\note Support for the "0b" prefix was added in Qt 6.4.
\sa number()
*/

View File

@ -401,30 +401,42 @@ double qt_asciiToDouble(const char *num, qsizetype numLen, bool &ok, int &proces
return d;
}
/* Detect base if 0 and, if base is hex, skip over 0x prefix */
/* Detect base if 0 and, if base is hex or bin, skip over 0x/0b prefixes */
static auto scanPrefix(const char *p, const char *stop, int base)
{
if (p < stop && *p >= '0' && *p <= '9') {
if (*p == '0') {
const char *x = p + 1;
if (x < stop && (*x == 'x' || *x == 'X')) {
if (base == 0)
base = 16;
if (base == 16)
p += 2;
} else if (base == 0) {
base = 8;
}
} else if (base == 0) {
base = 10;
}
Q_ASSERT(base);
}
struct R
{
const char *next;
int base;
};
if (p < stop && *p >= '0' && *p <= '9') {
if (*p == '0') {
const char *x_or_b = p + 1;
if (x_or_b < stop) {
switch (*x_or_b) {
case 'b':
case 'B':
if (base == 0)
base = 2;
if (base == 2)
p += 2;
return R{p, base};
case 'x':
case 'X':
if (base == 0)
base = 16;
if (base == 16)
p += 2;
return R{p, base};
}
}
if (base == 0)
base = 8;
} else if (base == 0) {
base = 10;
}
Q_ASSERT(base);
}
return R{p, base};
}

View File

@ -7111,9 +7111,10 @@ QString QString::vasprintf(const char *cformat, va_list ap)
If \a ok is not \nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: if the string
begins with "0x", base 16 is used; otherwise, if the string begins with "0",
base 8 is used; otherwise, base 10 is used.
If \a base is 0, the C language convention is used: if the string begins
with "0x", base 16 is used; otherwise, if the string begins with "0b", base
2 is used; otherwise, if the string begins with "0", base 8 is used;
otherwise, base 10 is used.
The string conversion will always happen in the 'C' locale. For
locale-dependent conversion use QLocale::toLongLong()
@ -7124,6 +7125,8 @@ QString QString::vasprintf(const char *cformat, va_list ap)
This function ignores leading and trailing whitespace.
\note Support for the "0b" prefix was added in Qt 6.4.
\sa number(), toULongLong(), toInt(), QLocale::toLongLong()
*/
@ -7153,9 +7156,10 @@ qlonglong QString::toIntegral_helper(QStringView string, bool *ok, int base)
If \a ok is not \nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: if the string
begins with "0x", base 16 is used; otherwise, if the string begins with "0",
base 8 is used; otherwise, base 10 is used.
If \a base is 0, the C language convention is used: if the string begins
with "0x", base 16 is used; otherwise, if the string begins with "0b", base
2 is used; otherwise, if the string begins with "0", base 8 is used;
otherwise, base 10 is used.
The string conversion will always happen in the 'C' locale. For
locale-dependent conversion use QLocale::toULongLong()
@ -7166,6 +7170,8 @@ qlonglong QString::toIntegral_helper(QStringView string, bool *ok, int base)
This function ignores leading and trailing whitespace.
\note Support for the "0b" prefix was added in Qt 6.4.
\sa number(), toLongLong(), QLocale::toULongLong()
*/
@ -7196,9 +7202,10 @@ qulonglong QString::toIntegral_helper(QStringView string, bool *ok, uint base)
If \a ok is not \nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: if the string
begins with "0x", base 16 is used; otherwise, if the string begins with "0",
base 8 is used; otherwise, base 10 is used.
If \a base is 0, the C language convention is used: if the string begins
with "0x", base 16 is used; otherwise, if the string begins with "0b", base
2 is used; otherwise, if the string begins with "0", base 8 is used;
otherwise, base 10 is used.
The string conversion will always happen in the 'C' locale. For
locale-dependent conversion use QLocale::toLongLong()
@ -7209,6 +7216,8 @@ qulonglong QString::toIntegral_helper(QStringView string, bool *ok, uint base)
This function ignores leading and trailing whitespace.
\note Support for the "0b" prefix was added in Qt 6.4.
\sa number(), toULong(), toInt(), QLocale::toInt()
*/
@ -7222,9 +7231,10 @@ qulonglong QString::toIntegral_helper(QStringView string, bool *ok, uint base)
If \a ok is not \nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: if the string
begins with "0x", base 16 is used; otherwise, if the string begins with "0",
base 8 is used; otherwise, base 10 is used.
If \a base is 0, the C language convention is used: if the string begins
with "0x", base 16 is used; otherwise, if the string begins with "0b", base
2 is used; otherwise, if the string begins with "0", base 8 is used;
otherwise, base 10 is used.
The string conversion will always happen in the 'C' locale. For
locale-dependent conversion use QLocale::toULongLong()
@ -7235,6 +7245,8 @@ qulonglong QString::toIntegral_helper(QStringView string, bool *ok, uint base)
This function ignores leading and trailing whitespace.
\note Support for the "0b" prefix was added in Qt 6.4.
\sa number(), QLocale::toUInt()
*/
@ -7247,9 +7259,10 @@ qulonglong QString::toIntegral_helper(QStringView string, bool *ok, uint base)
If \a ok is not \nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: if the string
begins with "0x", base 16 is used; otherwise, if the string begins with "0",
base 8 is used; otherwise, base 10 is used.
If \a base is 0, the C language convention is used: if the string begins
with "0x", base 16 is used; otherwise, if the string begins with "0b", base
2 is used; otherwise, if the string begins with "0", base 8 is used;
otherwise, base 10 is used.
The string conversion will always happen in the 'C' locale. For
locale-dependent conversion use QLocale::toInt()
@ -7260,6 +7273,8 @@ qulonglong QString::toIntegral_helper(QStringView string, bool *ok, uint base)
This function ignores leading and trailing whitespace.
\note Support for the "0b" prefix was added in Qt 6.4.
\sa number(), toUInt(), toDouble(), QLocale::toInt()
*/
@ -7272,9 +7287,10 @@ qulonglong QString::toIntegral_helper(QStringView string, bool *ok, uint base)
If \a ok is not \nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: if the string
begins with "0x", base 16 is used; otherwise, if the string begins with "0",
base 8 is used; otherwise, base 10 is used.
If \a base is 0, the C language convention is used: if the string begins
with "0x", base 16 is used; otherwise, if the string begins with "0b", base
2 is used; otherwise, if the string begins with "0", base 8 is used;
otherwise, base 10 is used.
The string conversion will always happen in the 'C' locale. For
locale-dependent conversion use QLocale::toUInt()
@ -7285,6 +7301,8 @@ qulonglong QString::toIntegral_helper(QStringView string, bool *ok, uint base)
This function ignores leading and trailing whitespace.
\note Support for the "0b" prefix was added in Qt 6.4.
\sa number(), toInt(), QLocale::toUInt()
*/
@ -7298,9 +7316,10 @@ qulonglong QString::toIntegral_helper(QStringView string, bool *ok, uint base)
If \a ok is not \nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: if the string
begins with "0x", base 16 is used; otherwise, if the string begins with "0",
base 8 is used; otherwise, base 10 is used.
If \a base is 0, the C language convention is used: if the string begins
with "0x", base 16 is used; otherwise, if the string begins with "0b", base
2 is used; otherwise, if the string begins with "0", base 8 is used;
otherwise, base 10 is used.
The string conversion will always happen in the 'C' locale. For
locale-dependent conversion use QLocale::toShort()
@ -7311,6 +7330,8 @@ qulonglong QString::toIntegral_helper(QStringView string, bool *ok, uint base)
This function ignores leading and trailing whitespace.
\note Support for the "0b" prefix was added in Qt 6.4.
\sa number(), toUShort(), toInt(), QLocale::toShort()
*/
@ -7324,9 +7345,10 @@ qulonglong QString::toIntegral_helper(QStringView string, bool *ok, uint base)
If \a ok is not \nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: if the string
begins with "0x", base 16 is used; if the string begins with "0",
base 8 is used; otherwise, base 10 is used.
If \a base is 0, the C language convention is used: if the string begins
with "0x", base 16 is used; otherwise, if the string begins with "0b", base
2 is used; otherwise, if the string begins with "0", base 8 is used;
otherwise, base 10 is used.
The string conversion will always happen in the 'C' locale. For
locale-dependent conversion use QLocale::toUShort()
@ -7337,6 +7359,8 @@ qulonglong QString::toIntegral_helper(QStringView string, bool *ok, uint base)
This function ignores leading and trailing whitespace.
\note Support for the "0b" prefix was added in Qt 6.4.
\sa number(), toShort(), QLocale::toUShort()
*/
@ -10210,7 +10234,8 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size)
If \a base is 0, the base is determined automatically using the following
rules: if the Latin-1 string begins with "0x", the rest of it is read as
hexadecimal (base 16); otherwise, if it begins with "0", the rest of it is
hexadecimal (base 16); otherwise, if it begins with "0b", the rest of it is
read as binary (base 2); otherwise, if it begins with "0", the rest of it is
read as octal (base 8); otherwise it is read as decimal.
Returns 0 if the conversion fails.
@ -10225,6 +10250,8 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size)
This function ignores leading and trailing spacing characters.
//! [latin1-numeric-conversion-note]
\note Support for the "0b" prefix was added in Qt 6.4.
*/
/*!

View File

@ -2654,14 +2654,13 @@ void tst_QStringApiSymmetry::toNumberWithBases_data()
const char prefix[3];
int base;
} bases[] = {
{ "", 2 }, // should be {"0b", 2}, but Qt lacks support for the 0b prefix (QTBUG-85002)
{ "0b", 2 },
{ "0", 8 },
{ "", 10 },
{ "0x", 16 },
};
const auto check = [&](const char *input, qint64 n2, qint64 n8, qint64 n10, qint64 n16, bool result) {
for (const auto &e : bases) {
const QString data = QLatin1StringView(e.prefix) + QString::fromUtf8(input);
const auto row = [&](int base) {
@ -2678,8 +2677,6 @@ void tst_QStringApiSymmetry::toNumberWithBases_data()
<< data << base << select(e.base /* NOT base! */) << result;
};
row(e.base); // explicit base
if (e.base == 2)
continue; // Qt doesn't know 0b (yet, QTBUG-85002), so nothing to auto-detect
row(0); // automatically detected base
}
};