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
38namespace WebCore {
39
40namespace {
41
42static const int stackLimit = 1000;
43
44enum 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
59const char* const nullString = "null";
60const char* const trueString = "true";
61const char* const falseString = "false";
62
63bool 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
72bool 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
90bool 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
139bool 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
152bool 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
189Token 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
247inline 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
259bool 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
311bool 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
327PassRefPtr<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
441inline 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
457inline 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
479bool InspectorValue::asBoolean(bool*) const
480{
481    return false;
482}
483
484bool InspectorValue::asNumber(double*) const
485{
486    return false;
487}
488
489bool InspectorValue::asNumber(long*) const
490{
491    return false;
492}
493
494bool InspectorValue::asNumber(int*) const
495{
496    return false;
497}
498
499bool InspectorValue::asNumber(unsigned long*) const
500{
501    return false;
502}
503
504bool InspectorValue::asNumber(unsigned int*) const
505{
506    return false;
507}
508
509bool InspectorValue::asString(String*) const
510{
511    return false;
512}
513
514bool InspectorValue::asValue(RefPtr<InspectorValue>* output)
515{
516    *output = this;
517    return true;
518}
519
520bool InspectorValue::asObject(RefPtr<InspectorObject>*)
521{
522    return false;
523}
524
525bool InspectorValue::asArray(RefPtr<InspectorArray>*)
526{
527    return false;
528}
529
530PassRefPtr<InspectorObject> InspectorValue::asObject()
531{
532    return 0;
533}
534
535PassRefPtr<InspectorArray> InspectorValue::asArray()
536{
537    return 0;
538}
539
540PassRefPtr<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
551String InspectorValue::toJSONString() const
552{
553    Vector<UChar> result;
554    result.reserveCapacity(512);
555    writeJSON(&result);
556    return String(result.data(), result.size());
557}
558
559void InspectorValue::writeJSON(Vector<UChar>* output) const
560{
561    ASSERT(m_type == TypeNull);
562    output->append(nullString, 4);
563}
564
565bool InspectorBasicValue::asBoolean(bool* output) const
566{
567    if (type() != TypeBoolean)
568        return false;
569    *output = m_boolValue;
570    return true;
571}
572
573bool InspectorBasicValue::asNumber(double* output) const
574{
575    if (type() != TypeNumber)
576        return false;
577    *output = m_doubleValue;
578    return true;
579}
580
581bool 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
589bool 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
597bool 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
605bool 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
613void 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
628bool InspectorString::asString(String* output) const
629{
630    *output = m_stringValue;
631    return true;
632}
633
634void InspectorString::writeJSON(Vector<UChar>* output) const
635{
636    ASSERT(type() == TypeString);
637    doubleQuoteString(m_stringValue, output);
638}
639
640InspectorObject::~InspectorObject()
641{
642}
643
644bool InspectorObject::asObject(RefPtr<InspectorObject>* output)
645{
646    *output = this;
647    return true;
648}
649
650PassRefPtr<InspectorObject> InspectorObject::asObject()
651{
652    return this;
653}
654
655bool 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
663bool 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
671PassRefPtr<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
679PassRefPtr<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
687PassRefPtr<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
695void 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
706void 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
721InspectorObject::InspectorObject()
722    : InspectorValue(TypeObject)
723    , m_data()
724    , m_order()
725{
726}
727
728InspectorArray::~InspectorArray()
729{
730}
731
732bool InspectorArray::asArray(RefPtr<InspectorArray>* output)
733{
734    *output = this;
735    return true;
736}
737
738PassRefPtr<InspectorArray> InspectorArray::asArray()
739{
740    return this;
741}
742
743void 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
754InspectorArray::InspectorArray()
755    : InspectorValue(TypeArray)
756    , m_data()
757{
758}
759
760PassRefPtr<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