| 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 bool isASCII(uint16_t c) |
| 32 { |
| 33 return !(c & ~0x7F); |
| 34 } |
| 35 |
| 36 double charactersToDouble(const uint16_t* characters, size_t length, bool* ok) |
| 37 { |
| 38 std::vector<char> buffer; |
| 39 buffer.reserve(length + 1); |
| 40 for (size_t i = 0; i < length; ++i) { |
| 41 if (!isASCII(characters[i])) { |
| 42 *ok = false; |
| 43 return 0; |
| 44 } |
| 45 buffer.push_back(static_cast<char>(characters[i])); |
| 46 } |
| 47 buffer.push_back('\0'); |
| 48 char* endptr; |
| 49 double result = std::strtod(buffer.data(), &endptr); |
| 50 *ok = !(*endptr); |
| 51 return result; |
| 52 } |
| 53 |
| 54 double charactersToDouble(const uint8_t* characters, size_t length, bool* ok) |
| 55 { |
| 56 std::string buffer(reinterpret_cast<const char*>(characters), length); |
| 57 char* endptr; |
| 58 double result = std::strtod(buffer.data(), &endptr); |
| 59 *ok = !(*endptr); |
| 60 return result; |
| 61 } |
| 62 |
| 63 template<typename Char> |
| 64 bool parseConstToken(const Char* start, const Char* end, const Char** tokenEnd,
const char* token) |
| 32 { | 65 { |
| 33 while (start < end && *token != '\0' && *start++ == *token++) { } | 66 while (start < end && *token != '\0' && *start++ == *token++) { } |
| 34 if (*token != '\0') | 67 if (*token != '\0') |
| 35 return false; | 68 return false; |
| 36 *tokenEnd = start; | 69 *tokenEnd = start; |
| 37 return true; | 70 return true; |
| 38 } | 71 } |
| 39 | 72 |
| 40 bool readInt(const UChar* start, const UChar* end, const UChar** tokenEnd, bool
canHaveLeadingZeros) | 73 template<typename Char> |
| 74 bool readInt(const Char* start, const Char* end, const Char** tokenEnd, bool can
HaveLeadingZeros) |
| 41 { | 75 { |
| 42 if (start == end) | 76 if (start == end) |
| 43 return false; | 77 return false; |
| 44 bool haveLeadingZero = '0' == *start; | 78 bool haveLeadingZero = '0' == *start; |
| 45 int length = 0; | 79 int length = 0; |
| 46 while (start < end && '0' <= *start && *start <= '9') { | 80 while (start < end && '0' <= *start && *start <= '9') { |
| 47 ++start; | 81 ++start; |
| 48 ++length; | 82 ++length; |
| 49 } | 83 } |
| 50 if (!length) | 84 if (!length) |
| 51 return false; | 85 return false; |
| 52 if (!canHaveLeadingZeros && length > 1 && haveLeadingZero) | 86 if (!canHaveLeadingZeros && length > 1 && haveLeadingZero) |
| 53 return false; | 87 return false; |
| 54 *tokenEnd = start; | 88 *tokenEnd = start; |
| 55 return true; | 89 return true; |
| 56 } | 90 } |
| 57 | 91 |
| 58 bool parseNumberToken(const UChar* start, const UChar* end, const UChar** tokenE
nd) | 92 template<typename Char> |
| 93 bool parseNumberToken(const Char* start, const Char* end, const Char** tokenEnd) |
| 59 { | 94 { |
| 60 // We just grab the number here. We validate the size in DecodeNumber. | 95 // We just grab the number here. We validate the size in DecodeNumber. |
| 61 // According to RFC4627, a valid number is: [minus] int [frac] [exp] | 96 // According to RFC4627, a valid number is: [minus] int [frac] [exp] |
| 62 if (start == end) | 97 if (start == end) |
| 63 return false; | 98 return false; |
| 64 UChar c = *start; | 99 Char c = *start; |
| 65 if ('-' == c) | 100 if ('-' == c) |
| 66 ++start; | 101 ++start; |
| 67 | 102 |
| 68 if (!readInt(start, end, &start, false)) | 103 if (!readInt(start, end, &start, false)) |
| 69 return false; | 104 return false; |
| 70 if (start == end) { | 105 if (start == end) { |
| 71 *tokenEnd = start; | 106 *tokenEnd = start; |
| 72 return true; | 107 return true; |
| 73 } | 108 } |
| 74 | 109 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 97 return false; | 132 return false; |
| 98 } | 133 } |
| 99 if (!readInt(start, end, &start, true)) | 134 if (!readInt(start, end, &start, true)) |
| 100 return false; | 135 return false; |
| 101 } | 136 } |
| 102 | 137 |
| 103 *tokenEnd = start; | 138 *tokenEnd = start; |
| 104 return true; | 139 return true; |
| 105 } | 140 } |
| 106 | 141 |
| 107 bool readHexDigits(const UChar* start, const UChar* end, const UChar** tokenEnd,
int digits) | 142 template<typename Char> |
| 143 bool readHexDigits(const Char* start, const Char* end, const Char** tokenEnd, in
t digits) |
| 108 { | 144 { |
| 109 if (end - start < digits) | 145 if (end - start < digits) |
| 110 return false; | 146 return false; |
| 111 for (int i = 0; i < digits; ++i) { | 147 for (int i = 0; i < digits; ++i) { |
| 112 UChar c = *start++; | 148 Char c = *start++; |
| 113 if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c
<= 'F'))) | 149 if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c
<= 'F'))) |
| 114 return false; | 150 return false; |
| 115 } | 151 } |
| 116 *tokenEnd = start; | 152 *tokenEnd = start; |
| 117 return true; | 153 return true; |
| 118 } | 154 } |
| 119 | 155 |
| 120 bool parseStringToken(const UChar* start, const UChar* end, const UChar** tokenE
nd) | 156 template<typename Char> |
| 157 bool parseStringToken(const Char* start, const Char* end, const Char** tokenEnd) |
| 121 { | 158 { |
| 122 while (start < end) { | 159 while (start < end) { |
| 123 UChar c = *start++; | 160 Char c = *start++; |
| 124 if ('\\' == c) { | 161 if ('\\' == c) { |
| 125 c = *start++; | 162 c = *start++; |
| 126 // Make sure the escaped char is valid. | 163 // Make sure the escaped char is valid. |
| 127 switch (c) { | 164 switch (c) { |
| 128 case 'x': | 165 case 'x': |
| 129 if (!readHexDigits(start, end, &start, 2)) | 166 if (!readHexDigits(start, end, &start, 2)) |
| 130 return false; | 167 return false; |
| 131 break; | 168 break; |
| 132 case 'u': | 169 case 'u': |
| 133 if (!readHexDigits(start, end, &start, 4)) | 170 if (!readHexDigits(start, end, &start, 4)) |
| (...skipping 13 matching lines...) Expand all Loading... |
| 147 return false; | 184 return false; |
| 148 } | 185 } |
| 149 } else if ('"' == c) { | 186 } else if ('"' == c) { |
| 150 *tokenEnd = start; | 187 *tokenEnd = start; |
| 151 return true; | 188 return true; |
| 152 } | 189 } |
| 153 } | 190 } |
| 154 return false; | 191 return false; |
| 155 } | 192 } |
| 156 | 193 |
| 157 bool skipComment(const UChar* start, const UChar* end, const UChar** commentEnd) | 194 template<typename Char> |
| 195 bool skipComment(const Char* start, const Char* end, const Char** commentEnd) |
| 158 { | 196 { |
| 159 if (start == end) | 197 if (start == end) |
| 160 return false; | 198 return false; |
| 161 | 199 |
| 162 if (*start != '/' || start + 1 >= end) | 200 if (*start != '/' || start + 1 >= end) |
| 163 return false; | 201 return false; |
| 164 ++start; | 202 ++start; |
| 165 | 203 |
| 166 if (*start == '/') { | 204 if (*start == '/') { |
| 167 // Single line comment, read to newline. | 205 // Single line comment, read to newline. |
| 168 for (++start; start < end; ++start) { | 206 for (++start; start < end; ++start) { |
| 169 if (*start == '\n' || *start == '\r') { | 207 if (*start == '\n' || *start == '\r') { |
| 170 *commentEnd = start + 1; | 208 *commentEnd = start + 1; |
| 171 return true; | 209 return true; |
| 172 } | 210 } |
| 173 } | 211 } |
| 174 *commentEnd = end; | 212 *commentEnd = end; |
| 175 // Comment reaches end-of-input, which is fine. | 213 // Comment reaches end-of-input, which is fine. |
| 176 return true; | 214 return true; |
| 177 } | 215 } |
| 178 | 216 |
| 179 if (*start == '*') { | 217 if (*start == '*') { |
| 180 UChar previous = '\0'; | 218 Char previous = '\0'; |
| 181 // Block comment, read until end marker. | 219 // Block comment, read until end marker. |
| 182 for (++start; start < end; previous = *start++) { | 220 for (++start; start < end; previous = *start++) { |
| 183 if (previous == '*' && *start == '/') { | 221 if (previous == '*' && *start == '/') { |
| 184 *commentEnd = start + 1; | 222 *commentEnd = start + 1; |
| 185 return true; | 223 return true; |
| 186 } | 224 } |
| 187 } | 225 } |
| 188 // Block comment must close before end-of-input. | 226 // Block comment must close before end-of-input. |
| 189 return false; | 227 return false; |
| 190 } | 228 } |
| 191 | 229 |
| 192 return false; | 230 return false; |
| 193 } | 231 } |
| 194 | 232 |
| 195 void skipWhitespaceAndComments(const UChar* start, const UChar* end, const UChar
** whitespaceEnd) | 233 template<typename Char> |
| 234 void skipWhitespaceAndComments(const Char* start, const Char* end, const Char**
whitespaceEnd) |
| 196 { | 235 { |
| 197 while (start < end) { | 236 while (start < end) { |
| 198 if (String16::isSpaceOrNewLine(*start)) { | 237 if (String16::isSpaceOrNewLine(*start)) { |
| 199 ++start; | 238 ++start; |
| 200 } else if (*start == '/') { | 239 } else if (*start == '/') { |
| 201 const UChar* commentEnd; | 240 const Char* commentEnd; |
| 202 if (!skipComment(start, end, &commentEnd)) | 241 if (!skipComment(start, end, &commentEnd)) |
| 203 break; | 242 break; |
| 204 start = commentEnd; | 243 start = commentEnd; |
| 205 } else { | 244 } else { |
| 206 break; | 245 break; |
| 207 } | 246 } |
| 208 } | 247 } |
| 209 *whitespaceEnd = start; | 248 *whitespaceEnd = start; |
| 210 } | 249 } |
| 211 | 250 |
| 212 Token parseToken(const UChar* start, const UChar* end, const UChar** tokenStart,
const UChar** tokenEnd) | 251 template<typename Char> |
| 252 Token parseToken(const Char* start, const Char* end, const Char** tokenStart, co
nst Char** tokenEnd) |
| 213 { | 253 { |
| 214 skipWhitespaceAndComments(start, end, tokenStart); | 254 skipWhitespaceAndComments(start, end, tokenStart); |
| 215 start = *tokenStart; | 255 start = *tokenStart; |
| 216 | 256 |
| 217 if (start == end) | 257 if (start == end) |
| 218 return InvalidToken; | 258 return InvalidToken; |
| 219 | 259 |
| 220 switch (*start) { | 260 switch (*start) { |
| 221 case 'n': | 261 case 'n': |
| 222 if (parseConstToken(start, end, tokenEnd, nullString)) | 262 if (parseConstToken(start, end, tokenEnd, nullString)) |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 return Number; | 303 return Number; |
| 264 break; | 304 break; |
| 265 case '"': | 305 case '"': |
| 266 if (parseStringToken(start + 1, end, tokenEnd)) | 306 if (parseStringToken(start + 1, end, tokenEnd)) |
| 267 return StringLiteral; | 307 return StringLiteral; |
| 268 break; | 308 break; |
| 269 } | 309 } |
| 270 return InvalidToken; | 310 return InvalidToken; |
| 271 } | 311 } |
| 272 | 312 |
| 273 inline int hexToInt(UChar c) | 313 template<typename Char> |
| 314 int hexToInt(Char c) |
| 274 { | 315 { |
| 275 if ('0' <= c && c <= '9') | 316 if ('0' <= c && c <= '9') |
| 276 return c - '0'; | 317 return c - '0'; |
| 277 if ('A' <= c && c <= 'F') | 318 if ('A' <= c && c <= 'F') |
| 278 return c - 'A' + 10; | 319 return c - 'A' + 10; |
| 279 if ('a' <= c && c <= 'f') | 320 if ('a' <= c && c <= 'f') |
| 280 return c - 'a' + 10; | 321 return c - 'a' + 10; |
| 281 NOTREACHED(); | 322 NOTREACHED(); |
| 282 return 0; | 323 return 0; |
| 283 } | 324 } |
| 284 | 325 |
| 285 bool decodeString(const UChar* start, const UChar* end, String16Builder* output) | 326 template<typename Char> |
| 327 bool decodeString(const Char* start, const Char* end, String16Builder* output) |
| 286 { | 328 { |
| 287 while (start < end) { | 329 while (start < end) { |
| 288 UChar c = *start++; | 330 UChar c = *start++; |
| 289 if ('\\' != c) { | 331 if ('\\' != c) { |
| 290 output->append(c); | 332 output->append(c); |
| 291 continue; | 333 continue; |
| 292 } | 334 } |
| 293 c = *start++; | 335 c = *start++; |
| 294 | 336 |
| 295 if (c == 'x') { | 337 if (c == 'x') { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 328 start += 4; | 370 start += 4; |
| 329 break; | 371 break; |
| 330 default: | 372 default: |
| 331 return false; | 373 return false; |
| 332 } | 374 } |
| 333 output->append(c); | 375 output->append(c); |
| 334 } | 376 } |
| 335 return true; | 377 return true; |
| 336 } | 378 } |
| 337 | 379 |
| 338 bool decodeString(const UChar* start, const UChar* end, String16* output) | 380 template<typename Char> |
| 381 bool decodeString(const Char* start, const Char* end, String16* output) |
| 339 { | 382 { |
| 340 if (start == end) { | 383 if (start == end) { |
| 341 *output = ""; | 384 *output = ""; |
| 342 return true; | 385 return true; |
| 343 } | 386 } |
| 344 if (start > end) | 387 if (start > end) |
| 345 return false; | 388 return false; |
| 346 String16Builder buffer; | 389 String16Builder buffer; |
| 347 buffer.reserveCapacity(end - start); | 390 buffer.reserveCapacity(end - start); |
| 348 if (!decodeString(start, end, &buffer)) | 391 if (!decodeString(start, end, &buffer)) |
| 349 return false; | 392 return false; |
| 350 *output = buffer.toString(); | 393 *output = buffer.toString(); |
| 351 return true; | 394 return true; |
| 352 } | 395 } |
| 353 | 396 |
| 354 std::unique_ptr<Value> buildValue(const UChar* start, const UChar* end, const UC
har** valueTokenEnd, int depth) | 397 template<typename Char> |
| 398 std::unique_ptr<Value> buildValue(const Char* start, const Char* end, const Char
** valueTokenEnd, int depth) |
| 355 { | 399 { |
| 356 if (depth > stackLimit) | 400 if (depth > stackLimit) |
| 357 return nullptr; | 401 return nullptr; |
| 358 | 402 |
| 359 std::unique_ptr<Value> result; | 403 std::unique_ptr<Value> result; |
| 360 const UChar* tokenStart; | 404 const Char* tokenStart; |
| 361 const UChar* tokenEnd; | 405 const Char* tokenEnd; |
| 362 Token token = parseToken(start, end, &tokenStart, &tokenEnd); | 406 Token token = parseToken(start, end, &tokenStart, &tokenEnd); |
| 363 switch (token) { | 407 switch (token) { |
| 364 case InvalidToken: | 408 case InvalidToken: |
| 365 return nullptr; | 409 return nullptr; |
| 366 case NullToken: | 410 case NullToken: |
| 367 result = Value::null(); | 411 result = Value::null(); |
| 368 break; | 412 break; |
| 369 case BoolTrue: | 413 case BoolTrue: |
| 370 result = FundamentalValue::create(true); | 414 result = FundamentalValue::create(true); |
| 371 break; | 415 break; |
| 372 case BoolFalse: | 416 case BoolFalse: |
| 373 result = FundamentalValue::create(false); | 417 result = FundamentalValue::create(false); |
| 374 break; | 418 break; |
| 375 case Number: { | 419 case Number: { |
| 376 bool ok; | 420 bool ok; |
| 377 double value = String16::charactersToDouble(tokenStart, tokenEnd - token
Start, &ok); | 421 double value = charactersToDouble(tokenStart, tokenEnd - tokenStart, &ok
); |
| 378 if (!ok) | 422 if (!ok) |
| 379 return nullptr; | 423 return nullptr; |
| 380 int number = static_cast<int>(value); | 424 int number = static_cast<int>(value); |
| 381 if (number == value) | 425 if (number == value) |
| 382 result = FundamentalValue::create(number); | 426 result = FundamentalValue::create(number); |
| 383 else | 427 else |
| 384 result = FundamentalValue::create(value); | 428 result = FundamentalValue::create(value); |
| 385 break; | 429 break; |
| 386 } | 430 } |
| 387 case StringLiteral: { | 431 case StringLiteral: { |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 464 | 508 |
| 465 default: | 509 default: |
| 466 // We got a token that's not a value. | 510 // We got a token that's not a value. |
| 467 return nullptr; | 511 return nullptr; |
| 468 } | 512 } |
| 469 | 513 |
| 470 skipWhitespaceAndComments(tokenEnd, end, valueTokenEnd); | 514 skipWhitespaceAndComments(tokenEnd, end, valueTokenEnd); |
| 471 return result; | 515 return result; |
| 472 } | 516 } |
| 473 | 517 |
| 474 std::unique_ptr<Value> parseJSONInternal(const UChar* start, unsigned length) | 518 template<typename Char> |
| 519 std::unique_ptr<Value> parseJSONInternal(const Char* start, unsigned length) |
| 475 { | 520 { |
| 476 const UChar* end = start + length; | 521 const Char* end = start + length; |
| 477 const UChar *tokenEnd; | 522 const Char *tokenEnd; |
| 478 std::unique_ptr<Value> value = buildValue(start, end, &tokenEnd, 0); | 523 std::unique_ptr<Value> value = buildValue(start, end, &tokenEnd, 0); |
| 479 if (!value || tokenEnd != end) | 524 if (!value || tokenEnd != end) |
| 480 return nullptr; | 525 return nullptr; |
| 481 return value; | 526 return value; |
| 482 } | 527 } |
| 483 | 528 |
| 484 } // anonymous namespace | 529 } // anonymous namespace |
| 485 | 530 |
| 531 std::unique_ptr<Value> parseJSON(const uint16_t* characters, unsigned length) |
| 532 { |
| 533 return parseJSONInternal<uint16_t>(characters, length); |
| 534 } |
| 535 |
| 536 std::unique_ptr<Value> parseJSON(const uint8_t* characters, unsigned length) |
| 537 { |
| 538 return parseJSONInternal<uint8_t>(characters, length); |
| 539 } |
| 540 |
| 486 std::unique_ptr<Value> parseJSON(const String16& json) | 541 std::unique_ptr<Value> parseJSON(const String16& json) |
| 487 { | 542 { |
| 488 if (json.isEmpty()) | 543 if (json.isEmpty()) |
| 489 return nullptr; | 544 return nullptr; |
| 490 return parseJSONInternal(json.characters16(), json.length()); | 545 return parseJSONInternal<UChar>(json.characters16(), json.length()); |
| 491 } | 546 } |
| 492 | 547 |
| 493 } // namespace protocol | 548 } // namespace protocol |
| 494 } // namespace blink | 549 } // namespace blink |
| OLD | NEW |