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