| 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 #include "platform/inspector_protocol/Parser.h" | 5 #include "platform/inspector_protocol/Parser.h" |
| 6 | 6 |
| 7 #include "platform/inspector_protocol/String16.h" | 7 #include "platform/inspector_protocol/String16.h" |
| 8 #include "platform/inspector_protocol/Values.h" | 8 #include "platform/inspector_protocol/Values.h" |
| 9 | 9 |
| 10 namespace blink { | 10 namespace blink { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 NullToken, | 26 NullToken, |
| 27 ListSeparator, | 27 ListSeparator, |
| 28 ObjectPairSeparator, | 28 ObjectPairSeparator, |
| 29 InvalidToken, | 29 InvalidToken, |
| 30 }; | 30 }; |
| 31 | 31 |
| 32 const char* const nullString = "null"; | 32 const char* const nullString = "null"; |
| 33 const char* const trueString = "true"; | 33 const char* const trueString = "true"; |
| 34 const char* const falseString = "false"; | 34 const char* const falseString = "false"; |
| 35 | 35 |
| 36 template<typename CharType> | 36 bool parseConstToken(const UChar* start, const UChar* end, const UChar** tokenEn
d, const char* token) |
| 37 bool parseConstToken(const CharType* start, const CharType* end, const CharType*
* tokenEnd, const char* token) | |
| 38 { | 37 { |
| 39 while (start < end && *token != '\0' && *start++ == *token++) { } | 38 while (start < end && *token != '\0' && *start++ == *token++) { } |
| 40 if (*token != '\0') | 39 if (*token != '\0') |
| 41 return false; | 40 return false; |
| 42 *tokenEnd = start; | 41 *tokenEnd = start; |
| 43 return true; | 42 return true; |
| 44 } | 43 } |
| 45 | 44 |
| 46 template<typename CharType> | 45 bool readInt(const UChar* start, const UChar* end, const UChar** tokenEnd, bool
canHaveLeadingZeros) |
| 47 bool readInt(const CharType* start, const CharType* end, const CharType** tokenE
nd, bool canHaveLeadingZeros) | |
| 48 { | 46 { |
| 49 if (start == end) | 47 if (start == end) |
| 50 return false; | 48 return false; |
| 51 bool haveLeadingZero = '0' == *start; | 49 bool haveLeadingZero = '0' == *start; |
| 52 int length = 0; | 50 int length = 0; |
| 53 while (start < end && '0' <= *start && *start <= '9') { | 51 while (start < end && '0' <= *start && *start <= '9') { |
| 54 ++start; | 52 ++start; |
| 55 ++length; | 53 ++length; |
| 56 } | 54 } |
| 57 if (!length) | 55 if (!length) |
| 58 return false; | 56 return false; |
| 59 if (!canHaveLeadingZeros && length > 1 && haveLeadingZero) | 57 if (!canHaveLeadingZeros && length > 1 && haveLeadingZero) |
| 60 return false; | 58 return false; |
| 61 *tokenEnd = start; | 59 *tokenEnd = start; |
| 62 return true; | 60 return true; |
| 63 } | 61 } |
| 64 | 62 |
| 65 template<typename CharType> | 63 bool parseNumberToken(const UChar* start, const UChar* end, const UChar** tokenE
nd) |
| 66 bool parseNumberToken(const CharType* start, const CharType* end, const CharType
** tokenEnd) | |
| 67 { | 64 { |
| 68 // We just grab the number here. We validate the size in DecodeNumber. | 65 // We just grab the number here. We validate the size in DecodeNumber. |
| 69 // According to RFC4627, a valid number is: [minus] int [frac] [exp] | 66 // According to RFC4627, a valid number is: [minus] int [frac] [exp] |
| 70 if (start == end) | 67 if (start == end) |
| 71 return false; | 68 return false; |
| 72 CharType c = *start; | 69 UChar c = *start; |
| 73 if ('-' == c) | 70 if ('-' == c) |
| 74 ++start; | 71 ++start; |
| 75 | 72 |
| 76 if (!readInt(start, end, &start, false)) | 73 if (!readInt(start, end, &start, false)) |
| 77 return false; | 74 return false; |
| 78 if (start == end) { | 75 if (start == end) { |
| 79 *tokenEnd = start; | 76 *tokenEnd = start; |
| 80 return true; | 77 return true; |
| 81 } | 78 } |
| 82 | 79 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 105 return false; | 102 return false; |
| 106 } | 103 } |
| 107 if (!readInt(start, end, &start, true)) | 104 if (!readInt(start, end, &start, true)) |
| 108 return false; | 105 return false; |
| 109 } | 106 } |
| 110 | 107 |
| 111 *tokenEnd = start; | 108 *tokenEnd = start; |
| 112 return true; | 109 return true; |
| 113 } | 110 } |
| 114 | 111 |
| 115 template<typename CharType> | 112 bool readHexDigits(const UChar* start, const UChar* end, const UChar** tokenEnd,
int digits) |
| 116 bool readHexDigits(const CharType* start, const CharType* end, const CharType**
tokenEnd, int digits) | |
| 117 { | 113 { |
| 118 if (end - start < digits) | 114 if (end - start < digits) |
| 119 return false; | 115 return false; |
| 120 for (int i = 0; i < digits; ++i) { | 116 for (int i = 0; i < digits; ++i) { |
| 121 CharType c = *start++; | 117 UChar c = *start++; |
| 122 if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c
<= 'F'))) | 118 if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c
<= 'F'))) |
| 123 return false; | 119 return false; |
| 124 } | 120 } |
| 125 *tokenEnd = start; | 121 *tokenEnd = start; |
| 126 return true; | 122 return true; |
| 127 } | 123 } |
| 128 | 124 |
| 129 template<typename CharType> | 125 bool parseStringToken(const UChar* start, const UChar* end, const UChar** tokenE
nd) |
| 130 bool parseStringToken(const CharType* start, const CharType* end, const CharType
** tokenEnd) | |
| 131 { | 126 { |
| 132 while (start < end) { | 127 while (start < end) { |
| 133 CharType c = *start++; | 128 UChar c = *start++; |
| 134 if ('\\' == c) { | 129 if ('\\' == c) { |
| 135 c = *start++; | 130 c = *start++; |
| 136 // Make sure the escaped char is valid. | 131 // Make sure the escaped char is valid. |
| 137 switch (c) { | 132 switch (c) { |
| 138 case 'x': | 133 case 'x': |
| 139 if (!readHexDigits(start, end, &start, 2)) | 134 if (!readHexDigits(start, end, &start, 2)) |
| 140 return false; | 135 return false; |
| 141 break; | 136 break; |
| 142 case 'u': | 137 case 'u': |
| 143 if (!readHexDigits(start, end, &start, 4)) | 138 if (!readHexDigits(start, end, &start, 4)) |
| (...skipping 13 matching lines...) Expand all Loading... |
| 157 return false; | 152 return false; |
| 158 } | 153 } |
| 159 } else if ('"' == c) { | 154 } else if ('"' == c) { |
| 160 *tokenEnd = start; | 155 *tokenEnd = start; |
| 161 return true; | 156 return true; |
| 162 } | 157 } |
| 163 } | 158 } |
| 164 return false; | 159 return false; |
| 165 } | 160 } |
| 166 | 161 |
| 167 template<typename CharType> | 162 bool skipComment(const UChar* start, const UChar* end, const UChar** commentEnd) |
| 168 bool skipComment(const CharType* start, const CharType* end, const CharType** co
mmentEnd) | |
| 169 { | 163 { |
| 170 if (start == end) | 164 if (start == end) |
| 171 return false; | 165 return false; |
| 172 | 166 |
| 173 if (*start != '/' || start + 1 >= end) | 167 if (*start != '/' || start + 1 >= end) |
| 174 return false; | 168 return false; |
| 175 ++start; | 169 ++start; |
| 176 | 170 |
| 177 if (*start == '/') { | 171 if (*start == '/') { |
| 178 // Single line comment, read to newline. | 172 // Single line comment, read to newline. |
| 179 for (++start; start < end; ++start) { | 173 for (++start; start < end; ++start) { |
| 180 if (*start == '\n' || *start == '\r') { | 174 if (*start == '\n' || *start == '\r') { |
| 181 *commentEnd = start + 1; | 175 *commentEnd = start + 1; |
| 182 return true; | 176 return true; |
| 183 } | 177 } |
| 184 } | 178 } |
| 185 *commentEnd = end; | 179 *commentEnd = end; |
| 186 // Comment reaches end-of-input, which is fine. | 180 // Comment reaches end-of-input, which is fine. |
| 187 return true; | 181 return true; |
| 188 } | 182 } |
| 189 | 183 |
| 190 if (*start == '*') { | 184 if (*start == '*') { |
| 191 CharType previous = '\0'; | 185 UChar previous = '\0'; |
| 192 // Block comment, read until end marker. | 186 // Block comment, read until end marker. |
| 193 for (++start; start < end; previous = *start++) { | 187 for (++start; start < end; previous = *start++) { |
| 194 if (previous == '*' && *start == '/') { | 188 if (previous == '*' && *start == '/') { |
| 195 *commentEnd = start + 1; | 189 *commentEnd = start + 1; |
| 196 return true; | 190 return true; |
| 197 } | 191 } |
| 198 } | 192 } |
| 199 // Block comment must close before end-of-input. | 193 // Block comment must close before end-of-input. |
| 200 return false; | 194 return false; |
| 201 } | 195 } |
| 202 | 196 |
| 203 return false; | 197 return false; |
| 204 } | 198 } |
| 205 | 199 |
| 206 template<typename CharType> | 200 void skipWhitespaceAndComments(const UChar* start, const UChar* end, const UChar
** whitespaceEnd) |
| 207 void skipWhitespaceAndComments(const CharType* start, const CharType* end, const
CharType** whitespaceEnd) | |
| 208 { | 201 { |
| 209 while (start < end) { | 202 while (start < end) { |
| 210 if (isSpaceOrNewline(*start)) { | 203 if (isSpaceOrNewline(*start)) { |
| 211 ++start; | 204 ++start; |
| 212 } else if (*start == '/') { | 205 } else if (*start == '/') { |
| 213 const CharType* commentEnd; | 206 const UChar* commentEnd; |
| 214 if (!skipComment(start, end, &commentEnd)) | 207 if (!skipComment(start, end, &commentEnd)) |
| 215 break; | 208 break; |
| 216 start = commentEnd; | 209 start = commentEnd; |
| 217 } else { | 210 } else { |
| 218 break; | 211 break; |
| 219 } | 212 } |
| 220 } | 213 } |
| 221 *whitespaceEnd = start; | 214 *whitespaceEnd = start; |
| 222 } | 215 } |
| 223 | 216 |
| 224 template<typename CharType> | 217 Token parseToken(const UChar* start, const UChar* end, const UChar** tokenStart,
const UChar** tokenEnd) |
| 225 Token parseToken(const CharType* start, const CharType* end, const CharType** to
kenStart, const CharType** tokenEnd) | |
| 226 { | 218 { |
| 227 skipWhitespaceAndComments(start, end, tokenStart); | 219 skipWhitespaceAndComments(start, end, tokenStart); |
| 228 start = *tokenStart; | 220 start = *tokenStart; |
| 229 | 221 |
| 230 if (start == end) | 222 if (start == end) |
| 231 return InvalidToken; | 223 return InvalidToken; |
| 232 | 224 |
| 233 switch (*start) { | 225 switch (*start) { |
| 234 case 'n': | 226 case 'n': |
| 235 if (parseConstToken(start, end, tokenEnd, nullString)) | 227 if (parseConstToken(start, end, tokenEnd, nullString)) |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 return Number; | 268 return Number; |
| 277 break; | 269 break; |
| 278 case '"': | 270 case '"': |
| 279 if (parseStringToken(start + 1, end, tokenEnd)) | 271 if (parseStringToken(start + 1, end, tokenEnd)) |
| 280 return StringLiteral; | 272 return StringLiteral; |
| 281 break; | 273 break; |
| 282 } | 274 } |
| 283 return InvalidToken; | 275 return InvalidToken; |
| 284 } | 276 } |
| 285 | 277 |
| 286 template<typename CharType> | 278 inline int hexToInt(UChar c) |
| 287 inline int hexToInt(CharType c) | |
| 288 { | 279 { |
| 289 if ('0' <= c && c <= '9') | 280 if ('0' <= c && c <= '9') |
| 290 return c - '0'; | 281 return c - '0'; |
| 291 if ('A' <= c && c <= 'F') | 282 if ('A' <= c && c <= 'F') |
| 292 return c - 'A' + 10; | 283 return c - 'A' + 10; |
| 293 if ('a' <= c && c <= 'f') | 284 if ('a' <= c && c <= 'f') |
| 294 return c - 'a' + 10; | 285 return c - 'a' + 10; |
| 295 ASSERT_NOT_REACHED(); | 286 ASSERT_NOT_REACHED(); |
| 296 return 0; | 287 return 0; |
| 297 } | 288 } |
| 298 | 289 |
| 299 template<typename CharType> | 290 bool decodeString(const UChar* start, const UChar* end, String16Builder* output) |
| 300 bool decodeUTF8(const CharType* start, const CharType* end, const CharType** utf
8charEnd, String16Builder* output) | |
| 301 { | |
| 302 UChar utf16[4] = {0}; | |
| 303 char utf8[6] = {0}; | |
| 304 size_t utf8count = 0; | |
| 305 | |
| 306 while (start < end) { | |
| 307 if (start + 1 >= end || *start != '\\' || *(start + 1) != 'x') | |
| 308 return false; | |
| 309 start += 2; | |
| 310 | |
| 311 // Accumulate one more utf8 character and try converting to utf16. | |
| 312 if (start + 1 >= end) | |
| 313 return false; | |
| 314 utf8[utf8count++] = (hexToInt(*start) << 4) + hexToInt(*(start + 1)); | |
| 315 start += 2; | |
| 316 | |
| 317 const char* utf8start = utf8; | |
| 318 UChar* utf16start = utf16; | |
| 319 String16::ConversionResult conversionResult = String16::convertUTF8ToUTF
16(&utf8start, utf8start + utf8count, &utf16start, utf16start + 4, nullptr, true
); | |
| 320 | |
| 321 if (conversionResult == String16::sourceIllegal) | |
| 322 return false; | |
| 323 | |
| 324 if (conversionResult == String16::conversionOK) { | |
| 325 // Not all utf8 characters were consumed - failed parsing. | |
| 326 if (utf8start != utf8 + utf8count) | |
| 327 return false; | |
| 328 | |
| 329 size_t utf16length = utf16start - utf16; | |
| 330 output->append(utf16, utf16length); | |
| 331 *utf8charEnd = start; | |
| 332 return true; | |
| 333 } | |
| 334 | |
| 335 // Keep accumulating utf8 characters up to buffer length (6 should be en
ough). | |
| 336 if (utf8count >= 6) | |
| 337 return false; | |
| 338 } | |
| 339 | |
| 340 return false; | |
| 341 } | |
| 342 | |
| 343 template<typename CharType> | |
| 344 bool decodeString(const CharType* start, const CharType* end, String16Builder* o
utput) | |
| 345 { | 291 { |
| 346 while (start < end) { | 292 while (start < end) { |
| 347 UChar c = *start++; | 293 UChar c = *start++; |
| 348 if ('\\' != c) { | 294 if ('\\' != c) { |
| 349 output->append(c); | 295 output->append(c); |
| 350 continue; | 296 continue; |
| 351 } | 297 } |
| 352 c = *start++; | 298 c = *start++; |
| 353 | 299 |
| 354 if (c == 'x') { | 300 if (c == 'x') { |
| 355 // Rewind "\x". | 301 // \x is not supported. |
| 356 if (!decodeUTF8(start - 2, end, &start, output)) | 302 return false; |
| 357 return false; | |
| 358 continue; | |
| 359 } | 303 } |
| 360 | 304 |
| 361 switch (c) { | 305 switch (c) { |
| 362 case '"': | 306 case '"': |
| 363 case '/': | 307 case '/': |
| 364 case '\\': | 308 case '\\': |
| 365 break; | 309 break; |
| 366 case 'b': | 310 case 'b': |
| 367 c = '\b'; | 311 c = '\b'; |
| 368 break; | 312 break; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 389 start += 4; | 333 start += 4; |
| 390 break; | 334 break; |
| 391 default: | 335 default: |
| 392 return false; | 336 return false; |
| 393 } | 337 } |
| 394 output->append(c); | 338 output->append(c); |
| 395 } | 339 } |
| 396 return true; | 340 return true; |
| 397 } | 341 } |
| 398 | 342 |
| 399 template<typename CharType> | 343 bool decodeString(const UChar* start, const UChar* end, String16* output) |
| 400 bool decodeString(const CharType* start, const CharType* end, String16* output) | |
| 401 { | 344 { |
| 402 if (start == end) { | 345 if (start == end) { |
| 403 *output = ""; | 346 *output = ""; |
| 404 return true; | 347 return true; |
| 405 } | 348 } |
| 406 if (start > end) | 349 if (start > end) |
| 407 return false; | 350 return false; |
| 408 String16Builder buffer; | 351 String16Builder buffer; |
| 409 buffer.reserveCapacity(end - start); | 352 buffer.reserveCapacity(end - start); |
| 410 if (!decodeString(start, end, &buffer)) | 353 if (!decodeString(start, end, &buffer)) |
| 411 return false; | 354 return false; |
| 412 *output = buffer.toString(); | 355 *output = buffer.toString(); |
| 413 // Validate constructed utf16 string. | |
| 414 if (!output->validateUTF8()) | |
| 415 return false; | |
| 416 return true; | 356 return true; |
| 417 } | 357 } |
| 418 | 358 |
| 419 template<typename CharType> | 359 PassOwnPtr<Value> buildValue(const UChar* start, const UChar* end, const UChar**
valueTokenEnd, int depth) |
| 420 PassOwnPtr<Value> buildValue(const CharType* start, const CharType* end, const C
harType** valueTokenEnd, int depth) | |
| 421 { | 360 { |
| 422 if (depth > stackLimit) | 361 if (depth > stackLimit) |
| 423 return nullptr; | 362 return nullptr; |
| 424 | 363 |
| 425 OwnPtr<Value> result; | 364 OwnPtr<Value> result; |
| 426 const CharType* tokenStart; | 365 const UChar* tokenStart; |
| 427 const CharType* tokenEnd; | 366 const UChar* tokenEnd; |
| 428 Token token = parseToken(start, end, &tokenStart, &tokenEnd); | 367 Token token = parseToken(start, end, &tokenStart, &tokenEnd); |
| 429 switch (token) { | 368 switch (token) { |
| 430 case InvalidToken: | 369 case InvalidToken: |
| 431 return nullptr; | 370 return nullptr; |
| 432 case NullToken: | 371 case NullToken: |
| 433 result = Value::null(); | 372 result = Value::null(); |
| 434 break; | 373 break; |
| 435 case BoolTrue: | 374 case BoolTrue: |
| 436 result = FundamentalValue::create(true); | 375 result = FundamentalValue::create(true); |
| 437 break; | 376 break; |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 526 | 465 |
| 527 default: | 466 default: |
| 528 // We got a token that's not a value. | 467 // We got a token that's not a value. |
| 529 return nullptr; | 468 return nullptr; |
| 530 } | 469 } |
| 531 | 470 |
| 532 skipWhitespaceAndComments(tokenEnd, end, valueTokenEnd); | 471 skipWhitespaceAndComments(tokenEnd, end, valueTokenEnd); |
| 533 return result.release(); | 472 return result.release(); |
| 534 } | 473 } |
| 535 | 474 |
| 536 template<typename CharType> | 475 PassOwnPtr<Value> parseJSONInternal(const UChar* start, unsigned length) |
| 537 PassOwnPtr<Value> parseJSONInternal(const CharType* start, unsigned length) | |
| 538 { | 476 { |
| 539 const CharType* end = start + length; | 477 const UChar* end = start + length; |
| 540 const CharType *tokenEnd; | 478 const UChar *tokenEnd; |
| 541 OwnPtr<Value> value = buildValue(start, end, &tokenEnd, 0); | 479 OwnPtr<Value> value = buildValue(start, end, &tokenEnd, 0); |
| 542 if (!value || tokenEnd != end) | 480 if (!value || tokenEnd != end) |
| 543 return nullptr; | 481 return nullptr; |
| 544 return value.release(); | 482 return value.release(); |
| 545 } | 483 } |
| 546 | 484 |
| 547 } // anonymous namespace | 485 } // anonymous namespace |
| 548 | 486 |
| 549 PassOwnPtr<Value> parseJSON(const String16& json) | 487 PassOwnPtr<Value> parseJSON(const String16& json) |
| 550 { | 488 { |
| 551 if (json.isEmpty()) | 489 if (json.isEmpty()) |
| 552 return nullptr; | 490 return nullptr; |
| 553 if (json.is8Bit()) | |
| 554 return parseJSONInternal(json.characters8(), json.length()); | |
| 555 return parseJSONInternal(json.characters16(), json.length()); | 491 return parseJSONInternal(json.characters16(), json.length()); |
| 556 } | 492 } |
| 557 | 493 |
| 558 } // namespace protocol | 494 } // namespace protocol |
| 559 } // namespace blink | 495 } // namespace blink |
| OLD | NEW |