d1b8093541a187a5782185ef734256f7dd40ac77
[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(unsigned long*) const
495 {
496     return false;
497 }
498
499 bool InspectorValue::asNumber(unsigned int*) const
500 {
501     return false;
502 }
503
504 bool InspectorValue::asString(String*) const
505 {
506     return false;
507 }
508
509 bool InspectorValue::asValue(RefPtr<InspectorValue>* output)
510 {
511     *output = this;
512     return true;
513 }
514
515 bool InspectorValue::asObject(RefPtr<InspectorObject>*)
516 {
517     return false;
518 }
519
520 bool InspectorValue::asArray(RefPtr<InspectorArray>*)
521 {
522     return false;
523 }
524
525 PassRefPtr<InspectorObject> InspectorValue::asObject()
526 {
527     return 0;
528 }
529
530 PassRefPtr<InspectorArray> InspectorValue::asArray()
531 {
532     return 0;
533 }
534
535 PassRefPtr<InspectorValue> InspectorValue::parseJSON(const String& json)
536 {
537     const UChar* start = json.characters();
538     const UChar* end = json.characters() + json.length();
539     const UChar *tokenEnd;
540     RefPtr<InspectorValue> value = buildValue(start, end, &tokenEnd, 0);
541     if (!value || tokenEnd != end)
542         return 0;
543     return value.release();
544 }
545
546 String InspectorValue::toJSONString() const
547 {
548     Vector<UChar> result;
549     result.reserveCapacity(512);
550     writeJSON(&result);
551     return String(result.data(), result.size());
552 }
553
554 void InspectorValue::writeJSON(Vector<UChar>* output) const
555 {
556     ASSERT(m_type == TypeNull);
557     output->append(nullString, 4);
558 }
559
560 bool InspectorBasicValue::asBoolean(bool* output) const
561 {
562     if (type() != TypeBoolean)
563         return false;
564     *output = m_boolValue;
565     return true;
566 }
567
568 bool InspectorBasicValue::asNumber(double* output) const
569 {
570     if (type() != TypeNumber)
571         return false;
572     *output = m_doubleValue;
573     return true;
574 }
575
576 bool InspectorBasicValue::asNumber(long* output) const
577 {
578     if (type() != TypeNumber)
579         return false;
580     *output = static_cast<long>(m_doubleValue);
581     return true;
582 }
583
584 bool InspectorBasicValue::asNumber(unsigned long* output) const
585 {
586     if (type() != TypeNumber)
587         return false;
588     *output = static_cast<unsigned long>(m_doubleValue);
589     return true;
590 }
591
592 bool InspectorBasicValue::asNumber(unsigned int* output) const
593 {
594     if (type() != TypeNumber)
595         return false;
596     *output = static_cast<unsigned int>(m_doubleValue);
597     return true;
598 }
599
600 void InspectorBasicValue::writeJSON(Vector<UChar>* output) const
601 {
602     ASSERT(type() == TypeBoolean || type() == TypeNumber);
603     if (type() == TypeBoolean) {
604         if (m_boolValue)
605             output->append(trueString, 4);
606         else
607             output->append(falseString, 5);
608     } else if (type() == TypeNumber) {
609         NumberToStringBuffer buffer;
610         unsigned length = DecimalNumber(m_doubleValue).toStringDecimal(buffer, WTF::NumberToStringBufferLength);
611         output->append(buffer, length);
612     }
613 }
614
615 bool InspectorString::asString(String* output) const
616 {
617     *output = m_stringValue;
618     return true;
619 }
620
621 void InspectorString::writeJSON(Vector<UChar>* output) const
622 {
623     ASSERT(type() == TypeString);
624     doubleQuoteString(m_stringValue, output);
625 }
626
627 InspectorObject::~InspectorObject()
628 {
629 }
630
631 bool InspectorObject::asObject(RefPtr<InspectorObject>* output)
632 {
633     *output = this;
634     return true;
635 }
636
637 PassRefPtr<InspectorObject> InspectorObject::asObject()
638 {
639     return this;
640 }
641
642 bool InspectorObject::getBoolean(const String& name, bool* output) const
643 {
644     RefPtr<InspectorValue> value = get(name);
645     if (!value)
646         return false;
647     return value->asBoolean(output);
648 }
649
650 bool InspectorObject::getNumber(const String& name, long* output) const
651 {
652     RefPtr<InspectorValue> value = get(name);
653     if (!value)
654         return false;
655     return value->asNumber(output);
656 }
657
658 bool InspectorObject::getNumber(const String& name, double* output) const
659 {
660     RefPtr<InspectorValue> value = get(name);
661     if (!value)
662         return false;
663     return value->asNumber(output);
664 }
665
666 bool InspectorObject::getString(const String& name, String* output) const
667 {
668     RefPtr<InspectorValue> value = get(name);
669     if (!value)
670         return false;
671     return value->asString(output);
672 }
673
674 PassRefPtr<InspectorObject> InspectorObject::getObject(const String& name) const
675 {
676     PassRefPtr<InspectorValue> value = get(name);
677     if (!value)
678         return 0;
679     return value->asObject();
680 }
681
682 PassRefPtr<InspectorArray> InspectorObject::getArray(const String& name) const
683 {
684     PassRefPtr<InspectorValue> value = get(name);
685     if (!value)
686         return 0;
687     return value->asArray();
688 }
689
690 PassRefPtr<InspectorValue> InspectorObject::get(const String& name) const
691 {
692     Dictionary::const_iterator it = m_data.find(name);
693     if (it == m_data.end())
694         return 0;
695     return it->second;
696 }
697
698 void InspectorObject::writeJSON(Vector<UChar>* output) const
699 {
700     output->append('{');
701     for (size_t i = 0; i < m_order.size(); ++i) {
702         Dictionary::const_iterator it = m_data.find(m_order[i]);
703         ASSERT(it != m_data.end());
704         if (i)
705             output->append(',');
706         doubleQuoteString(it->first, output);
707         output->append(':');
708         it->second->writeJSON(output);
709     }
710     output->append('}');
711 }
712
713 InspectorObject::InspectorObject()
714     : InspectorValue(TypeObject)
715     , m_data()
716     , m_order()
717 {
718 }
719
720 InspectorArray::~InspectorArray()
721 {
722 }
723
724 bool InspectorArray::asArray(RefPtr<InspectorArray>* output)
725 {
726     *output = this;
727     return true;
728 }
729
730 PassRefPtr<InspectorArray> InspectorArray::asArray()
731 {
732     return this;
733 }
734
735 void InspectorArray::writeJSON(Vector<UChar>* output) const
736 {
737     output->append('[');
738     for (Vector<RefPtr<InspectorValue> >::const_iterator it = m_data.begin(); it != m_data.end(); ++it) {
739         if (it != m_data.begin())
740             output->append(',');
741         (*it)->writeJSON(output);
742     }
743     output->append(']');
744 }
745
746 InspectorArray::InspectorArray()
747     : InspectorValue(TypeArray)
748     , m_data()
749 {
750 }
751
752 PassRefPtr<InspectorValue> InspectorArray::get(size_t index)
753 {
754     ASSERT(index < m_data.size());
755     return m_data[index];
756 }
757
758 } // namespace WebCore
759
760 #endif // ENABLE(INSPECTOR)