1 /* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "InspectorValues.h" 33 34 #if ENABLE(INSPECTOR) 35 36 #include <wtf/DecimalNumber.h> 37 38 namespace WebCore { 39 40 namespace { 41 42 static const int stackLimit = 1000; 43 44 enum Token { 45 OBJECT_BEGIN, 46 OBJECT_END, 47 ARRAY_BEGIN, 48 ARRAY_END, 49 STRING, 50 NUMBER, 51 BOOL_TRUE, 52 BOOL_FALSE, 53 NULL_TOKEN, 54 LIST_SEPARATOR, 55 OBJECT_PAIR_SEPARATOR, 56 INVALID_TOKEN, 57 }; 58 59 const char* const nullString = "null"; 60 const char* const trueString = "true"; 61 const char* const falseString = "false"; 62 63 bool parseConstToken(const UChar* start, const UChar* end, const UChar** tokenEnd, const char* token) 64 { 65 while (start < end && *token != '\0' && *start++ == *token++) { } 66 if (*token != '\0') 67 return false; 68 *tokenEnd = start; 69 return true; 70 } 71 72 bool readInt(const UChar* start, const UChar* end, const UChar** tokenEnd, bool canHaveLeadingZeros) 73 { 74 if (start == end) 75 return false; 76 bool haveLeadingZero = '0' == *start; 77 int length = 0; 78 while (start < end && '0' <= *start && *start <= '9') { 79 ++start; 80 ++length; 81 } 82 if (!length) 83 return false; 84 if (!canHaveLeadingZeros && length > 1 && haveLeadingZero) 85 return false; 86 *tokenEnd = start; 87 return true; 88 } 89 90 bool parseNumberToken(const UChar* start, const UChar* end, const UChar** tokenEnd) 91 { 92 // We just grab the number here. We validate the size in DecodeNumber. 93 // According to RFC4627, a valid number is: [minus] int [frac] [exp] 94 if (start == end) 95 return false; 96 UChar c = *start; 97 if ('-' == c) 98 ++start; 99 100 if (!readInt(start, end, &start, false)) 101 return false; 102 if (start == end) { 103 *tokenEnd = start; 104 return true; 105 } 106 107 // Optional fraction part 108 c = *start; 109 if ('.' == c) { 110 ++start; 111 if (!readInt(start, end, &start, true)) 112 return false; 113 if (start == end) { 114 *tokenEnd = start; 115 return true; 116 } 117 c = *start; 118 } 119 120 // Optional exponent part 121 if ('e' == c || 'E' == c) { 122 ++start; 123 if (start == end) 124 return false; 125 c = *start; 126 if ('-' == c || '+' == c) { 127 ++start; 128 if (start == end) 129 return false; 130 } 131 if (!readInt(start, end, &start, true)) 132 return false; 133 } 134 135 *tokenEnd = start; 136 return true; 137 } 138 139 bool readHexDigits(const UChar* start, const UChar* end, const UChar** tokenEnd, int digits) 140 { 141 if (end - start < digits) 142 return false; 143 for (int i = 0; i < digits; ++i) { 144 UChar c = *start++; 145 if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F'))) 146 return false; 147 } 148 *tokenEnd = start; 149 return true; 150 } 151 152 bool parseStringToken(const UChar* start, const UChar* end, const UChar** tokenEnd) 153 { 154 while (start < end) { 155 UChar c = *start++; 156 if ('\\' == c) { 157 c = *start++; 158 // Make sure the escaped char is valid. 159 switch (c) { 160 case 'x': 161 if (!readHexDigits(start, end, &start, 2)) 162 return false; 163 break; 164 case 'u': 165 if (!readHexDigits(start, end, &start, 4)) 166 return false; 167 break; 168 case '\\': 169 case '/': 170 case 'b': 171 case 'f': 172 case 'n': 173 case 'r': 174 case 't': 175 case 'v': 176 case '"': 177 break; 178 default: 179 return false; 180 } 181 } else if ('"' == c) { 182 *tokenEnd = start; 183 return true; 184 } 185 } 186 return false; 187 } 188 189 Token parseToken(const UChar* start, const UChar* end, const UChar** tokenEnd) 190 { 191 if (start == end) 192 return INVALID_TOKEN; 193 194 switch (*start) { 195 case 'n': 196 if (parseConstToken(start, end, tokenEnd, nullString)) 197 return NULL_TOKEN; 198 break; 199 case 't': 200 if (parseConstToken(start, end, tokenEnd, trueString)) 201 return BOOL_TRUE; 202 break; 203 case 'f': 204 if (parseConstToken(start, end, tokenEnd, falseString)) 205 return BOOL_FALSE; 206 break; 207 case '[': 208 *tokenEnd = start + 1; 209 return ARRAY_BEGIN; 210 case ']': 211 *tokenEnd = start + 1; 212 return ARRAY_END; 213 case ',': 214 *tokenEnd = start + 1; 215 return LIST_SEPARATOR; 216 case '{': 217 *tokenEnd = start + 1; 218 return OBJECT_BEGIN; 219 case '}': 220 *tokenEnd = start + 1; 221 return OBJECT_END; 222 case ':': 223 *tokenEnd = start + 1; 224 return OBJECT_PAIR_SEPARATOR; 225 case '0': 226 case '1': 227 case '2': 228 case '3': 229 case '4': 230 case '5': 231 case '6': 232 case '7': 233 case '8': 234 case '9': 235 case '-': 236 if (parseNumberToken(start, end, tokenEnd)) 237 return NUMBER; 238 break; 239 case '"': 240 if (parseStringToken(start + 1, end, tokenEnd)) 241 return STRING; 242 break; 243 } 244 return INVALID_TOKEN; 245 } 246 247 inline int hexToInt(UChar c) 248 { 249 if ('0' <= c && c <= '9') 250 return c - '0'; 251 if ('A' <= c && c <= 'F') 252 return c - 'A' + 10; 253 if ('a' <= c && c <= 'f') 254 return c - 'a' + 10; 255 ASSERT_NOT_REACHED(); 256 return 0; 257 } 258 259 bool decodeString(const UChar* start, const UChar* end, Vector<UChar>* output) 260 { 261 while (start < end) { 262 UChar c = *start++; 263 if ('\\' != c) { 264 output->append(c); 265 continue; 266 } 267 c = *start++; 268 switch (c) { 269 case '"': 270 case '/': 271 case '\\': 272 break; 273 case 'b': 274 c = '\b'; 275 break; 276 case 'f': 277 c = '\f'; 278 break; 279 case 'n': 280 c = '\n'; 281 break; 282 case 'r': 283 c = '\r'; 284 break; 285 case 't': 286 c = '\t'; 287 break; 288 case 'v': 289 c = '\v'; 290 break; 291 case 'x': 292 c = (hexToInt(*start) << 4) + 293 hexToInt(*(start + 1)); 294 start += 2; 295 break; 296 case 'u': 297 c = (hexToInt(*start) << 12) + 298 (hexToInt(*(start + 1)) << 8) + 299 (hexToInt(*(start + 2)) << 4) + 300 hexToInt(*(start + 3)); 301 start += 4; 302 break; 303 default: 304 return false; 305 } 306 output->append(c); 307 } 308 return true; 309 } 310 311 bool decodeString(const UChar* start, const UChar* end, String* output) 312 { 313 if (start == end) { 314 *output = ""; 315 return true; 316 } 317 if (start > end) 318 return false; 319 Vector<UChar> buffer; 320 buffer.reserveCapacity(end - start); 321 if (!decodeString(start, end, &buffer)) 322 return false; 323 *output = String(buffer.data(), buffer.size()); 324 return true; 325 } 326 327 PassRefPtr<InspectorValue> buildValue(const UChar* start, const UChar* end, const UChar** valueTokenEnd, int depth) 328 { 329 if (depth > stackLimit) 330 return 0; 331 332 RefPtr<InspectorValue> result; 333 const UChar* tokenEnd; 334 Token token = parseToken(start, end, &tokenEnd); 335 switch (token) { 336 case INVALID_TOKEN: 337 return 0; 338 case NULL_TOKEN: 339 result = InspectorValue::null(); 340 break; 341 case BOOL_TRUE: 342 result = InspectorBasicValue::create(true); 343 break; 344 case BOOL_FALSE: 345 result = InspectorBasicValue::create(false); 346 break; 347 case NUMBER: { 348 bool ok; 349 double value = charactersToDouble(start, tokenEnd - start, &ok); 350 if (!ok) 351 return 0; 352 result = InspectorBasicValue::create(value); 353 break; 354 } 355 case STRING: { 356 String value; 357 bool ok = decodeString(start + 1, tokenEnd - 1, &value); 358 if (!ok) 359 return 0; 360 result = InspectorString::create(value); 361 break; 362 } 363 case ARRAY_BEGIN: { 364 RefPtr<InspectorArray> array = InspectorArray::create(); 365 start = tokenEnd; 366 token = parseToken(start, end, &tokenEnd); 367 while (token != ARRAY_END) { 368 RefPtr<InspectorValue> arrayNode = buildValue(start, end, &tokenEnd, depth + 1); 369 if (!arrayNode) 370 return 0; 371 array->pushValue(arrayNode); 372 373 // After a list value, we expect a comma or the end of the list. 374 start = tokenEnd; 375 token = parseToken(start, end, &tokenEnd); 376 if (token == LIST_SEPARATOR) { 377 start = tokenEnd; 378 token = parseToken(start, end, &tokenEnd); 379 if (token == ARRAY_END) 380 return 0; 381 } else if (token != ARRAY_END) { 382 // Unexpected value after list value. Bail out. 383 return 0; 384 } 385 } 386 if (token != ARRAY_END) 387 return 0; 388 result = array.release(); 389 break; 390 } 391 case OBJECT_BEGIN: { 392 RefPtr<InspectorObject> object = InspectorObject::create(); 393 start = tokenEnd; 394 token = parseToken(start, end, &tokenEnd); 395 while (token != OBJECT_END) { 396 if (token != STRING) 397 return 0; 398 String key; 399 if (!decodeString(start + 1, tokenEnd - 1, &key)) 400 return 0; 401 start = tokenEnd; 402 403 token = parseToken(start, end, &tokenEnd); 404 if (token != OBJECT_PAIR_SEPARATOR) 405 return 0; 406 start = tokenEnd; 407 408 RefPtr<InspectorValue> value = buildValue(start, end, &tokenEnd, depth + 1); 409 if (!value) 410 return 0; 411 object->setValue(key, value); 412 start = tokenEnd; 413 414 // After a key/value pair, we expect a comma or the end of the 415 // object. 416 token = parseToken(start, end, &tokenEnd); 417 if (token == LIST_SEPARATOR) { 418 start = tokenEnd; 419 token = parseToken(start, end, &tokenEnd); 420 if (token == OBJECT_END) 421 return 0; 422 } else if (token != OBJECT_END) { 423 // Unexpected value after last object value. Bail out. 424 return 0; 425 } 426 } 427 if (token != OBJECT_END) 428 return 0; 429 result = object.release(); 430 break; 431 } 432 433 default: 434 // We got a token that's not a value. 435 return 0; 436 } 437 *valueTokenEnd = tokenEnd; 438 return result.release(); 439 } 440 441 inline bool escapeChar(UChar c, Vector<UChar>* dst) 442 { 443 switch (c) { 444 case '\b': dst->append("\\b", 2); break; 445 case '\f': dst->append("\\f", 2); break; 446 case '\n': dst->append("\\n", 2); break; 447 case '\r': dst->append("\\r", 2); break; 448 case '\t': dst->append("\\t", 2); break; 449 case '\\': dst->append("\\\\", 2); break; 450 case '"': dst->append("\\\"", 2); break; 451 default: 452 return false; 453 } 454 return true; 455 } 456 457 inline void doubleQuoteString(const String& str, Vector<UChar>* dst) 458 { 459 dst->append('"'); 460 for (unsigned i = 0; i < str.length(); ++i) { 461 UChar c = str[i]; 462 if (!escapeChar(c, dst)) { 463 if (c < 32 || c > 126 || c == '<' || c == '>') { 464 // 1. Escaping <, > to prevent script execution. 465 // 2. Technically, we could also pass through c > 126 as UTF8, but this 466 // is also optional. It would also be a pain to implement here. 467 unsigned int symbol = static_cast<unsigned int>(c); 468 String symbolCode = String::format("\\u%04X", symbol); 469 dst->append(symbolCode.characters(), symbolCode.length()); 470 } else 471 dst->append(c); 472 } 473 } 474 dst->append('"'); 475 } 476 477 } // anonymous namespace 478 479 bool InspectorValue::asBoolean(bool*) const 480 { 481 return false; 482 } 483 484 bool InspectorValue::asNumber(double*) const 485 { 486 return false; 487 } 488 489 bool InspectorValue::asNumber(long*) const 490 { 491 return false; 492 } 493 494 bool InspectorValue::asNumber(int*) const 495 { 496 return false; 497 } 498 499 bool InspectorValue::asNumber(unsigned long*) const 500 { 501 return false; 502 } 503 504 bool InspectorValue::asNumber(unsigned int*) const 505 { 506 return false; 507 } 508 509 bool InspectorValue::asString(String*) const 510 { 511 return false; 512 } 513 514 bool InspectorValue::asValue(RefPtr<InspectorValue>* output) 515 { 516 *output = this; 517 return true; 518 } 519 520 bool InspectorValue::asObject(RefPtr<InspectorObject>*) 521 { 522 return false; 523 } 524 525 bool InspectorValue::asArray(RefPtr<InspectorArray>*) 526 { 527 return false; 528 } 529 530 PassRefPtr<InspectorObject> InspectorValue::asObject() 531 { 532 return 0; 533 } 534 535 PassRefPtr<InspectorArray> InspectorValue::asArray() 536 { 537 return 0; 538 } 539 540 PassRefPtr<InspectorValue> InspectorValue::parseJSON(const String& json) 541 { 542 const UChar* start = json.characters(); 543 const UChar* end = json.characters() + json.length(); 544 const UChar *tokenEnd; 545 RefPtr<InspectorValue> value = buildValue(start, end, &tokenEnd, 0); 546 if (!value || tokenEnd != end) 547 return 0; 548 return value.release(); 549 } 550 551 String InspectorValue::toJSONString() const 552 { 553 Vector<UChar> result; 554 result.reserveCapacity(512); 555 writeJSON(&result); 556 return String(result.data(), result.size()); 557 } 558 559 void InspectorValue::writeJSON(Vector<UChar>* output) const 560 { 561 ASSERT(m_type == TypeNull); 562 output->append(nullString, 4); 563 } 564 565 bool InspectorBasicValue::asBoolean(bool* output) const 566 { 567 if (type() != TypeBoolean) 568 return false; 569 *output = m_boolValue; 570 return true; 571 } 572 573 bool InspectorBasicValue::asNumber(double* output) const 574 { 575 if (type() != TypeNumber) 576 return false; 577 *output = m_doubleValue; 578 return true; 579 } 580 581 bool InspectorBasicValue::asNumber(long* output) const 582 { 583 if (type() != TypeNumber) 584 return false; 585 *output = static_cast<long>(m_doubleValue); 586 return true; 587 } 588 589 bool InspectorBasicValue::asNumber(int* output) const 590 { 591 if (type() != TypeNumber) 592 return false; 593 *output = static_cast<int>(m_doubleValue); 594 return true; 595 } 596 597 bool InspectorBasicValue::asNumber(unsigned long* output) const 598 { 599 if (type() != TypeNumber) 600 return false; 601 *output = static_cast<unsigned long>(m_doubleValue); 602 return true; 603 } 604 605 bool InspectorBasicValue::asNumber(unsigned int* output) const 606 { 607 if (type() != TypeNumber) 608 return false; 609 *output = static_cast<unsigned int>(m_doubleValue); 610 return true; 611 } 612 613 void InspectorBasicValue::writeJSON(Vector<UChar>* output) const 614 { 615 ASSERT(type() == TypeBoolean || type() == TypeNumber); 616 if (type() == TypeBoolean) { 617 if (m_boolValue) 618 output->append(trueString, 4); 619 else 620 output->append(falseString, 5); 621 } else if (type() == TypeNumber) { 622 NumberToStringBuffer buffer; 623 unsigned length = DecimalNumber(m_doubleValue).toStringDecimal(buffer, WTF::NumberToStringBufferLength); 624 output->append(buffer, length); 625 } 626 } 627 628 bool InspectorString::asString(String* output) const 629 { 630 *output = m_stringValue; 631 return true; 632 } 633 634 void InspectorString::writeJSON(Vector<UChar>* output) const 635 { 636 ASSERT(type() == TypeString); 637 doubleQuoteString(m_stringValue, output); 638 } 639 640 InspectorObject::~InspectorObject() 641 { 642 } 643 644 bool InspectorObject::asObject(RefPtr<InspectorObject>* output) 645 { 646 *output = this; 647 return true; 648 } 649 650 PassRefPtr<InspectorObject> InspectorObject::asObject() 651 { 652 return this; 653 } 654 655 bool InspectorObject::getBoolean(const String& name, bool* output) const 656 { 657 RefPtr<InspectorValue> value = get(name); 658 if (!value) 659 return false; 660 return value->asBoolean(output); 661 } 662 663 bool InspectorObject::getString(const String& name, String* output) const 664 { 665 RefPtr<InspectorValue> value = get(name); 666 if (!value) 667 return false; 668 return value->asString(output); 669 } 670 671 PassRefPtr<InspectorObject> InspectorObject::getObject(const String& name) const 672 { 673 PassRefPtr<InspectorValue> value = get(name); 674 if (!value) 675 return 0; 676 return value->asObject(); 677 } 678 679 PassRefPtr<InspectorArray> InspectorObject::getArray(const String& name) const 680 { 681 PassRefPtr<InspectorValue> value = get(name); 682 if (!value) 683 return 0; 684 return value->asArray(); 685 } 686 687 PassRefPtr<InspectorValue> InspectorObject::get(const String& name) const 688 { 689 Dictionary::const_iterator it = m_data.find(name); 690 if (it == m_data.end()) 691 return 0; 692 return it->second; 693 } 694 695 void InspectorObject::remove(const String& name) 696 { 697 m_data.remove(name); 698 for (size_t i = 0; i < m_order.size(); ++i) { 699 if (m_order[i] == name) { 700 m_order.remove(i); 701 break; 702 } 703 } 704 } 705 706 void InspectorObject::writeJSON(Vector<UChar>* output) const 707 { 708 output->append('{'); 709 for (size_t i = 0; i < m_order.size(); ++i) { 710 Dictionary::const_iterator it = m_data.find(m_order[i]); 711 ASSERT(it != m_data.end()); 712 if (i) 713 output->append(','); 714 doubleQuoteString(it->first, output); 715 output->append(':'); 716 it->second->writeJSON(output); 717 } 718 output->append('}'); 719 } 720 721 InspectorObject::InspectorObject() 722 : InspectorValue(TypeObject) 723 , m_data() 724 , m_order() 725 { 726 } 727 728 InspectorArray::~InspectorArray() 729 { 730 } 731 732 bool InspectorArray::asArray(RefPtr<InspectorArray>* output) 733 { 734 *output = this; 735 return true; 736 } 737 738 PassRefPtr<InspectorArray> InspectorArray::asArray() 739 { 740 return this; 741 } 742 743 void InspectorArray::writeJSON(Vector<UChar>* output) const 744 { 745 output->append('['); 746 for (Vector<RefPtr<InspectorValue> >::const_iterator it = m_data.begin(); it != m_data.end(); ++it) { 747 if (it != m_data.begin()) 748 output->append(','); 749 (*it)->writeJSON(output); 750 } 751 output->append(']'); 752 } 753 754 InspectorArray::InspectorArray() 755 : InspectorValue(TypeArray) 756 , m_data() 757 { 758 } 759 760 PassRefPtr<InspectorValue> InspectorArray::get(size_t index) 761 { 762 ASSERT(index < m_data.size()); 763 return m_data[index]; 764 } 765 766 } // namespace WebCore 767 768 #endif // ENABLE(INSPECTOR) 769