diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2022-11-10 23:23:43 -0800 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2022-11-16 16:15:32 -0800 |
commit | 2ea3d2e924151843b8348871232eb88afb4cfe40 (patch) | |
tree | 7f174db7a33d3e4785f4d9c7b1b332335b8e14e8 /src | |
parent | cc98a7d01f19ea99f97b59dc66181c0d560e2cc8 (diff) |
QLocale: make qt_asciiToDouble() do case-insensitive comparisons
To "inf" and "nan".
Change-Id: Ieba79baf5ac34264a988fffd172676e1a776a0b1
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/text/qlocale_tools.cpp | 48 | ||||
-rw-r--r-- | src/corelib/text/qstring.cpp | 9 |
2 files changed, 30 insertions, 27 deletions
diff --git a/src/corelib/text/qlocale_tools.cpp b/src/corelib/text/qlocale_tools.cpp index 405f096420..5d439f2b26 100644 --- a/src/corelib/text/qlocale_tools.cpp +++ b/src/corelib/text/qlocale_tools.cpp @@ -250,31 +250,43 @@ void qt_doubleToAscii(double d, QLocaleData::DoubleForm form, int precision, QSimpleParsedNumber<double> qt_asciiToDouble(const char *num, qsizetype numLen, StrayCharacterMode strayCharMode) { - auto string_equals = [](const char *needle, const char *haystack, qsizetype haystackLen) { - qsizetype needleLen = strlen(needle); - return needleLen == haystackLen && memcmp(needle, haystack, haystackLen) == 0; - }; - if (numLen <= 0) return {}; // We have to catch NaN before because we need NaN as marker for "garbage" in the // libdouble-conversion case and, in contrast to libdouble-conversion or sscanf, we don't allow // "-nan" or "+nan" - if (string_equals("nan", num, numLen)) { - return { qt_qnan(), num + 3 }; - } else if (string_equals("+nan", num, numLen) || string_equals("-nan", num, numLen)) { - return {}; - } + if (char c = *num; numLen >= 3 + && (c == '-' || c == '+' || c == 'I' || c == 'i' || c == 'N' || c == 'n')) { + bool negative = (c == '-'); + bool hasSign = negative || (c == '+'); + qptrdiff offset = 0; + if (hasSign) { + offset = 1; + c = num[offset]; + } - // Infinity values are implementation defined in the sscanf case. In the libdouble-conversion - // case we need infinity as overflow marker. - if (string_equals("+inf", num, numLen)) { - return { qt_inf(), num + 4 }; - } else if (string_equals("inf", num, numLen)) { - return { qt_inf(), num + 3 }; - } else if (string_equals("-inf", num, numLen)) { - return { -qt_inf(), num + 4 }; + if (c > '9') { + auto lowered = [](char c) { + // this will mangle non-letters, but none can become a letter + return c | 0x20; + }; + + // Found a non-digit, so this MUST be either "inf", "+inf", "-inf" + // or "nan". Anything else is an invalid parse and we don't need to + // feed it to the converter below. + if (numLen != offset + 3) + return {}; + + c = lowered(c); + char c2 = lowered(num[offset + 1]); + char c3 = lowered(num[offset + 2]); + if (c == 'i' && c2 == 'n' && c3 == 'f') + return { negative ? -qt_inf() : qt_inf(), num + offset + 3 }; + else if (c == 'n' && c2 == 'a' && c3 == 'n' && !hasSign) + return { qt_qnan(), num + 3 }; + return {}; + } } double d = 0.0; diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index b3e147c0ba..2ac8306eb4 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -7490,15 +7490,6 @@ double QStringView::toDouble(bool *ok) const QStringView string = qt_trimmed(*this); QVarLengthArray<uchar> latin1(string.size()); qt_to_latin1(latin1.data(), string.utf16(), string.size()); - - // We need lowetcased "inf" and "nan". - // This mangles the string, but nothing can become a number or letter - // that isn't already a number or letter. - for (uchar &c : latin1) { - if (c >= 'A') - c |= 0x20; - } - auto r = qt_asciiToDouble(reinterpret_cast<const char *>(latin1.data()), string.size()); if (ok != nullptr) *ok = r.ok(); |