Changeset 60774 in webkit


Ignore:
Timestamp:
Jun 7, 2010 4:33:11 AM (14 years ago)
Author:
eric@webkit.org
Message:

2010-06-07 Pavel Podivilov <podivilov@chromium.org>

Reviewed by Pavel Feldman.

Web Inspector: Implement JSON parsing for InspectorValue.
https://bugs.webkit.org/show_bug.cgi?id=40064

  • inspector/InspectorValues.cpp: (WebCore::): (WebCore::InspectorValue::asBool): (WebCore::InspectorValue::asNumber): (WebCore::InspectorValue::asString): (WebCore::InspectorValue::asObject): (WebCore::InspectorValue::asArray): (WebCore::InspectorValue::readJSON): (WebCore::InspectorValue::writeJSON): (WebCore::InspectorBasicValue::asBool): (WebCore::InspectorBasicValue::asNumber): (WebCore::InspectorBasicValue::writeJSON): (WebCore::InspectorString::asString): (WebCore::InspectorObject::asObject): (WebCore::InspectorObject::getBool): (WebCore::InspectorObject::getNumber): (WebCore::InspectorObject::getString): (WebCore::InspectorObject::getObject): (WebCore::InspectorObject::getArray): (WebCore::InspectorObject::get): (WebCore::InspectorArray::asArray):
  • inspector/InspectorValues.h: (WebCore::InspectorObject::begin): (WebCore::InspectorObject::end):
