QByteArray: toInt() and toDouble() ignore surrounding whitespaces
[ChangeLog][QtCore][QByteArray] QByteArray::toInt(), QByteArray::toDouble() and the other number conversion functions now ignore leading and trailing whitespaces, as their QString counterparts already did. For consistency reasons, the same behavior was added to qEnvironmentVariableIntValue() also. Task-number: QTBUG-66187 Change-Id: I8b5e478ea8577b811d969286ea9e269f539c1ea4 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>bb10
parent
85472b6b02
commit
f98ee77cd3
|
|
@ -3442,7 +3442,27 @@ int qEnvironmentVariableIntValue(const char *varName, bool *ok) Q_DECL_NOEXCEPT
|
|||
bool ok_ = true;
|
||||
const char *endptr;
|
||||
const qlonglong value = qstrtoll(buffer, &endptr, 0, &ok_);
|
||||
if (int(value) != value || *endptr != '\0') { // this is the check in QByteArray::toInt(), keep it in sync
|
||||
|
||||
// Keep the following checks in sync with QByteArray::toInt()
|
||||
if (!ok_) {
|
||||
if (ok)
|
||||
*ok = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*endptr != '\0') {
|
||||
while (ascii_isspace(*endptr))
|
||||
++endptr;
|
||||
}
|
||||
|
||||
if (*endptr != '\0') {
|
||||
// we stopped at a non-digit character after converting some digits
|
||||
if (ok)
|
||||
*ok = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (int(value) != value) {
|
||||
if (ok)
|
||||
*ok = false;
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -4135,7 +4135,8 @@ double QByteArray::toDouble(bool *ok) const
|
|||
QByteArray nulled = nulTerminated();
|
||||
bool nonNullOk = false;
|
||||
int processed = 0;
|
||||
double d = asciiToDouble(nulled.constData(), nulled.length(), nonNullOk, processed);
|
||||
double d = asciiToDouble(nulled.constData(), nulled.length(),
|
||||
nonNullOk, processed, WhitespacesAllowed);
|
||||
if (ok)
|
||||
*ok = nonNullOk;
|
||||
return d;
|
||||
|
|
|
|||
|
|
@ -3645,6 +3645,11 @@ qlonglong QLocaleData::bytearrayToLongLong(const char *num, int base, bool *ok)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (*endptr != '\0') {
|
||||
while (ascii_isspace(*endptr))
|
||||
++endptr;
|
||||
}
|
||||
|
||||
if (*endptr != '\0') {
|
||||
// we stopped at a non-digit character after converting some digits
|
||||
if (ok != 0)
|
||||
|
|
@ -3663,12 +3668,23 @@ qulonglong QLocaleData::bytearrayToUnsLongLong(const char *num, int base, bool *
|
|||
const char *endptr;
|
||||
qulonglong l = qstrtoull(num, &endptr, base, &_ok);
|
||||
|
||||
if (!_ok || *endptr != '\0') {
|
||||
if (!_ok) {
|
||||
if (ok != 0)
|
||||
*ok = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*endptr != '\0') {
|
||||
while (ascii_isspace(*endptr))
|
||||
++endptr;
|
||||
}
|
||||
|
||||
if (*endptr != '\0') {
|
||||
if (ok != nullptr)
|
||||
*ok = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ok != 0)
|
||||
*ok = true;
|
||||
return l;
|
||||
|
|
|
|||
|
|
@ -278,7 +278,7 @@ void doubleToAscii(double d, QLocaleData::DoubleForm form, int precision, char *
|
|||
}
|
||||
|
||||
double asciiToDouble(const char *num, int numLen, bool &ok, int &processed,
|
||||
TrailingJunkMode trailingJunkMode)
|
||||
StrayCharacterMode strayCharMode)
|
||||
{
|
||||
if (*num == '\0') {
|
||||
ok = false;
|
||||
|
|
@ -315,9 +315,13 @@ double asciiToDouble(const char *num, int numLen, bool &ok, int &processed,
|
|||
|
||||
double d = 0.0;
|
||||
#if !defined(QT_NO_DOUBLECONVERSION) && !defined(QT_BOOTSTRAPPED)
|
||||
int conv_flags = (trailingJunkMode == TrailingJunkAllowed) ?
|
||||
double_conversion::StringToDoubleConverter::ALLOW_TRAILING_JUNK :
|
||||
double_conversion::StringToDoubleConverter::NO_FLAGS;
|
||||
int conv_flags = double_conversion::StringToDoubleConverter::NO_FLAGS;
|
||||
if (strayCharMode == TrailingJunkAllowed) {
|
||||
conv_flags = double_conversion::StringToDoubleConverter::ALLOW_TRAILING_JUNK;
|
||||
} else if (strayCharMode == WhitespacesAllowed) {
|
||||
conv_flags = double_conversion::StringToDoubleConverter::ALLOW_LEADING_SPACES
|
||||
| double_conversion::StringToDoubleConverter::ALLOW_TRAILING_SPACES;
|
||||
}
|
||||
double_conversion::StringToDoubleConverter conv(conv_flags, 0.0, qt_snan(), 0, 0);
|
||||
d = conv.StringToDouble(num, numLen, &processed);
|
||||
|
||||
|
|
@ -336,7 +340,7 @@ double asciiToDouble(const char *num, int numLen, bool &ok, int &processed,
|
|||
if (qDoubleSscanf(num, QT_CLOCALE, "%lf%n", &d, &processed) < 1)
|
||||
processed = 0;
|
||||
|
||||
if ((trailingJunkMode == TrailingJunkProhibited && processed != numLen) || qIsNaN(d)) {
|
||||
if ((strayCharMode == TrailingJunkProhibited && processed != numLen) || qIsNaN(d)) {
|
||||
// Implementation defined nan symbol or garbage found. We don't accept it.
|
||||
processed = 0;
|
||||
ok = false;
|
||||
|
|
@ -361,7 +365,7 @@ double asciiToDouble(const char *num, int numLen, bool &ok, int &processed,
|
|||
#endif // !defined(QT_NO_DOUBLECONVERSION) && !defined(QT_BOOTSTRAPPED)
|
||||
|
||||
// Otherwise we would have gotten NaN or sorted it out above.
|
||||
Q_ASSERT(trailingJunkMode == TrailingJunkAllowed || processed == numLen);
|
||||
Q_ASSERT(strayCharMode == TrailingJunkAllowed || processed == numLen);
|
||||
|
||||
// Check if underflow has occurred.
|
||||
if (isZero(d)) {
|
||||
|
|
|
|||
|
|
@ -72,13 +72,14 @@
|
|||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
enum TrailingJunkMode {
|
||||
enum StrayCharacterMode {
|
||||
TrailingJunkProhibited,
|
||||
TrailingJunkAllowed
|
||||
TrailingJunkAllowed,
|
||||
WhitespacesAllowed
|
||||
};
|
||||
|
||||
double asciiToDouble(const char *num, int numLen, bool &ok, int &processed,
|
||||
TrailingJunkMode trailingJunkMode = TrailingJunkProhibited);
|
||||
StrayCharacterMode strayCharMode = TrailingJunkProhibited);
|
||||
void doubleToAscii(double d, QLocaleData::DoubleForm form, int precision, char *buf, int bufSize,
|
||||
bool &sign, int &length, int &decpt);
|
||||
|
||||
|
|
|
|||
|
|
@ -160,8 +160,10 @@ void tst_QGetPutEnv::intValue_data()
|
|||
|
||||
// some repetition from what is tested in getSetCheck()
|
||||
QTest::newRow("empty") << QByteArray() << 0 << false;
|
||||
QTest::newRow("spaces-heading") << QByteArray(" 1") << 1 << true;
|
||||
QTest::newRow("spaces-trailing") << QByteArray("1 ") << 0 << false;
|
||||
QTest::newRow("spaces-heading") << QByteArray(" \n\r\t1") << 1 << true;
|
||||
QTest::newRow("spaces-trailing") << QByteArray("1 \n\r\t") << 1 << true;
|
||||
QTest::newRow("junk-heading") << QByteArray("x1") << 0 << false;
|
||||
QTest::newRow("junk-trailing") << QByteArray("1x") << 0 << false;
|
||||
|
||||
#define ROW(x, i, b) \
|
||||
QTest::newRow(#x) << QByteArray(#x) << (i) << (b)
|
||||
|
|
|
|||
|
|
@ -106,6 +106,8 @@ private slots:
|
|||
void number();
|
||||
void toInt_data();
|
||||
void toInt();
|
||||
void toDouble_data();
|
||||
void toDouble();
|
||||
void blockSizeCalculations();
|
||||
|
||||
void resizeAfterFromRawData();
|
||||
|
|
@ -1317,6 +1319,11 @@ void tst_QByteArray::toInt_data()
|
|||
QTest::newRow("base 0-3") << QByteArray("010") << 0 << int(8) << true;
|
||||
QTest::newRow("empty") << QByteArray() << 0 << int(0) << false;
|
||||
|
||||
QTest::newRow("leading space") << QByteArray(" 100") << 10 << int(100) << true;
|
||||
QTest::newRow("trailing space") << QByteArray("100 ") << 10 << int(100) << true;
|
||||
QTest::newRow("leading junk") << QByteArray("x100") << 10 << int(0) << false;
|
||||
QTest::newRow("trailing junk") << QByteArray("100x") << 10 << int(0) << false;
|
||||
|
||||
// using fromRawData
|
||||
QTest::newRow("raw1") << QByteArray::fromRawData("1", 1) << 10 << 1 << true;
|
||||
QTest::newRow("raw2") << QByteArray::fromRawData("1foo", 1) << 10 << 1 << true;
|
||||
|
|
@ -1341,6 +1348,34 @@ void tst_QByteArray::toInt()
|
|||
QCOMPARE( number, expectednumber );
|
||||
}
|
||||
|
||||
void tst_QByteArray::toDouble_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("string");
|
||||
QTest::addColumn<double>("expectedNumber");
|
||||
QTest::addColumn<bool>("expectedOk");
|
||||
|
||||
QTest::newRow("decimal") << QByteArray("1.2345") << 1.2345 << true;
|
||||
QTest::newRow("exponent lowercase") << QByteArray("1.2345e+01") << 12.345 << true;
|
||||
QTest::newRow("exponent uppercase") << QByteArray("1.2345E+02") << 123.45 << true;
|
||||
QTest::newRow("leading spaces") << QByteArray(" \n\r\t1.2345") << 1.2345 << true;
|
||||
QTest::newRow("trailing spaces") << QByteArray("1.2345 \n\r\t") << 1.2345 << true;
|
||||
QTest::newRow("leading junk") << QByteArray("x1.2345") << 0.0 << false;
|
||||
QTest::newRow("trailing junk") << QByteArray("1.2345x") << 0.0 << false;
|
||||
}
|
||||
|
||||
void tst_QByteArray::toDouble()
|
||||
{
|
||||
QFETCH(QByteArray, string);
|
||||
QFETCH(double, expectedNumber);
|
||||
QFETCH(bool, expectedOk);
|
||||
|
||||
bool ok;
|
||||
const double number = string.toDouble(&ok);
|
||||
|
||||
QCOMPARE(ok, expectedOk);
|
||||
QCOMPARE(number, expectedNumber);
|
||||
}
|
||||
|
||||
void tst_QByteArray::toULong_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("str");
|
||||
|
|
@ -1354,6 +1389,11 @@ void tst_QByteArray::toULong_data()
|
|||
QTest::newRow("empty") << QByteArray("") << 10 << 0UL << false;
|
||||
QTest::newRow("ulong1") << QByteArray("3234567890") << 10 << 3234567890UL << true;
|
||||
QTest::newRow("ulong2") << QByteArray("fFFfFfFf") << 16 << 0xFFFFFFFFUL << true;
|
||||
|
||||
QTest::newRow("leading spaces") << QByteArray(" \n\r\t100") << 10 << 100UL << true;
|
||||
QTest::newRow("trailing spaces") << QByteArray("100 \n\r\t") << 10 << 100UL << true;
|
||||
QTest::newRow("leading junk") << QByteArray("x100") << 10 << 0UL << false;
|
||||
QTest::newRow("trailing junk") << QByteArray("100x") << 10 << 0UL << false;
|
||||
}
|
||||
|
||||
void tst_QByteArray::toULong()
|
||||
|
|
@ -1379,6 +1419,10 @@ void tst_QByteArray::toULongLong_data()
|
|||
QTest::newRow("default") << QByteArray() << 10 << (qulonglong)0 << false;
|
||||
QTest::newRow("out of base bound") << QByteArray("c") << 10 << (qulonglong)0 << false;
|
||||
|
||||
QTest::newRow("leading spaces") << QByteArray(" \n\r\t100") << 10 << qulonglong(100) << true;
|
||||
QTest::newRow("trailing spaces") << QByteArray("100 \n\r\t") << 10 << qulonglong(100) << true;
|
||||
QTest::newRow("leading junk") << QByteArray("x100") << 10 << qulonglong(0) << false;
|
||||
QTest::newRow("trailing junk") << QByteArray("100x") << 10 << qulonglong(0) << false;
|
||||
}
|
||||
|
||||
void tst_QByteArray::toULongLong()
|
||||
|
|
|
|||
Loading…
Reference in New Issue