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 |