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
parseConstToken(const UChar * start,const UChar * end,const UChar ** tokenEnd,const char * token)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
readInt(const UChar * start,const UChar * end,const UChar ** tokenEnd,bool canHaveLeadingZeros)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
parseNumberToken(const UChar * start,const UChar * end,const UChar ** tokenEnd)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
readHexDigits(const UChar * start,const UChar * end,const UChar ** tokenEnd,int digits)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
parseStringToken(const UChar * start,const UChar * end,const UChar ** tokenEnd)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
parseToken(const UChar * start,const UChar * end,const UChar ** tokenEnd)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
hexToInt(UChar c)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
decodeString(const UChar * start,const UChar * end,Vector<UChar> * output)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
decodeString(const UChar * start,const UChar * end,String * output)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
buildValue(const UChar * start,const UChar * end,const UChar ** valueTokenEnd,int depth)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
escapeChar(UChar c,Vector<UChar> * dst)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
doubleQuoteString(const String & str,Vector<UChar> * dst)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
asBoolean(bool *) const479 bool InspectorValue::asBoolean(bool*) const
480 {
481 return false;
482 }
483
asNumber(double *) const484 bool InspectorValue::asNumber(double*) const
485 {
486 return false;
487 }
488
asNumber(long *) const489 bool InspectorValue::asNumber(long*) const
490 {
491 return false;
492 }
493
asNumber(int *) const494 bool InspectorValue::asNumber(int*) const
495 {
496 return false;
497 }
498
asNumber(unsigned long *) const499 bool InspectorValue::asNumber(unsigned long*) const
500 {
501 return false;
502 }
503
asNumber(unsigned int *) const504 bool InspectorValue::asNumber(unsigned int*) const
505 {
506 return false;
507 }
508
asString(String *) const509 bool InspectorValue::asString(String*) const
510 {
511 return false;
512 }
513
asValue(RefPtr<InspectorValue> * output)514 bool InspectorValue::asValue(RefPtr<InspectorValue>* output)
515 {
516 *output = this;
517 return true;
518 }
519
asObject(RefPtr<InspectorObject> *)520 bool InspectorValue::asObject(RefPtr<InspectorObject>*)
521 {
522 return false;
523 }
524
asArray(RefPtr<InspectorArray> *)525 bool InspectorValue::asArray(RefPtr<InspectorArray>*)
526 {
527 return false;
528 }
529
asObject()530 PassRefPtr<InspectorObject> InspectorValue::asObject()
531 {
532 return 0;
533 }
534
asArray()535 PassRefPtr<InspectorArray> InspectorValue::asArray()
536 {
537 return 0;
538 }
539
parseJSON(const String & json)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
toJSONString() const551 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
writeJSON(Vector<UChar> * output) const559 void InspectorValue::writeJSON(Vector<UChar>* output) const
560 {
561 ASSERT(m_type == TypeNull);
562 output->append(nullString, 4);
563 }
564
asBoolean(bool * output) const565 bool InspectorBasicValue::asBoolean(bool* output) const
566 {
567 if (type() != TypeBoolean)
568 return false;
569 *output = m_boolValue;
570 return true;
571 }
572
asNumber(double * output) const573 bool InspectorBasicValue::asNumber(double* output) const
574 {
575 if (type() != TypeNumber)
576 return false;
577 *output = m_doubleValue;
578 return true;
579 }
580
asNumber(long * output) const581 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
asNumber(int * output) const589 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
asNumber(unsigned long * output) const597 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
asNumber(unsigned int * output) const605 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
writeJSON(Vector<UChar> * output) const613 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 DecimalNumber decimal = m_doubleValue;
624 unsigned length = 0;
625 if (decimal.bufferLengthForStringDecimal() > WTF::NumberToStringBufferLength) {
626 // Not enough room for decimal. Use exponential format.
627 if (decimal.bufferLengthForStringExponential() > WTF::NumberToStringBufferLength) {
628 // Fallback for an abnormal case if it's too little even for exponential.
629 output->append("NaN", 3);
630 return;
631 }
632 length = decimal.toStringExponential(buffer, WTF::NumberToStringBufferLength);
633 } else
634 length = decimal.toStringDecimal(buffer, WTF::NumberToStringBufferLength);
635 output->append(buffer, length);
636 }
637 }
638
asString(String * output) const639 bool InspectorString::asString(String* output) const
640 {
641 *output = m_stringValue;
642 return true;
643 }
644
writeJSON(Vector<UChar> * output) const645 void InspectorString::writeJSON(Vector<UChar>* output) const
646 {
647 ASSERT(type() == TypeString);
648 doubleQuoteString(m_stringValue, output);
649 }
650
~InspectorObject()651 InspectorObject::~InspectorObject()
652 {
653 }
654
asObject(RefPtr<InspectorObject> * output)655 bool InspectorObject::asObject(RefPtr<InspectorObject>* output)
656 {
657 *output = this;
658 return true;
659 }
660
asObject()661 PassRefPtr<InspectorObject> InspectorObject::asObject()
662 {
663 return this;
664 }
665
getBoolean(const String & name,bool * output) const666 bool InspectorObject::getBoolean(const String& name, bool* output) const
667 {
668 RefPtr<InspectorValue> value = get(name);
669 if (!value)
670 return false;
671 return value->asBoolean(output);
672 }
673
getString(const String & name,String * output) const674 bool InspectorObject::getString(const String& name, String* output) const
675 {
676 RefPtr<InspectorValue> value = get(name);
677 if (!value)
678 return false;
679 return value->asString(output);
680 }
681
getObject(const String & name) const682 PassRefPtr<InspectorObject> InspectorObject::getObject(const String& name) const
683 {
684 PassRefPtr<InspectorValue> value = get(name);
685 if (!value)
686 return 0;
687 return value->asObject();
688 }
689
getArray(const String & name) const690 PassRefPtr<InspectorArray> InspectorObject::getArray(const String& name) const
691 {
692 PassRefPtr<InspectorValue> value = get(name);
693 if (!value)
694 return 0;
695 return value->asArray();
696 }
697
get(const String & name) const698 PassRefPtr<InspectorValue> InspectorObject::get(const String& name) const
699 {
700 Dictionary::const_iterator it = m_data.find(name);
701 if (it == m_data.end())
702 return 0;
703 return it->second;
704 }
705
remove(const String & name)706 void InspectorObject::remove(const String& name)
707 {
708 m_data.remove(name);
709 for (size_t i = 0; i < m_order.size(); ++i) {
710 if (m_order[i] == name) {
711 m_order.remove(i);
712 break;
713 }
714 }
715 }
716
writeJSON(Vector<UChar> * output) const717 void InspectorObject::writeJSON(Vector<UChar>* output) const
718 {
719 output->append('{');
720 for (size_t i = 0; i < m_order.size(); ++i) {
721 Dictionary::const_iterator it = m_data.find(m_order[i]);
722 ASSERT(it != m_data.end());
723 if (i)
724 output->append(',');
725 doubleQuoteString(it->first, output);
726 output->append(':');
727 it->second->writeJSON(output);
728 }
729 output->append('}');
730 }
731
InspectorObject()732 InspectorObject::InspectorObject()
733 : InspectorValue(TypeObject)
734 , m_data()
735 , m_order()
736 {
737 }
738
~InspectorArray()739 InspectorArray::~InspectorArray()
740 {
741 }
742
asArray(RefPtr<InspectorArray> * output)743 bool InspectorArray::asArray(RefPtr<InspectorArray>* output)
744 {
745 *output = this;
746 return true;
747 }
748
asArray()749 PassRefPtr<InspectorArray> InspectorArray::asArray()
750 {
751 return this;
752 }
753
writeJSON(Vector<UChar> * output) const754 void InspectorArray::writeJSON(Vector<UChar>* output) const
755 {
756 output->append('[');
757 for (Vector<RefPtr<InspectorValue> >::const_iterator it = m_data.begin(); it != m_data.end(); ++it) {
758 if (it != m_data.begin())
759 output->append(',');
760 (*it)->writeJSON(output);
761 }
762 output->append(']');
763 }
764
InspectorArray()765 InspectorArray::InspectorArray()
766 : InspectorValue(TypeArray)
767 , m_data()
768 {
769 }
770
get(size_t index)771 PassRefPtr<InspectorValue> InspectorArray::get(size_t index)
772 {
773 ASSERT(index < m_data.size());
774 return m_data[index];
775 }
776
777 } // namespace WebCore
778
779 #endif // ENABLE(INSPECTOR)
780