Convert HTML parser to handle 8-bit resources without converting to UChar*
[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 "Decimal.h"
29 #include <limits>
30 #include <wtf/MathExtras.h>
31 #include <wtf/dtoa.h>
32 #include <wtf/text/AtomicString.h>
33 #include <wtf/text/StringBuilder.h>
34
35 namespace WebCore {
36
37 template <typename CharType>
38 static String stripLeadingAndTrailingHTMLSpaces(String string, CharType characters, unsigned length)
39 {
40     unsigned numLeadingSpaces = 0;
41     unsigned numTrailingSpaces = 0;
42
43     for (; numLeadingSpaces < length; ++numLeadingSpaces) {
44         if (isNotHTMLSpace(characters[numLeadingSpaces]))
45             break;
46     }
47
48     if (numLeadingSpaces == length)
49         return string.isNull() ? string : emptyAtom.string();
50
51     for (; numTrailingSpaces < length; ++numTrailingSpaces) {
52         if (isNotHTMLSpace(characters[length - numTrailingSpaces - 1]))
53             break;
54     }
55
56     ASSERT(numLeadingSpaces + numTrailingSpaces < length);
57
58     if (!(numLeadingSpaces | numTrailingSpaces))
59         return string;
60
61     return string.substring(numLeadingSpaces, length - (numLeadingSpaces + numTrailingSpaces));
62 }
63
64 String stripLeadingAndTrailingHTMLSpaces(const String& string)
65 {
66     unsigned length = string.length();
67
68     if (!length)
69         return string.isNull() ? string : emptyAtom.string();
70
71     if (string.is8Bit())
72         return stripLeadingAndTrailingHTMLSpaces(string, string.characters8(), length);
73
74     return stripLeadingAndTrailingHTMLSpaces(string, string.characters(), length);
75 }
76
77 String serializeForNumberType(const Decimal& number)
78 {
79     if (number.isZero()) {
80         // Decimal::toString appends exponent, e.g. "0e-18"
81         return number.isNegative() ? "-0" : "0";
82     }
83     return number.toString();
84 }
85
86 String serializeForNumberType(double number)
87 {
88     // According to HTML5, "the best representation of the number n as a floating
89     // point number" is a string produced by applying ToString() to n.
90     NumberToStringBuffer buffer;
91     return String(numberToString(number, buffer));
92 }
93
94 Decimal parseToDecimalForNumberType(const String& string, const Decimal& fallbackValue)
95 {
96     // See HTML5 2.5.4.3 `Real numbers.' and parseToDoubleForNumberType
97
98     // String::toDouble() accepts leading + and whitespace characters, which are not valid here.
99     const UChar firstCharacter = string[0];
100     if (firstCharacter != '-' && firstCharacter != '.' && !isASCIIDigit(firstCharacter))
101         return fallbackValue;
102
103     const Decimal value = Decimal::fromString(string);
104     if (!value.isFinite())
105         return fallbackValue;
106
107     // Numbers are considered finite IEEE 754 single-precision floating point values.
108     // See HTML5 2.5.4.3 `Real numbers.'
109     // FIXME: We should use numeric_limits<double>::max for number input type.
110     const Decimal floatMax = Decimal::fromDouble(std::numeric_limits<float>::max());
111     if (value < -floatMax || value > floatMax)
112         return fallbackValue;
113
114     // We return +0 for -0 case.
115     return value.isZero() ? Decimal(0) : value;
116 }
117
118 Decimal parseToDecimalForNumberType(const String& string)
119 {
120     return parseToDecimalForNumberType(string, Decimal::nan());
121 }
122
123 double parseToDoubleForNumberType(const String& string, double fallbackValue)
124 {
125     // See HTML5 2.5.4.3 `Real numbers.'
126
127     // String::toDouble() accepts leading + and whitespace characters, which are not valid here.
128     UChar firstCharacter = string[0];
129     if (firstCharacter != '-' && firstCharacter != '.' && !isASCIIDigit(firstCharacter))
130         return fallbackValue;
131
132     bool valid = false;
133     double value = string.toDouble(&valid);
134     if (!valid)
135         return fallbackValue;
136
137     // NaN and infinity are considered valid by String::toDouble, but not valid here.
138     if (!isfinite(value))
139         return fallbackValue;
140
141     // Numbers are considered finite IEEE 754 single-precision floating point values.
142     // See HTML5 2.5.4.3 `Real numbers.'
143     if (-std::numeric_limits<float>::max() > value || value > std::numeric_limits<float>::max())
144         return fallbackValue;
145
146     // The following expression converts -0 to +0.
147     return value ? value : 0;
148 }
149
150 double parseToDoubleForNumberType(const String& string)
151 {
152     return parseToDoubleForNumberType(string, std::numeric_limits<double>::quiet_NaN());
153 }
154
155 double parseToDoubleForNumberTypeWithDecimalPlaces(const String& string, unsigned *decimalPlaces, double fallbackValue)
156 {
157     if (decimalPlaces)
158         *decimalPlaces = 0;
159
160     double value = parseToDoubleForNumberType(string, std::numeric_limits<double>::quiet_NaN());
161     if (!isfinite(value))
162         return fallbackValue;
163
164     if (!decimalPlaces)
165         return value;
166
167     size_t dotIndex = string.find('.');
168     size_t eIndex = string.find('e');
169     if (eIndex == notFound) 
170         eIndex = string.find('E');
171
172     unsigned baseDecimalPlaces = 0;
173     if (dotIndex != notFound) {
174         if (eIndex == notFound)
175             baseDecimalPlaces = string.length() - dotIndex - 1;
176         else
177             baseDecimalPlaces = eIndex - dotIndex - 1;
178     }
179
180     int exponent = 0;
181     if (eIndex != notFound) {
182         unsigned cursor = eIndex + 1, cursorSaved;
183         int digit, exponentSign;
184         int32_t exponent32;
185         size_t length = string.length();
186
187         // Not using String.toInt() in order to perform the same computation as dtoa() does.
188         exponentSign = 0;
189         switch (digit = string[cursor]) {
190         case '-':
191             exponentSign = 1;
192         case '+':
193             digit = string[++cursor];
194         }
195         if (digit >= '0' && digit <= '9') {
196             while (cursor < length && digit == '0')
197                 digit = string[++cursor];
198             if (digit > '0' && digit <= '9') {
199                 exponent32 = digit - '0';
200                 cursorSaved = cursor;
201                 while (cursor < length && (digit = string[++cursor]) >= '0' && digit <= '9')
202                     exponent32 = (10 * exponent32) + digit - '0';
203                 if (cursor - cursorSaved > 8 || exponent32 > 19999)
204                     /* Avoid confusion from exponents
205                      * so large that e might overflow.
206                      */
207                     exponent = 19999; /* safe for 16 bit ints */
208                 else
209                     exponent = static_cast<int>(exponent32);
210                 if (exponentSign)
211                     exponent = -exponent;
212             } else
213                 exponent = 0;
214         }
215     }
216
217     int intDecimalPlaces = baseDecimalPlaces - exponent;
218     if (intDecimalPlaces < 0)
219         *decimalPlaces = 0;
220     else if (intDecimalPlaces > 19999)
221         *decimalPlaces = 19999;
222     else
223         *decimalPlaces = static_cast<unsigned>(intDecimalPlaces);
224
225     return value;
226 }
227
228 double parseToDoubleForNumberTypeWithDecimalPlaces(const String& string, unsigned *decimalPlaces)
229 {
230     return parseToDoubleForNumberTypeWithDecimalPlaces(string, decimalPlaces, std::numeric_limits<double>::quiet_NaN());
231 }
232
233 // http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-integers
234 bool parseHTMLInteger(const String& input, int& value)
235 {
236     // Step 1
237     // Step 2
238     const UChar* position = input.characters();
239     const UChar* end = position + input.length();
240
241     // Step 3
242     int sign = 1;
243
244     // Step 4
245     while (position < end) {
246         if (!isHTMLSpace(*position))
247             break;
248         ++position;
249     }
250
251     // Step 5
252     if (position == end)
253         return false;
254     ASSERT(position < end);
255
256     // Step 6
257     if (*position == '-') {
258         sign = -1;
259         ++position;
260     } else if (*position == '+')
261         ++position;
262     if (position == end)
263         return false;
264     ASSERT(position < end);
265
266     // Step 7
267     if (!isASCIIDigit(*position))
268         return false;
269
270     // Step 8
271     StringBuilder digits;
272     while (position < end) {
273         if (!isASCIIDigit(*position))
274             break;
275         digits.append(*position++);
276     }
277
278     // Step 9
279     bool ok;
280     value = sign * charactersToIntStrict(digits.characters(), digits.length(), &ok);
281     return ok;
282 }
283
284 // http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-non-negative-integers
285 bool parseHTMLNonNegativeInteger(const String& input, unsigned int& value)
286 {
287     // Step 1
288     // Step 2
289     const UChar* position = input.characters();
290     const UChar* end = position + input.length();
291
292     // Step 3
293     while (position < end) {
294         if (!isHTMLSpace(*position))
295             break;
296         ++position;
297     }
298
299     // Step 4
300     if (position == end)
301         return false;
302     ASSERT(position < end);
303
304     // Step 5
305     if (*position == '+')
306         ++position;
307
308     // Step 6
309     if (position == end)
310         return false;
311     ASSERT(position < end);
312
313     // Step 7
314     if (!isASCIIDigit(*position))
315         return false;
316
317     // Step 8
318     StringBuilder digits;
319     while (position < end) {
320         if (!isASCIIDigit(*position))
321             break;
322         digits.append(*position++);
323     }
324
325     // Step 9
326     bool ok;
327     value = charactersToUIntStrict(digits.characters(), digits.length(), &ok);
328     return ok;
329 }
330
331 }