Streamline strtod and fix some related problems
[WebKit-https.git] / Source / WebCore / html / parser / HTMLParserIdioms.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "config.h"
26 #include "HTMLParserIdioms.h"
27
28 #include <limits>
29 #include <wtf/MathExtras.h>
30 #include <wtf/dtoa.h>
31 #include <wtf/text/AtomicString.h>
32 #include <wtf/text/StringBuilder.h>
33
34 namespace WebCore {
35
36 String stripLeadingAndTrailingHTMLSpaces(const String& string)
37 {
38     const UChar* characters = string.characters();
39     unsigned length = string.length();
40
41     unsigned numLeadingSpaces;
42     for (numLeadingSpaces = 0; numLeadingSpaces < length; ++numLeadingSpaces) {
43         if (isNotHTMLSpace(characters[numLeadingSpaces]))
44             break;
45     }
46
47     if (numLeadingSpaces == length)
48         return string.isNull() ? string : emptyAtom.string();
49
50     unsigned numTrailingSpaces;
51     for (numTrailingSpaces = 0; numTrailingSpaces < length; ++numTrailingSpaces) {
52         if (isNotHTMLSpace(characters[length - numTrailingSpaces - 1]))
53             break;
54     }
55
56     ASSERT(numLeadingSpaces + numTrailingSpaces < length);
57
58     return string.substring(numLeadingSpaces, length - (numLeadingSpaces + numTrailingSpaces));
59 }
60
61 String serializeForNumberType(double number)
62 {
63     // According to HTML5, "the best representation of the number n as a floating
64     // point number" is a string produced by applying ToString() to n.
65     NumberToStringBuffer buffer;
66     return String(numberToString(number, buffer));
67 }
68
69 bool parseToDoubleForNumberType(const String& string, double* result)
70 {
71     // See HTML5 2.5.4.3 `Real numbers.'
72
73     // String::toDouble() accepts leading + and whitespace characters, which are not valid here.
74     UChar firstCharacter = string[0];
75     if (firstCharacter != '-' && firstCharacter != '.' && !isASCIIDigit(firstCharacter))
76         return false;
77
78     bool valid = false;
79     double value = string.toDouble(&valid);
80     if (!valid)
81         return false;
82     ASSERT(isfinite(value));
83
84     // Numbers are considered finite IEEE 754 single-precision floating point values.
85     // See HTML5 2.5.4.3 `Real numbers.'
86     if (-std::numeric_limits<float>::max() > value || value > std::numeric_limits<float>::max())
87         return false;
88
89     if (result) {
90         // The following expression converts -0 to +0.
91         *result = value ? value : 0;
92     }
93
94     return true;
95 }
96
97 bool parseToDoubleForNumberTypeWithDecimalPlaces(const String& string, double *result, unsigned *decimalPlaces)
98 {
99     if (decimalPlaces)
100         *decimalPlaces = 0;
101
102     if (!parseToDoubleForNumberType(string, result))
103         return false;
104
105     if (!decimalPlaces)
106         return true;
107
108     size_t dotIndex = string.find('.');
109     size_t eIndex = string.find('e');
110     if (eIndex == notFound) 
111         eIndex = string.find('E');
112
113     unsigned baseDecimalPlaces = 0;
114     if (dotIndex != notFound) {
115         if (eIndex == notFound)
116             baseDecimalPlaces = string.length() - dotIndex - 1;
117         else
118             baseDecimalPlaces = eIndex - dotIndex - 1;
119     }
120
121     int exponent = 0;
122     if (eIndex != notFound) {
123         unsigned cursor = eIndex + 1, cursorSaved;
124         int digit, exponentSign;
125         int32_t exponent32;
126         size_t length = string.length();
127
128         // Not using String.toInt() in order to perform the same computation as dtoa() does.
129         exponentSign = 0;
130         switch (digit = string[cursor]) {
131         case '-':
132             exponentSign = 1;
133         case '+':
134             digit = string[++cursor];
135         }
136         if (digit >= '0' && digit <= '9') {
137             while (cursor < length && digit == '0')
138                 digit = string[++cursor];
139             if (digit > '0' && digit <= '9') {
140                 exponent32 = digit - '0';
141                 cursorSaved = cursor;
142                 while (cursor < length && (digit = string[++cursor]) >= '0' && digit <= '9')
143                     exponent32 = (10 * exponent32) + digit - '0';
144                 if (cursor - cursorSaved > 8 || exponent32 > 19999)
145                     /* Avoid confusion from exponents
146                      * so large that e might overflow.
147                      */
148                     exponent = 19999; /* safe for 16 bit ints */
149                 else
150                     exponent = static_cast<int>(exponent32);
151                 if (exponentSign)
152                     exponent = -exponent;
153             } else
154                 exponent = 0;
155         }
156     }
157
158     int intDecimalPlaces = baseDecimalPlaces - exponent;
159     if (intDecimalPlaces < 0)
160         *decimalPlaces = 0;
161     else if (intDecimalPlaces > 19999)
162         *decimalPlaces = 19999;
163     else
164         *decimalPlaces = static_cast<unsigned>(intDecimalPlaces);
165
166     return true;
167 }
168
169 // http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-integers
170 bool parseHTMLInteger(const String& input, int& value)
171 {
172     // Step 1
173     // Step 2
174     const UChar* position = input.characters();
175     const UChar* end = position + input.length();
176
177     // Step 3
178     int sign = 1;
179
180     // Step 4
181     while (position < end) {
182         if (!isHTMLSpace(*position))
183             break;
184         ++position;
185     }
186
187     // Step 5
188     if (position == end)
189         return false;
190     ASSERT(position < end);
191
192     // Step 6
193     if (*position == '-') {
194         sign = -1;
195         ++position;
196     } else if (*position == '+')
197         ++position;
198     if (position == end)
199         return false;
200     ASSERT(position < end);
201
202     // Step 7
203     if (!isASCIIDigit(*position))
204         return false;
205
206     // Step 8
207     StringBuilder digits;
208     while (position < end) {
209         if (!isASCIIDigit(*position))
210             break;
211         digits.append(*position++);
212     }
213
214     // Step 9
215     bool ok;
216     value = sign * charactersToIntStrict(digits.characters(), digits.length(), &ok);
217     return ok;
218 }
219
220 // http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-non-negative-integers
221 bool parseHTMLNonNegativeInteger(const String& input, unsigned int& value)
222 {
223     // Step 1
224     // Step 2
225     const UChar* position = input.characters();
226     const UChar* end = position + input.length();
227
228     // Step 3
229     while (position < end) {
230         if (!isHTMLSpace(*position))
231             break;
232         ++position;
233     }
234
235     // Step 4
236     if (position == end)
237         return false;
238     ASSERT(position < end);
239
240     // Step 5
241     if (*position == '+')
242         ++position;
243
244     // Step 6
245     if (position == end)
246         return false;
247     ASSERT(position < end);
248
249     // Step 7
250     if (!isASCIIDigit(*position))
251         return false;
252
253     // Step 8
254     StringBuilder digits;
255     while (position < end) {
256         if (!isASCIIDigit(*position))
257             break;
258         digits.append(*position++);
259     }
260
261     // Step 9
262     bool ok;
263     value = charactersToUIntStrict(digits.characters(), digits.length(), &ok);
264     return ok;
265 }
266
267 }