2011-02-01 Pavel Podivilov <podivilov@chromium.org>
[WebKit-https.git] / Source / WebCore / inspector / InspectorValues.cpp
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)