| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "wtf/text/StringToNumber.h" | |
| 6 | |
| 7 #include "wtf/ASCIICType.h" | |
| 8 #include "wtf/dtoa.h" | |
| 9 #include "wtf/text/StringImpl.h" | |
| 10 #include <type_traits> | |
| 11 | |
| 12 namespace WTF { | |
| 13 | |
| 14 static bool isCharacterAllowedInBase(UChar c, int base) { | |
| 15 if (c > 0x7F) | |
| 16 return false; | |
| 17 if (isASCIIDigit(c)) | |
| 18 return c - '0' < base; | |
| 19 if (isASCIIAlpha(c)) { | |
| 20 if (base > 36) | |
| 21 base = 36; | |
| 22 return (c >= 'a' && c < 'a' + base - 10) || | |
| 23 (c >= 'A' && c < 'A' + base - 10); | |
| 24 } | |
| 25 return false; | |
| 26 } | |
| 27 | |
| 28 template <typename IntegralType, typename CharType> | |
| 29 static inline IntegralType toIntegralType(const CharType* data, | |
| 30 size_t length, | |
| 31 bool* ok, | |
| 32 int base) { | |
| 33 static_assert(std::is_integral<IntegralType>::value, | |
| 34 "IntegralType must be an integral type."); | |
| 35 static constexpr IntegralType integralMax = | |
| 36 std::numeric_limits<IntegralType>::max(); | |
| 37 static constexpr IntegralType integralMin = | |
| 38 std::numeric_limits<IntegralType>::min(); | |
| 39 static constexpr bool isSigned = std::numeric_limits<IntegralType>::is_signed; | |
| 40 | |
| 41 IntegralType value = 0; | |
| 42 bool isOk = false; | |
| 43 bool isNegative = false; | |
| 44 | |
| 45 if (!data) | |
| 46 goto bye; | |
| 47 | |
| 48 // skip leading whitespace | |
| 49 while (length && isSpaceOrNewline(*data)) { | |
| 50 --length; | |
| 51 ++data; | |
| 52 } | |
| 53 | |
| 54 if (isSigned && length && *data == '-') { | |
| 55 --length; | |
| 56 ++data; | |
| 57 isNegative = true; | |
| 58 } else if (length && *data == '+') { | |
| 59 --length; | |
| 60 ++data; | |
| 61 } | |
| 62 | |
| 63 if (!length || !isCharacterAllowedInBase(*data, base)) | |
| 64 goto bye; | |
| 65 | |
| 66 while (length && isCharacterAllowedInBase(*data, base)) { | |
| 67 --length; | |
| 68 IntegralType digitValue; | |
| 69 CharType c = *data; | |
| 70 if (isASCIIDigit(c)) | |
| 71 digitValue = c - '0'; | |
| 72 else if (c >= 'a') | |
| 73 digitValue = c - 'a' + 10; | |
| 74 else | |
| 75 digitValue = c - 'A' + 10; | |
| 76 | |
| 77 bool overflow; | |
| 78 if (isNegative) { | |
| 79 // Overflow condition: | |
| 80 // value * base - digitValue < integralMin | |
| 81 // <=> value < (integralMin + digitValue) / base | |
| 82 // We must be careful of rounding errors here, but the default rounding | |
| 83 // mode (round to zero) works well, so we can use this formula as-is. | |
| 84 overflow = value < (integralMin + digitValue) / base; | |
| 85 } else { | |
| 86 // Overflow condition: | |
| 87 // value * base + digitValue > integralMax | |
| 88 // <=> value > (integralMax + digitValue) / base | |
| 89 // Ditto regarding rounding errors. | |
| 90 overflow = value > (integralMax - digitValue) / base; | |
| 91 } | |
| 92 if (overflow) | |
| 93 goto bye; | |
| 94 | |
| 95 if (isNegative) | |
| 96 value = base * value - digitValue; | |
| 97 else | |
| 98 value = base * value + digitValue; | |
| 99 ++data; | |
| 100 } | |
| 101 | |
| 102 // skip trailing space | |
| 103 while (length && isSpaceOrNewline(*data)) { | |
| 104 --length; | |
| 105 ++data; | |
| 106 } | |
| 107 | |
| 108 if (!length) | |
| 109 isOk = true; | |
| 110 bye: | |
| 111 if (ok) | |
| 112 *ok = isOk; | |
| 113 return isOk ? value : 0; | |
| 114 } | |
| 115 | |
| 116 template <typename CharType> | |
| 117 static unsigned lengthOfCharactersAsInteger(const CharType* data, | |
| 118 size_t length) { | |
| 119 size_t i = 0; | |
| 120 | |
| 121 // Allow leading spaces. | |
| 122 for (; i != length; ++i) { | |
| 123 if (!isSpaceOrNewline(data[i])) | |
| 124 break; | |
| 125 } | |
| 126 | |
| 127 // Allow sign. | |
| 128 if (i != length && (data[i] == '+' || data[i] == '-')) | |
| 129 ++i; | |
| 130 | |
| 131 // Allow digits. | |
| 132 for (; i != length; ++i) { | |
| 133 if (!isASCIIDigit(data[i])) | |
| 134 break; | |
| 135 } | |
| 136 | |
| 137 return i; | |
| 138 } | |
| 139 | |
| 140 int charactersToIntStrict(const LChar* data, | |
| 141 size_t length, | |
| 142 bool* ok, | |
| 143 int base) { | |
| 144 return toIntegralType<int, LChar>(data, length, ok, base); | |
| 145 } | |
| 146 | |
| 147 int charactersToIntStrict(const UChar* data, | |
| 148 size_t length, | |
| 149 bool* ok, | |
| 150 int base) { | |
| 151 return toIntegralType<int, UChar>(data, length, ok, base); | |
| 152 } | |
| 153 | |
| 154 unsigned charactersToUIntStrict(const LChar* data, | |
| 155 size_t length, | |
| 156 bool* ok, | |
| 157 int base) { | |
| 158 return toIntegralType<unsigned, LChar>(data, length, ok, base); | |
| 159 } | |
| 160 | |
| 161 unsigned charactersToUIntStrict(const UChar* data, | |
| 162 size_t length, | |
| 163 bool* ok, | |
| 164 int base) { | |
| 165 return toIntegralType<unsigned, UChar>(data, length, ok, base); | |
| 166 } | |
| 167 | |
| 168 int64_t charactersToInt64Strict(const LChar* data, | |
| 169 size_t length, | |
| 170 bool* ok, | |
| 171 int base) { | |
| 172 return toIntegralType<int64_t, LChar>(data, length, ok, base); | |
| 173 } | |
| 174 | |
| 175 int64_t charactersToInt64Strict(const UChar* data, | |
| 176 size_t length, | |
| 177 bool* ok, | |
| 178 int base) { | |
| 179 return toIntegralType<int64_t, UChar>(data, length, ok, base); | |
| 180 } | |
| 181 | |
| 182 uint64_t charactersToUInt64Strict(const LChar* data, | |
| 183 size_t length, | |
| 184 bool* ok, | |
| 185 int base) { | |
| 186 return toIntegralType<uint64_t, LChar>(data, length, ok, base); | |
| 187 } | |
| 188 | |
| 189 uint64_t charactersToUInt64Strict(const UChar* data, | |
| 190 size_t length, | |
| 191 bool* ok, | |
| 192 int base) { | |
| 193 return toIntegralType<uint64_t, UChar>(data, length, ok, base); | |
| 194 } | |
| 195 | |
| 196 int charactersToInt(const LChar* data, size_t length, bool* ok) { | |
| 197 return toIntegralType<int, LChar>( | |
| 198 data, lengthOfCharactersAsInteger<LChar>(data, length), ok, 10); | |
| 199 } | |
| 200 | |
| 201 int charactersToInt(const UChar* data, size_t length, bool* ok) { | |
| 202 return toIntegralType<int, UChar>( | |
| 203 data, lengthOfCharactersAsInteger(data, length), ok, 10); | |
| 204 } | |
| 205 | |
| 206 unsigned charactersToUInt(const LChar* data, size_t length, bool* ok) { | |
| 207 return toIntegralType<unsigned, LChar>( | |
| 208 data, lengthOfCharactersAsInteger<LChar>(data, length), ok, 10); | |
| 209 } | |
| 210 | |
| 211 unsigned charactersToUInt(const UChar* data, size_t length, bool* ok) { | |
| 212 return toIntegralType<unsigned, UChar>( | |
| 213 data, lengthOfCharactersAsInteger<UChar>(data, length), ok, 10); | |
| 214 } | |
| 215 | |
| 216 int64_t charactersToInt64(const LChar* data, size_t length, bool* ok) { | |
| 217 return toIntegralType<int64_t, LChar>( | |
| 218 data, lengthOfCharactersAsInteger<LChar>(data, length), ok, 10); | |
| 219 } | |
| 220 | |
| 221 int64_t charactersToInt64(const UChar* data, size_t length, bool* ok) { | |
| 222 return toIntegralType<int64_t, UChar>( | |
| 223 data, lengthOfCharactersAsInteger<UChar>(data, length), ok, 10); | |
| 224 } | |
| 225 | |
| 226 uint64_t charactersToUInt64(const LChar* data, size_t length, bool* ok) { | |
| 227 return toIntegralType<uint64_t, LChar>( | |
| 228 data, lengthOfCharactersAsInteger<LChar>(data, length), ok, 10); | |
| 229 } | |
| 230 | |
| 231 uint64_t charactersToUInt64(const UChar* data, size_t length, bool* ok) { | |
| 232 return toIntegralType<uint64_t, UChar>( | |
| 233 data, lengthOfCharactersAsInteger<UChar>(data, length), ok, 10); | |
| 234 } | |
| 235 | |
| 236 enum TrailingJunkPolicy { DisallowTrailingJunk, AllowTrailingJunk }; | |
| 237 | |
| 238 template <typename CharType, TrailingJunkPolicy policy> | |
| 239 static inline double toDoubleType(const CharType* data, | |
| 240 size_t length, | |
| 241 bool* ok, | |
| 242 size_t& parsedLength) { | |
| 243 size_t leadingSpacesLength = 0; | |
| 244 while (leadingSpacesLength < length && | |
| 245 isASCIISpace(data[leadingSpacesLength])) | |
| 246 ++leadingSpacesLength; | |
| 247 | |
| 248 double number = parseDouble(data + leadingSpacesLength, | |
| 249 length - leadingSpacesLength, parsedLength); | |
| 250 if (!parsedLength) { | |
| 251 if (ok) | |
| 252 *ok = false; | |
| 253 return 0.0; | |
| 254 } | |
| 255 | |
| 256 parsedLength += leadingSpacesLength; | |
| 257 if (ok) | |
| 258 *ok = policy == AllowTrailingJunk || parsedLength == length; | |
| 259 return number; | |
| 260 } | |
| 261 | |
| 262 double charactersToDouble(const LChar* data, size_t length, bool* ok) { | |
| 263 size_t parsedLength; | |
| 264 return toDoubleType<LChar, DisallowTrailingJunk>(data, length, ok, | |
| 265 parsedLength); | |
| 266 } | |
| 267 | |
| 268 double charactersToDouble(const UChar* data, size_t length, bool* ok) { | |
| 269 size_t parsedLength; | |
| 270 return toDoubleType<UChar, DisallowTrailingJunk>(data, length, ok, | |
| 271 parsedLength); | |
| 272 } | |
| 273 | |
| 274 double charactersToDouble(const LChar* data, | |
| 275 size_t length, | |
| 276 size_t& parsedLength) { | |
| 277 return toDoubleType<LChar, AllowTrailingJunk>(data, length, nullptr, | |
| 278 parsedLength); | |
| 279 } | |
| 280 | |
| 281 double charactersToDouble(const UChar* data, | |
| 282 size_t length, | |
| 283 size_t& parsedLength) { | |
| 284 return toDoubleType<UChar, AllowTrailingJunk>(data, length, nullptr, | |
| 285 parsedLength); | |
| 286 } | |
| 287 | |
| 288 float charactersToFloat(const LChar* data, size_t length, bool* ok) { | |
| 289 // FIXME: This will return ok even when the string fits into a double but | |
| 290 // not a float. | |
| 291 size_t parsedLength; | |
| 292 return static_cast<float>(toDoubleType<LChar, DisallowTrailingJunk>( | |
| 293 data, length, ok, parsedLength)); | |
| 294 } | |
| 295 | |
| 296 float charactersToFloat(const UChar* data, size_t length, bool* ok) { | |
| 297 // FIXME: This will return ok even when the string fits into a double but | |
| 298 // not a float. | |
| 299 size_t parsedLength; | |
| 300 return static_cast<float>(toDoubleType<UChar, DisallowTrailingJunk>( | |
| 301 data, length, ok, parsedLength)); | |
| 302 } | |
| 303 | |
| 304 float charactersToFloat(const LChar* data, | |
| 305 size_t length, | |
| 306 size_t& parsedLength) { | |
| 307 // FIXME: This will return ok even when the string fits into a double but | |
| 308 // not a float. | |
| 309 return static_cast<float>( | |
| 310 toDoubleType<LChar, AllowTrailingJunk>(data, length, 0, parsedLength)); | |
| 311 } | |
| 312 | |
| 313 float charactersToFloat(const UChar* data, | |
| 314 size_t length, | |
| 315 size_t& parsedLength) { | |
| 316 // FIXME: This will return ok even when the string fits into a double but | |
| 317 // not a float. | |
| 318 return static_cast<float>( | |
| 319 toDoubleType<UChar, AllowTrailingJunk>(data, length, 0, parsedLength)); | |
| 320 } | |
| 321 | |
| 322 } // namespace WTF | |
| OLD | NEW |