Move WebCore into Source
[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 <wtf/MathExtras.h>
29 #include <wtf/dtoa.h>
30 #include <wtf/text/AtomicString.h>
31
32 namespace WebCore {
33
34 String stripLeadingAndTrailingHTMLSpaces(const String& string)
35 {
36     const UChar* characters = string.characters();
37     unsigned length = string.length();
38
39     unsigned numLeadingSpaces;
40     for (numLeadingSpaces = 0; numLeadingSpaces < length; ++numLeadingSpaces) {
41         if (isNotHTMLSpace(characters[numLeadingSpaces]))
42             break;
43     }
44
45     if (numLeadingSpaces == length)
46         return string.isNull() ? string : emptyAtom.string();
47
48     unsigned numTrailingSpaces;
49     for (numTrailingSpaces = 0; numTrailingSpaces < length; ++numTrailingSpaces) {
50         if (isNotHTMLSpace(characters[length - numTrailingSpaces - 1]))
51             break;
52     }
53
54     ASSERT(numLeadingSpaces + numTrailingSpaces < length);
55
56     return string.substring(numLeadingSpaces, length - (numLeadingSpaces + numTrailingSpaces));
57 }
58
59 String serializeForNumberType(double number)
60 {
61     // According to HTML5, "the best representation of the number n as a floating
62     // point number" is a string produced by applying ToString() to n.
63     NumberToStringBuffer buffer;
64     unsigned length = numberToString(number, buffer);
65     return String(buffer, length);
66 }
67
68 bool parseToDoubleForNumberType(const String& string, double* result)
69 {
70     // See HTML5 2.4.4.3 `Real numbers.'
71
72     // String::toDouble() accepts leading + and whitespace characters, which are not valid here.
73     UChar firstCharacter = string[0];
74     if (firstCharacter != '-' && !isASCIIDigit(firstCharacter))
75         return false;
76
77     bool valid = false;
78     double value = string.toDouble(&valid);
79     if (!valid)
80         return false;
81
82     // NaN and infinity are considered valid by String::toDouble, but not valid here.
83     if (!isfinite(value))
84         return false;
85
86     // Numbers are considered finite IEEE 754 single-precision floating point values.
87     // See HTML5 2.4.4.3 `Real numbers.'
88     if (-FLT_MAX > value || value > FLT_MAX)
89         return false;
90
91     if (result) {
92         // The following expression converts -0 to +0.
93         *result = value ? value : 0;
94     }
95
96     return true;
97 }
98
99 bool parseToDoubleForNumberTypeWithDecimalPlaces(const String& string, double *result, unsigned *decimalPlaces)
100 {
101     if (decimalPlaces)
102         *decimalPlaces = 0;
103
104     if (!parseToDoubleForNumberType(string, result))
105         return false;
106
107     if (!decimalPlaces)
108         return true;
109
110     size_t dotIndex = string.find('.');
111     size_t eIndex = string.find('e');
112     if (eIndex == notFound) 
113         eIndex = string.find('E');
114
115     unsigned baseDecimalPlaces = 0;
116     if (dotIndex != notFound) {
117         if (eIndex == notFound)
118             baseDecimalPlaces = string.length() - dotIndex - 1;
119         else
120             baseDecimalPlaces = eIndex - dotIndex - 1;
121     }
122
123     int exponent = 0;
124     if (eIndex != notFound) {
125         unsigned cursor = eIndex + 1, cursorSaved;
126         int digit, exponentSign;
127         int32_t exponent32;
128         size_t length = string.length();
129
130         // Not using String.toInt() in order to perform the same computation as dtoa() does.
131         exponentSign = 0;
132         switch (digit = string[cursor]) {
133         case '-':
134             exponentSign = 1;
135         case '+':
136             digit = string[++cursor];
137         }
138         if (digit >= '0' && digit <= '9') {
139             while (cursor < length && digit == '0')
140                 digit = string[++cursor];
141             if (digit > '0' && digit <= '9') {
142                 exponent32 = digit - '0';
143                 cursorSaved = cursor;
144                 while (cursor < length && (digit = string[++cursor]) >= '0' && digit <= '9')
145                     exponent32 = (10 * exponent32) + digit - '0';
146                 if (cursor - cursorSaved > 8 || exponent32 > 19999)
147                     /* Avoid confusion from exponents
148                      * so large that e might overflow.
149                      */
150                     exponent = 19999; /* safe for 16 bit ints */
151                 else
152                     exponent = static_cast<int>(exponent32);
153                 if (exponentSign)
154                     exponent = -exponent;
155             } else
156                 exponent = 0;
157         }
158     }
159
160     int intDecimalPlaces = baseDecimalPlaces - exponent;
161     if (intDecimalPlaces < 0)
162         *decimalPlaces = 0;
163     else if (intDecimalPlaces > 19999)
164         *decimalPlaces = 19999;
165     else
166         *decimalPlaces = static_cast<unsigned>(intDecimalPlaces);
167
168     return true;
169 }
170
171 // http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-integers
172 bool parseHTMLInteger(const String& input, int& value)
173 {
174     // Step 1
175     // Step 2
176     const UChar* position = input.characters();
177     const UChar* end = position + input.length();
178
179     // Step 3
180     int sign = 1;
181
182     // Step 4
183     while (position < end) {
184         if (!isHTMLSpace(*position))
185             break;
186         ++position;
187     }
188
189     // Step 5
190     if (position == end)
191         return false;
192     ASSERT(position < end);
193
194     // Step 6
195     if (*position == '-') {
196         sign = -1;
197         ++position;
198     } else if (*position == '+')
199         ++position;
200     if (position == end)
201         return false;
202     ASSERT(position < end);
203
204     // Step 7
205     if (!isASCIIDigit(*position))
206         return false;
207
208     // Step 8
209     Vector<UChar, 16> digits;
210     while (position < end) {
211         if (!isASCIIDigit(*position))
212             break;
213         digits.append(*position++);
214     }
215
216     // Step 9
217     value = sign * charactersToIntStrict(digits.data(), digits.size());
218     return true;
219 }
220
221 }