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