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
Andre Hartmann 2018-06-17 20:09:39 +02:00 committed by André Hartmann
parent 85472b6b02
commit f98ee77cd3
7 changed files with 102 additions and 14 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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)) {

View File

@ -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);

View File

@ -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)

View File

@ -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()