Home | History | Annotate | Download | only in inspector
      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