Location:
trunk/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r60772 r60774  
     12010-06-07  Pavel Podivilov  <podivilov@chromium.org>
     2
     3        Reviewed by Pavel Feldman.
     4
     5        Web Inspector: Implement JSON parsing for InspectorValue.
     6        https://bugs.webkit.org/show_bug.cgi?id=40064
     7
     8        * inspector/InspectorValues.cpp:
     9        (WebCore::):
     10        (WebCore::InspectorValue::asBool):
     11        (WebCore::InspectorValue::asNumber):
     12        (WebCore::InspectorValue::asString):
     13        (WebCore::InspectorValue::asObject):
     14        (WebCore::InspectorValue::asArray):
     15        (WebCore::InspectorValue::readJSON):
     16        (WebCore::InspectorValue::writeJSON):
     17        (WebCore::InspectorBasicValue::asBool):
     18        (WebCore::InspectorBasicValue::asNumber):
     19        (WebCore::InspectorBasicValue::writeJSON):
     20        (WebCore::InspectorString::asString):
     21        (WebCore::InspectorObject::asObject):
     22        (WebCore::InspectorObject::getBool):
     23        (WebCore::InspectorObject::getNumber):
     24        (WebCore::InspectorObject::getString):
     25        (WebCore::InspectorObject::getObject):
     26        (WebCore::InspectorObject::getArray):
     27        (WebCore::InspectorObject::get):
     28        (WebCore::InspectorArray::asArray):
     29        * inspector/InspectorValues.h:
     30        (WebCore::InspectorObject::begin):
     31        (WebCore::InspectorObject::end):
     32
    1332010-06-07  Jocelyn Turcotte  <jocelyn.turcotte@nokia.com>
    234
  • trunk/WebCore/inspector/InspectorValues.cpp

    r60687 r60774  
    3636namespace WebCore {
    3737
     38namespace {
     39
     40static const int stackLimit = 1000;
     41
     42enum Token {
     43    OBJECT_BEGIN,
     44    OBJECT_END,
     45    ARRAY_BEGIN,
     46    ARRAY_END,
     47    STRING,
     48    NUMBER,
     49    BOOL_TRUE,
     50    BOOL_FALSE,
     51    NULL_TOKEN,
     52    LIST_SEPARATOR,
     53    OBJECT_PAIR_SEPARATOR,
     54    INVALID_TOKEN,
     55};
     56   
     57const char* const nullString = "null";
     58const char* const trueString = "true";
     59const char* const falseString = "false";
     60
     61bool parseConstToken(const UChar* start, const UChar* end, const UChar** tokenEnd, const char* token)
     62{
     63    while (start < end && *token != '\0' && *start++ == *token++) { }
     64    if (*token != '\0')
     65        return false;
     66    *tokenEnd = start;
     67    return true;
     68}
     69
     70bool readInt(const UChar* start, const UChar* end, const UChar** tokenEnd, bool canHaveLeadingZeros)
     71{
     72    if (start == end)
     73        return false;
     74    bool haveLeadingZero = '0' == *start;
     75    int length = 0;
     76    while (start < end && '0' <= *start && *start <= '9') {
     77        ++start;
     78        ++length;
     79    }
     80    if (!length)
     81        return false;
     82    if (!canHaveLeadingZeros && length > 1 && haveLeadingZero)
     83        return false;
     84    *tokenEnd = start;
     85    return true;
     86}
     87
     88bool parseNumberToken(const UChar* start, const UChar* end, const UChar** tokenEnd)
     89{
     90    // We just grab the number here.  We validate the size in DecodeNumber.
     91    // According   to RFC4627, a valid number is: [minus] int [frac] [exp]
     92    if (start == end)
     93        return false;
     94    UChar c = *start;
     95    if ('-' == c)
     96        ++start;
     97
     98    if (!readInt(start, end, &start, false))
     99        return false;
     100    if (start == end) {
     101        *tokenEnd = start;
     102        return true;
     103    }
     104
     105    // Optional fraction part
     106    c = *start;
     107    if ('.' == c) {
     108        ++start;
     109        if (!readInt(start, end, &start, true))
     110            return false;
     111        if (start == end) {
     112            *tokenEnd = start;
     113            return true;
     114        }
     115        c = *start;
     116    }
     117
     118    // Optional exponent part
     119    if ('e' == c || 'E' == c) {
     120        ++start;
     121        if (start == end)
     122            return false;
     123        c = *start;
     124        if ('-' == c || '+' == c) {
     125            ++start;
     126            if (start == end)
     127                return false;
     128        }
     129        if (!readInt(start, end, &start, true))
     130            return false;
     131    }
     132
     133    *tokenEnd = start;
     134    return true;
     135}
     136
     137bool readHexDigits(const UChar* start, const UChar* end, const UChar** tokenEnd, int digits)
     138{
     139    if (end - start < digits)
     140        return false;
     141    for (int i = 0; i < digits; ++i) {
     142        UChar c = *start++;
     143        if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')))
     144            return false;
     145    }
     146    *tokenEnd = start;
     147    return true;
     148}
     149
     150bool parseStringToken(const UChar* start, const UChar* end, const UChar** tokenEnd)
     151{
     152    while (start < end) {
     153        UChar c = *start++;
     154        if ('\\' == c) {
     155            c = *start++;
     156            // Make sure the escaped char is valid.
     157            switch (c) {
     158            case 'x':
     159                if (!readHexDigits(start, end, &start, 2))
     160                    return false;
     161                break;
     162            case 'u':
     163                if (!readHexDigits(start, end, &start, 4))
     164                    return false;
     165                break;
     166            case '\\':
     167            case '/':
     168            case 'b':
     169            case 'f':
     170            case 'n':
     171            case 'r':
     172            case 't':
     173            case 'v':
     174            case '"':
     175                break;
     176            default:
     177                return false;
     178            }
     179        } else if ('"' == c) {
     180            *tokenEnd = start;
     181            return true;
     182        }
     183    }
     184    return false;
     185}
     186
     187Token parseToken(const UChar* start, const UChar* end, const UChar** tokenEnd)
     188{
     189    if (start == end)
     190        return INVALID_TOKEN;
     191
     192    switch (*start) {
     193    case 'n':
     194        if (parseConstToken(start, end, tokenEnd, nullString))
     195            return NULL_TOKEN;
     196        break;
     197    case 't':
     198        if (parseConstToken(start, end, tokenEnd, trueString))
     199            return BOOL_TRUE;
     200        break;
     201    case 'f':
     202        if (parseConstToken(start, end, tokenEnd, falseString))
     203            return BOOL_FALSE;
     204        break;
     205    case '[':
     206        *tokenEnd = start + 1;
     207        return ARRAY_BEGIN;
     208    case ']':
     209        *tokenEnd = start + 1;
     210        return ARRAY_END;
     211    case ',':
     212        *tokenEnd = start + 1;
     213        return LIST_SEPARATOR;
     214    case '{':
     215        *tokenEnd = start + 1;
     216        return OBJECT_BEGIN;
     217    case '}':
     218        *tokenEnd = start + 1;
     219        return OBJECT_END;
     220    case ':':
     221        *tokenEnd = start + 1;
     222        return OBJECT_PAIR_SEPARATOR;
     223    case '0':
     224    case '1':
     225    case '2':
     226    case '3':
     227    case '4':
     228    case '5':
     229    case '6':
     230    case '7':
     231    case '8':
     232    case '9':
     233    case '-':
     234        if (parseNumberToken(start, end, tokenEnd))
     235            return NUMBER;
     236        break;           
     237    case '"':
     238        if (parseStringToken(start + 1, end, tokenEnd))
     239            return STRING;
     240        break;
     241    }
     242    return INVALID_TOKEN;
     243}
     244
     245inline int hexToInt(UChar c)
     246{
     247    if ('0' <= c && c <= '9')
     248        return c - '0';
     249    if ('A' <= c && c <= 'F')
     250        return c - 'A' + 10;
     251    if ('a' <= c && c <= 'f')
     252        return c - 'a' + 10;
     253    ASSERT_NOT_REACHED();
     254    return 0;
     255}
     256
     257bool decodeString(const UChar* start, const UChar* end, Vector<UChar>* output)
     258{
     259    while (start < end) {
     260        UChar c = *start++;
     261        if ('\\' != c) {
     262            output->append(c);
     263            continue;
     264        }
     265        c = *start++;
     266        switch (c) {
     267        case '"':
     268        case '/':
     269        case '\\':
     270            break;
     271        case 'b':
     272            c = '\b';
     273            break;
     274        case 'f':
     275            c = '\f';
     276            break;
     277        case 'n':
     278            c = '\n';
     279            break;
     280        case 'r':
     281            c = '\r';
     282            break;
     283        case 't':
     284            c = '\t';
     285            break;
     286        case 'v':
     287            c = '\v';
     288            break;
     289        case 'x':
     290            c = (hexToInt(*start) << 4) +
     291                hexToInt(*(start + 1));
     292            start += 2;
     293            break;
     294        case 'u':
     295            c = (hexToInt(*start) << 12) +
     296                (hexToInt(*(start + 1)) << 8) +
     297                (hexToInt(*(start + 2)) << 4) +
     298                hexToInt(*(start + 3));
     299            start += 4;
     300            break;
     301        default:
     302            return false;
     303        }
     304        output->append(c);
     305    }
     306    return true;
     307}
     308
     309bool decodeString(const UChar* start, const UChar* end, String* output)
     310{
     311    if (start == end) {
     312        *output = "";
     313        return true;
     314    }
     315    if (start > end)
     316        return false;
     317    Vector<UChar> buffer;
     318    buffer.reserveCapacity(end - start);
     319    if (!decodeString(start, end, &buffer))
     320        return false;
     321    *output = String(buffer.data(), buffer.size());   
     322    return true;
     323}
     324
     325PassRefPtr<InspectorValue> buildValue(const UChar* start, const UChar* end, const UChar** valueTokenEnd, int depth)
     326{
     327    if (depth > stackLimit)
     328        return 0;
     329
     330    RefPtr<InspectorValue> result;
     331    const UChar* tokenEnd;
     332    Token token = parseToken(start, end, &tokenEnd);
     333    switch (token) {
     334    case INVALID_TOKEN:
     335        return 0;
     336    case NULL_TOKEN:
     337        result = InspectorValue::null();
     338        break;
     339    case BOOL_TRUE:
     340        result = InspectorBasicValue::create(true);
     341        break;
     342    case BOOL_FALSE:
     343        result = InspectorBasicValue::create(false);
     344        break;
     345    case NUMBER: {
     346        bool ok;
     347        double value = charactersToDouble(start, tokenEnd - start, &ok);
     348        if (!ok)
     349            return 0;
     350        result = InspectorBasicValue::create(value);
     351        break;
     352    }
     353    case STRING: {
     354        String value;
     355        bool ok = decodeString(start + 1, tokenEnd - 1, &value);
     356        if (!ok)
     357            return 0;
     358        result = InspectorString::create(value);
     359        break;
     360    }
     361    case ARRAY_BEGIN: {
     362        RefPtr<InspectorArray> array = InspectorArray::create();
     363        start = tokenEnd;
     364        token = parseToken(start, end, &tokenEnd);
     365        while (token != ARRAY_END) {
     366            RefPtr<InspectorValue> arrayNode = buildValue(start, end, &tokenEnd, depth + 1);
     367            if (!arrayNode)
     368                return 0;
     369            array->push(arrayNode);
     370
     371            // After a list value, we expect a comma or the end of the list.
     372            start = tokenEnd;
     373            token = parseToken(start, end, &tokenEnd);
     374            if (token == LIST_SEPARATOR) {
     375                start = tokenEnd;
     376                token = parseToken(start, end, &tokenEnd);
     377                if (token == ARRAY_END)
     378                    return 0;
     379            } else if (token != ARRAY_END) {
     380                // Unexpected value after list value.  Bail out.
     381                return 0;
     382            }
     383        }
     384        if (token != ARRAY_END)
     385            return 0;
     386        result = array.release();
     387        break;
     388    }
     389    case OBJECT_BEGIN: {
     390        RefPtr<InspectorObject> object = InspectorObject::create();
     391        start = tokenEnd;
     392        token = parseToken(start, end, &tokenEnd);
     393        while (token != OBJECT_END) {
     394            if (token != STRING)
     395                return 0;
     396            String key;
     397            if (!decodeString(start + 1, tokenEnd - 1, &key))
     398                return 0;
     399            start = tokenEnd;
     400
     401            token = parseToken(start, end, &tokenEnd);
     402            if (token != OBJECT_PAIR_SEPARATOR)
     403                return 0;
     404            start = tokenEnd;
     405
     406            RefPtr<InspectorValue> value = buildValue(start, end, &tokenEnd, depth + 1);
     407            if (!value)
     408                return 0;
     409            object->set(key, value);
     410            start = tokenEnd;
     411
     412            // After a key/value pair, we expect a comma or the end of the
     413            // object.
     414            token = parseToken(start, end, &tokenEnd);
     415            if (token == LIST_SEPARATOR) {
     416                start = tokenEnd;
     417                token = parseToken(start, end, &tokenEnd);
     418                 if (token == OBJECT_END)
     419                    return 0;
     420            } else if (token != OBJECT_END) {
     421                // Unexpected value after last object value.  Bail out.
     422                return 0;
     423            }
     424        }
     425        if (token != OBJECT_END)
     426            return 0;
     427        result = object.release();
     428        break;
     429    }
     430
     431    default:
     432        // We got a token that's not a value.
     433        return 0;
     434    }
     435    *valueTokenEnd = tokenEnd;
     436    return result.release();
     437}
     438
    38439inline bool escapeChar(UChar c, Vector<UChar>* dst)
    39440{
     
    72473}
    73474
     475} // anonymous namespace
     476
     477bool InspectorValue::asBool(bool*) const
     478{
     479    return false;
     480}
     481
     482bool InspectorValue::asNumber(double*) const
     483{
     484    return false;
     485}
     486
     487bool InspectorValue::asString(String*) const
     488{
     489    return false;
     490}
     491
     492PassRefPtr<InspectorObject> InspectorValue::asObject()
     493{
     494    return 0;
     495}
     496
     497PassRefPtr<InspectorArray> InspectorValue::asArray()
     498{
     499    return 0;
     500}
     501
     502PassRefPtr<InspectorValue> InspectorValue::readJSON(const String& json)
     503{
     504    const UChar* start = json.characters();
     505    const UChar* end = json.characters() + json.length();
     506    const UChar *tokenEnd;
     507    RefPtr<InspectorValue> value = buildValue(start, end, &tokenEnd, 0);
     508    if (!value || tokenEnd != end)
     509        return 0;
     510    return value.release();
     511}
     512
    74513String InspectorValue::toJSONString() const
    75514{
     
    83522{
    84523    ASSERT(m_type == TypeNull);
    85     output->append("null", 4);
     524    output->append(nullString, 4);
     525}
     526
     527bool InspectorBasicValue::asBool(bool* output) const
     528{
     529    if (type() != TypeBoolean)
     530        return false;
     531    *output = m_boolValue;
     532    return true;
     533}
     534
     535bool InspectorBasicValue::asNumber(double* output) const
     536{
     537    if (type() != TypeDouble)
     538        return false;
     539    *output = m_doubleValue;
     540    return true;
    86541}
    87542
     
    91546    if (type() == TypeBoolean) {
    92547        if (m_boolValue)
    93             output->append("true", 4);
     548            output->append(trueString, 4);
    94549        else
    95             output->append("false", 5);
     550            output->append(falseString, 5);
    96551    } else if (type() == TypeDouble) {
    97552        String value = String::format("%f", m_doubleValue);
     
    100555}
    101556
     557bool InspectorString::asString(String* output) const
     558{
     559    *output = m_stringValue;
     560    return true;
     561}
     562
    102563void InspectorString::writeJSON(Vector<UChar>* output) const
    103564{
    104565    ASSERT(type() == TypeString);
    105566    doubleQuoteString(m_stringValue, output);
     567}
     568
     569PassRefPtr<InspectorObject> InspectorObject::asObject()
     570{
     571    return this;
     572}
     573
     574bool InspectorObject::getBool(const String& name, bool* output) const
     575{
     576    RefPtr<InspectorValue> value = get(name);
     577    if (!value)
     578        return false;
     579    return value->asBool(output);
     580}
     581
     582bool InspectorObject::getNumber(const String& name, double* output) const
     583{
     584    RefPtr<InspectorValue> value = get(name);
     585    if (!value)
     586        return false;
     587    return value->asNumber(output);
     588}
     589
     590bool InspectorObject::getString(const String& name, String* output) const
     591{
     592    RefPtr<InspectorValue> value = get(name);
     593    if (!value)
     594        return false;
     595    return value->asString(output);
     596}
     597
     598PassRefPtr<InspectorObject> InspectorObject::getObject(const String& name) const
     599{
     600    PassRefPtr<InspectorValue> value = get(name);
     601    if (!value)
     602        return false;
     603    return value->asObject();
     604}
     605
     606PassRefPtr<InspectorArray> InspectorObject::getArray(const String& name) const
     607{
     608    PassRefPtr<InspectorValue> value = get(name);
     609    if (!value)
     610        return false;
     611    return value->asArray();
     612}
     613
     614PassRefPtr<InspectorValue> InspectorObject::get(const String& name) const
     615{
     616    Dictionary::const_iterator it = m_data.find(name);
     617    if (it == m_data.end())
     618        return 0;
     619    return it->second;
    106620}
    107621
     
    121635}
    122636
     637PassRefPtr<InspectorArray> InspectorArray::asArray()
     638{
     639    return this;
     640}
     641
    123642void InspectorArray::writeJSON(Vector<UChar>* output) const
    124643{
  • trunk/WebCore/inspector/InspectorValues.h

    r60687 r60774  
    4343namespace WebCore {
    4444
     45class InspectorArray;
     46class InspectorObject;
    4547class String;
    4648
     
    6668    Type type() const { return m_type; }
    6769
     70    virtual bool asBool(bool* output) const;
     71    virtual bool asNumber(double* output) const;
     72    virtual bool asString(String* output) const;
     73    virtual PassRefPtr<InspectorObject> asObject();
     74    virtual PassRefPtr<InspectorArray> asArray();
     75
     76    static PassRefPtr<InspectorValue> readJSON(const String& json);
     77
    6878    String toJSONString() const;
    6979    virtual void writeJSON(Vector<UChar>* output) const;
     
    93103        return adoptRef(new InspectorBasicValue(value));
    94104    }
     105
     106    virtual bool asBool(bool* output) const;
     107    virtual bool asNumber(double* output) const;
    95108
    96109    virtual void writeJSON(Vector<UChar>* output) const;
     
    118131        return adoptRef(new InspectorString(value));
    119132    }
     133
     134    virtual bool asString(String* output) const;   
     135
    120136    virtual void writeJSON(Vector<UChar>* output) const;
    121137
     
    128144
    129145class InspectorObject : public InspectorValue {
     146private:
     147    typedef HashMap<String, RefPtr<InspectorValue> > Dictionary;
     148
     149public:
     150    typedef Dictionary::iterator iterator;
     151    typedef Dictionary::const_iterator const_iterator;
     152
    130153public:
    131154    static PassRefPtr<InspectorObject> create()
     
    134157    }
    135158    ~InspectorObject() { }
     159
     160    virtual PassRefPtr<InspectorObject> asObject();
    136161
    137162    void setBool(const String& name, bool);
     
    140165    void set(const String& name, PassRefPtr<InspectorValue>);
    141166
    142     virtual void writeJSON(Vector<UChar>* output) const;
     167    bool getBool(const String& name, bool* output) const;
     168    bool getNumber(const String& name, double* output) const;
     169    bool getString(const String& name, String* output) const;
     170    PassRefPtr<InspectorObject> getObject(const String& name) const;
     171    PassRefPtr<InspectorArray> getArray(const String& name) const;
     172    PassRefPtr<InspectorValue> get(const String& name) const;
     173
     174    virtual void writeJSON(Vector<UChar>* output) const;
     175
     176    iterator begin() { return m_data.begin(); }
     177    iterator end() { return m_data.end(); }
     178    const_iterator begin() const { return m_data.begin(); }
     179    const_iterator end() const { return m_data.end(); }
    143180
    144181private:
    145182    InspectorObject() : InspectorValue(TypeObject) { }
    146     typedef HashMap<String, RefPtr<InspectorValue> > Dictionary;
    147183    Dictionary m_data;
    148184    Vector<String> m_order;
     
    156192    }
    157193    ~InspectorArray() { }
     194
     195    virtual PassRefPtr<InspectorArray> asArray();
    158196
    159197    void pushBool(bool);
     
    215253#endif // ENABLE(INSPECTOR)
    216254#endif // !defined(InspectorValues_h)
    217 
Note: See TracChangeset for help on using the changeset viewer.