OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 namespace blink { | 5 namespace blink { |
6 namespace protocol { | 6 namespace protocol { |
7 | 7 |
8 namespace { | 8 namespace { |
9 | 9 |
10 const int stackLimit = 1000; | 10 const int stackLimit = 1000; |
(...skipping 10 matching lines...) Expand all Loading... |
21 NullToken, | 21 NullToken, |
22 ListSeparator, | 22 ListSeparator, |
23 ObjectPairSeparator, | 23 ObjectPairSeparator, |
24 InvalidToken, | 24 InvalidToken, |
25 }; | 25 }; |
26 | 26 |
27 const char* const nullString = "null"; | 27 const char* const nullString = "null"; |
28 const char* const trueString = "true"; | 28 const char* const trueString = "true"; |
29 const char* const falseString = "false"; | 29 const char* const falseString = "false"; |
30 | 30 |
31 bool parseConstToken(const UChar* start, const UChar* end, const UChar** tokenEn
d, const char* token) | 31 template<typename Char> |
| 32 bool parseConstToken(const Char* start, const Char* end, const Char** tokenEnd,
const char* token) |
32 { | 33 { |
33 while (start < end && *token != '\0' && *start++ == *token++) { } | 34 while (start < end && *token != '\0' && *start++ == *token++) { } |
34 if (*token != '\0') | 35 if (*token != '\0') |
35 return false; | 36 return false; |
36 *tokenEnd = start; | 37 *tokenEnd = start; |
37 return true; | 38 return true; |
38 } | 39 } |
39 | 40 |
40 bool readInt(const UChar* start, const UChar* end, const UChar** tokenEnd, bool
canHaveLeadingZeros) | 41 template<typename Char> |
| 42 bool readInt(const Char* start, const Char* end, const Char** tokenEnd, bool can
HaveLeadingZeros) |
41 { | 43 { |
42 if (start == end) | 44 if (start == end) |
43 return false; | 45 return false; |
44 bool haveLeadingZero = '0' == *start; | 46 bool haveLeadingZero = '0' == *start; |
45 int length = 0; | 47 int length = 0; |
46 while (start < end && '0' <= *start && *start <= '9') { | 48 while (start < end && '0' <= *start && *start <= '9') { |
47 ++start; | 49 ++start; |
48 ++length; | 50 ++length; |
49 } | 51 } |
50 if (!length) | 52 if (!length) |
51 return false; | 53 return false; |
52 if (!canHaveLeadingZeros && length > 1 && haveLeadingZero) | 54 if (!canHaveLeadingZeros && length > 1 && haveLeadingZero) |
53 return false; | 55 return false; |
54 *tokenEnd = start; | 56 *tokenEnd = start; |
55 return true; | 57 return true; |
56 } | 58 } |
57 | 59 |
58 bool parseNumberToken(const UChar* start, const UChar* end, const UChar** tokenE
nd) | 60 template<typename Char> |
| 61 bool parseNumberToken(const Char* start, const Char* end, const Char** tokenEnd) |
59 { | 62 { |
60 // We just grab the number here. We validate the size in DecodeNumber. | 63 // We just grab the number here. We validate the size in DecodeNumber. |
61 // According to RFC4627, a valid number is: [minus] int [frac] [exp] | 64 // According to RFC4627, a valid number is: [minus] int [frac] [exp] |
62 if (start == end) | 65 if (start == end) |
63 return false; | 66 return false; |
64 UChar c = *start; | 67 Char c = *start; |
65 if ('-' == c) | 68 if ('-' == c) |
66 ++start; | 69 ++start; |
67 | 70 |
68 if (!readInt(start, end, &start, false)) | 71 if (!readInt(start, end, &start, false)) |
69 return false; | 72 return false; |
70 if (start == end) { | 73 if (start == end) { |
71 *tokenEnd = start; | 74 *tokenEnd = start; |
72 return true; | 75 return true; |
73 } | 76 } |
74 | 77 |
(...skipping 22 matching lines...) Expand all Loading... |
97 return false; | 100 return false; |
98 } | 101 } |
99 if (!readInt(start, end, &start, true)) | 102 if (!readInt(start, end, &start, true)) |
100 return false; | 103 return false; |
101 } | 104 } |
102 | 105 |
103 *tokenEnd = start; | 106 *tokenEnd = start; |
104 return true; | 107 return true; |
105 } | 108 } |
106 | 109 |
107 bool readHexDigits(const UChar* start, const UChar* end, const UChar** tokenEnd,
int digits) | 110 template<typename Char> |
| 111 bool readHexDigits(const Char* start, const Char* end, const Char** tokenEnd, in
t digits) |
108 { | 112 { |
109 if (end - start < digits) | 113 if (end - start < digits) |
110 return false; | 114 return false; |
111 for (int i = 0; i < digits; ++i) { | 115 for (int i = 0; i < digits; ++i) { |
112 UChar c = *start++; | 116 Char c = *start++; |
113 if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c
<= 'F'))) | 117 if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c
<= 'F'))) |
114 return false; | 118 return false; |
115 } | 119 } |
116 *tokenEnd = start; | 120 *tokenEnd = start; |
117 return true; | 121 return true; |
118 } | 122 } |
119 | 123 |
120 bool parseStringToken(const UChar* start, const UChar* end, const UChar** tokenE
nd) | 124 template<typename Char> |
| 125 bool parseStringToken(const Char* start, const Char* end, const Char** tokenEnd) |
121 { | 126 { |
122 while (start < end) { | 127 while (start < end) { |
123 UChar c = *start++; | 128 Char c = *start++; |
124 if ('\\' == c) { | 129 if ('\\' == c) { |
125 c = *start++; | 130 c = *start++; |
126 // Make sure the escaped char is valid. | 131 // Make sure the escaped char is valid. |
127 switch (c) { | 132 switch (c) { |
128 case 'x': | 133 case 'x': |
129 if (!readHexDigits(start, end, &start, 2)) | 134 if (!readHexDigits(start, end, &start, 2)) |
130 return false; | 135 return false; |
131 break; | 136 break; |
132 case 'u': | 137 case 'u': |
133 if (!readHexDigits(start, end, &start, 4)) | 138 if (!readHexDigits(start, end, &start, 4)) |
(...skipping 13 matching lines...) Expand all Loading... |
147 return false; | 152 return false; |
148 } | 153 } |
149 } else if ('"' == c) { | 154 } else if ('"' == c) { |
150 *tokenEnd = start; | 155 *tokenEnd = start; |
151 return true; | 156 return true; |
152 } | 157 } |
153 } | 158 } |
154 return false; | 159 return false; |
155 } | 160 } |
156 | 161 |
157 bool skipComment(const UChar* start, const UChar* end, const UChar** commentEnd) | 162 template<typename Char> |
| 163 bool skipComment(const Char* start, const Char* end, const Char** commentEnd) |
158 { | 164 { |
159 if (start == end) | 165 if (start == end) |
160 return false; | 166 return false; |
161 | 167 |
162 if (*start != '/' || start + 1 >= end) | 168 if (*start != '/' || start + 1 >= end) |
163 return false; | 169 return false; |
164 ++start; | 170 ++start; |
165 | 171 |
166 if (*start == '/') { | 172 if (*start == '/') { |
167 // Single line comment, read to newline. | 173 // Single line comment, read to newline. |
168 for (++start; start < end; ++start) { | 174 for (++start; start < end; ++start) { |
169 if (*start == '\n' || *start == '\r') { | 175 if (*start == '\n' || *start == '\r') { |
170 *commentEnd = start + 1; | 176 *commentEnd = start + 1; |
171 return true; | 177 return true; |
172 } | 178 } |
173 } | 179 } |
174 *commentEnd = end; | 180 *commentEnd = end; |
175 // Comment reaches end-of-input, which is fine. | 181 // Comment reaches end-of-input, which is fine. |
176 return true; | 182 return true; |
177 } | 183 } |
178 | 184 |
179 if (*start == '*') { | 185 if (*start == '*') { |
180 UChar previous = '\0'; | 186 Char previous = '\0'; |
181 // Block comment, read until end marker. | 187 // Block comment, read until end marker. |
182 for (++start; start < end; previous = *start++) { | 188 for (++start; start < end; previous = *start++) { |
183 if (previous == '*' && *start == '/') { | 189 if (previous == '*' && *start == '/') { |
184 *commentEnd = start + 1; | 190 *commentEnd = start + 1; |
185 return true; | 191 return true; |
186 } | 192 } |
187 } | 193 } |
188 // Block comment must close before end-of-input. | 194 // Block comment must close before end-of-input. |
189 return false; | 195 return false; |
190 } | 196 } |
191 | 197 |
192 return false; | 198 return false; |
193 } | 199 } |
194 | 200 |
195 void skipWhitespaceAndComments(const UChar* start, const UChar* end, const UChar
** whitespaceEnd) | 201 template<typename Char> |
| 202 void skipWhitespaceAndComments(const Char* start, const Char* end, const Char**
whitespaceEnd) |
196 { | 203 { |
197 while (start < end) { | 204 while (start < end) { |
198 if (String16::isSpaceOrNewLine(*start)) { | 205 if (String16::isSpaceOrNewLine(*start)) { |
199 ++start; | 206 ++start; |
200 } else if (*start == '/') { | 207 } else if (*start == '/') { |
201 const UChar* commentEnd; | 208 const Char* commentEnd; |
202 if (!skipComment(start, end, &commentEnd)) | 209 if (!skipComment(start, end, &commentEnd)) |
203 break; | 210 break; |
204 start = commentEnd; | 211 start = commentEnd; |
205 } else { | 212 } else { |
206 break; | 213 break; |
207 } | 214 } |
208 } | 215 } |
209 *whitespaceEnd = start; | 216 *whitespaceEnd = start; |
210 } | 217 } |
211 | 218 |
212 Token parseToken(const UChar* start, const UChar* end, const UChar** tokenStart,
const UChar** tokenEnd) | 219 template<typename Char> |
| 220 Token parseToken(const Char* start, const Char* end, const Char** tokenStart, co
nst Char** tokenEnd) |
213 { | 221 { |
214 skipWhitespaceAndComments(start, end, tokenStart); | 222 skipWhitespaceAndComments(start, end, tokenStart); |
215 start = *tokenStart; | 223 start = *tokenStart; |
216 | 224 |
217 if (start == end) | 225 if (start == end) |
218 return InvalidToken; | 226 return InvalidToken; |
219 | 227 |
220 switch (*start) { | 228 switch (*start) { |
221 case 'n': | 229 case 'n': |
222 if (parseConstToken(start, end, tokenEnd, nullString)) | 230 if (parseConstToken(start, end, tokenEnd, nullString)) |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
263 return Number; | 271 return Number; |
264 break; | 272 break; |
265 case '"': | 273 case '"': |
266 if (parseStringToken(start + 1, end, tokenEnd)) | 274 if (parseStringToken(start + 1, end, tokenEnd)) |
267 return StringLiteral; | 275 return StringLiteral; |
268 break; | 276 break; |
269 } | 277 } |
270 return InvalidToken; | 278 return InvalidToken; |
271 } | 279 } |
272 | 280 |
273 inline int hexToInt(UChar c) | 281 template<typename Char> |
| 282 int hexToInt(Char c) |
274 { | 283 { |
275 if ('0' <= c && c <= '9') | 284 if ('0' <= c && c <= '9') |
276 return c - '0'; | 285 return c - '0'; |
277 if ('A' <= c && c <= 'F') | 286 if ('A' <= c && c <= 'F') |
278 return c - 'A' + 10; | 287 return c - 'A' + 10; |
279 if ('a' <= c && c <= 'f') | 288 if ('a' <= c && c <= 'f') |
280 return c - 'a' + 10; | 289 return c - 'a' + 10; |
281 NOTREACHED(); | 290 NOTREACHED(); |
282 return 0; | 291 return 0; |
283 } | 292 } |
284 | 293 |
285 bool decodeString(const UChar* start, const UChar* end, String16Builder* output) | 294 template<typename Char> |
| 295 bool decodeString(const Char* start, const Char* end, String16Builder* output) |
286 { | 296 { |
287 while (start < end) { | 297 while (start < end) { |
288 UChar c = *start++; | 298 UChar c = *start++; |
289 if ('\\' != c) { | 299 if ('\\' != c) { |
290 output->append(c); | 300 output->append(c); |
291 continue; | 301 continue; |
292 } | 302 } |
293 c = *start++; | 303 c = *start++; |
294 | 304 |
295 if (c == 'x') { | 305 if (c == 'x') { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
328 start += 4; | 338 start += 4; |
329 break; | 339 break; |
330 default: | 340 default: |
331 return false; | 341 return false; |
332 } | 342 } |
333 output->append(c); | 343 output->append(c); |
334 } | 344 } |
335 return true; | 345 return true; |
336 } | 346 } |
337 | 347 |
338 bool decodeString(const UChar* start, const UChar* end, String16* output) | 348 template<typename Char> |
| 349 bool decodeString(const Char* start, const Char* end, String16* output) |
339 { | 350 { |
340 if (start == end) { | 351 if (start == end) { |
341 *output = ""; | 352 *output = ""; |
342 return true; | 353 return true; |
343 } | 354 } |
344 if (start > end) | 355 if (start > end) |
345 return false; | 356 return false; |
346 String16Builder buffer; | 357 String16Builder buffer; |
347 buffer.reserveCapacity(end - start); | 358 buffer.reserveCapacity(end - start); |
348 if (!decodeString(start, end, &buffer)) | 359 if (!decodeString(start, end, &buffer)) |
349 return false; | 360 return false; |
350 *output = buffer.toString(); | 361 *output = buffer.toString(); |
351 return true; | 362 return true; |
352 } | 363 } |
353 | 364 |
354 std::unique_ptr<Value> buildValue(const UChar* start, const UChar* end, const UC
har** valueTokenEnd, int depth) | 365 template<typename Char> |
| 366 std::unique_ptr<Value> buildValue(const Char* start, const Char* end, const Char
** valueTokenEnd, int depth) |
355 { | 367 { |
356 if (depth > stackLimit) | 368 if (depth > stackLimit) |
357 return nullptr; | 369 return nullptr; |
358 | 370 |
359 std::unique_ptr<Value> result; | 371 std::unique_ptr<Value> result; |
360 const UChar* tokenStart; | 372 const Char* tokenStart; |
361 const UChar* tokenEnd; | 373 const Char* tokenEnd; |
362 Token token = parseToken(start, end, &tokenStart, &tokenEnd); | 374 Token token = parseToken(start, end, &tokenStart, &tokenEnd); |
363 switch (token) { | 375 switch (token) { |
364 case InvalidToken: | 376 case InvalidToken: |
365 return nullptr; | 377 return nullptr; |
366 case NullToken: | 378 case NullToken: |
367 result = Value::null(); | 379 result = Value::null(); |
368 break; | 380 break; |
369 case BoolTrue: | 381 case BoolTrue: |
370 result = FundamentalValue::create(true); | 382 result = FundamentalValue::create(true); |
371 break; | 383 break; |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
464 | 476 |
465 default: | 477 default: |
466 // We got a token that's not a value. | 478 // We got a token that's not a value. |
467 return nullptr; | 479 return nullptr; |
468 } | 480 } |
469 | 481 |
470 skipWhitespaceAndComments(tokenEnd, end, valueTokenEnd); | 482 skipWhitespaceAndComments(tokenEnd, end, valueTokenEnd); |
471 return result; | 483 return result; |
472 } | 484 } |
473 | 485 |
474 std::unique_ptr<Value> parseJSONInternal(const UChar* start, unsigned length) | 486 template<typename Char> |
| 487 std::unique_ptr<Value> parseJSONInternal(const Char* start, unsigned length) |
475 { | 488 { |
476 const UChar* end = start + length; | 489 const Char* end = start + length; |
477 const UChar *tokenEnd; | 490 const Char *tokenEnd; |
478 std::unique_ptr<Value> value = buildValue(start, end, &tokenEnd, 0); | 491 std::unique_ptr<Value> value = buildValue(start, end, &tokenEnd, 0); |
479 if (!value || tokenEnd != end) | 492 if (!value || tokenEnd != end) |
480 return nullptr; | 493 return nullptr; |
481 return value; | 494 return value; |
482 } | 495 } |
483 | 496 |
484 } // anonymous namespace | 497 } // anonymous namespace |
485 | 498 |
| 499 std::unique_ptr<Value> parseJSON(const uint16_t* characters, unsigned length) |
| 500 { |
| 501 return parseJSONInternal<uint16_t>(characters, length); |
| 502 } |
| 503 |
| 504 std::unique_ptr<Value> parseJSON(const uint8_t* characters, unsigned length) |
| 505 { |
| 506 return parseJSONInternal<uint8_t>(characters, length); |
| 507 } |
| 508 |
486 std::unique_ptr<Value> parseJSON(const String16& json) | 509 std::unique_ptr<Value> parseJSON(const String16& json) |
487 { | 510 { |
488 if (json.isEmpty()) | 511 if (json.isEmpty()) |
489 return nullptr; | 512 return nullptr; |
490 return parseJSONInternal(json.characters16(), json.length()); | 513 return parseJSONInternal<UChar>(json.characters16(), json.length()); |
491 } | 514 } |
492 | 515 |
493 } // namespace protocol | 516 } // namespace protocol |
494 } // namespace blink | 517 } // namespace blink |
OLD | NEW |