2 * Copyright (C) 2010 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
32 #include "InspectorValues.h"
34 #include <wtf/DecimalNumber.h>
36 #include <wtf/text/StringBuilder.h>
42 static const int stackLimit
= 1000;
55 OBJECT_PAIR_SEPARATOR
,
59 const char* const nullString
= "null";
60 const char* const trueString
= "true";
61 const char* const falseString
= "false";
63 bool parseConstToken(const UChar
* start
, const UChar
* end
, const UChar
** tokenEnd
, const char* token
)
65 while (start
< end
&& *token
!= '\0' && *start
++ == *token
++) { }
72 bool readInt(const UChar
* start
, const UChar
* end
, const UChar
** tokenEnd
, bool canHaveLeadingZeros
)
76 bool haveLeadingZero
= '0' == *start
;
78 while (start
< end
&& '0' <= *start
&& *start
<= '9') {
84 if (!canHaveLeadingZeros
&& length
> 1 && haveLeadingZero
)
90 bool parseNumberToken(const UChar
* start
, const UChar
* end
, const UChar
** tokenEnd
)
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]
100 if (!readInt(start
, end
, &start
, false))
107 // Optional fraction part
111 if (!readInt(start
, end
, &start
, true))
120 // Optional exponent part
121 if ('e' == c
|| 'E' == c
) {
126 if ('-' == c
|| '+' == c
) {
131 if (!readInt(start
, end
, &start
, true))
139 bool readHexDigits(const UChar
* start
, const UChar
* end
, const UChar
** tokenEnd
, int digits
)
141 if (end
- start
< digits
)
143 for (int i
= 0; i
< digits
; ++i
) {
145 if (!(('0' <= c
&& c
<= '9') || ('a' <= c
&& c
<= 'f') || ('A' <= c
&& c
<= 'F')))
152 bool parseStringToken(const UChar
* start
, const UChar
* end
, const UChar
** tokenEnd
)
154 while (start
< end
) {
158 // Make sure the escaped char is valid.
161 if (!readHexDigits(start
, end
, &start
, 2))
165 if (!readHexDigits(start
, end
, &start
, 4))
181 } else if ('"' == c
) {
189 Token
parseToken(const UChar
* start
, const UChar
* end
, const UChar
** tokenStart
, const UChar
** tokenEnd
)
191 while (start
< end
&& isSpaceOrNewline(*start
))
195 return INVALID_TOKEN
;
201 if (parseConstToken(start
, end
, tokenEnd
, nullString
))
205 if (parseConstToken(start
, end
, tokenEnd
, trueString
))
209 if (parseConstToken(start
, end
, tokenEnd
, falseString
))
213 *tokenEnd
= start
+ 1;
216 *tokenEnd
= start
+ 1;
219 *tokenEnd
= start
+ 1;
220 return LIST_SEPARATOR
;
222 *tokenEnd
= start
+ 1;
225 *tokenEnd
= start
+ 1;
228 *tokenEnd
= start
+ 1;
229 return OBJECT_PAIR_SEPARATOR
;
241 if (parseNumberToken(start
, end
, tokenEnd
))
245 if (parseStringToken(start
+ 1, end
, tokenEnd
))
249 return INVALID_TOKEN
;
252 inline int hexToInt(UChar c
)
254 if ('0' <= c
&& c
<= '9')
256 if ('A' <= c
&& c
<= 'F')
258 if ('a' <= c
&& c
<= 'f')
260 ASSERT_NOT_REACHED();
264 bool decodeString(const UChar
* start
, const UChar
* end
, StringBuilder
* output
)
266 while (start
< end
) {
297 c
= (hexToInt(*start
) << 4) +
298 hexToInt(*(start
+ 1));
302 c
= (hexToInt(*start
) << 12) +
303 (hexToInt(*(start
+ 1)) << 8) +
304 (hexToInt(*(start
+ 2)) << 4) +
305 hexToInt(*(start
+ 3));
316 bool decodeString(const UChar
* start
, const UChar
* end
, String
* output
)
324 StringBuilder buffer
;
325 buffer
.reserveCapacity(end
- start
);
326 if (!decodeString(start
, end
, &buffer
))
328 *output
= buffer
.toString();
332 PassRefPtr
<InspectorValue
> buildValue(const UChar
* start
, const UChar
* end
, const UChar
** valueTokenEnd
, int depth
)
334 if (depth
> stackLimit
)
337 RefPtr
<InspectorValue
> result
;
338 const UChar
* tokenStart
;
339 const UChar
* tokenEnd
;
340 Token token
= parseToken(start
, end
, &tokenStart
, &tokenEnd
);
345 result
= InspectorValue::null();
348 result
= InspectorBasicValue::create(true);
351 result
= InspectorBasicValue::create(false);
355 double value
= charactersToDouble(tokenStart
, tokenEnd
- tokenStart
, &ok
);
358 result
= InspectorBasicValue::create(value
);
363 bool ok
= decodeString(tokenStart
+ 1, tokenEnd
- 1, &value
);
366 result
= InspectorString::create(value
);
370 RefPtr
<InspectorArray
> array
= InspectorArray::create();
372 token
= parseToken(start
, end
, &tokenStart
, &tokenEnd
);
373 while (token
!= ARRAY_END
) {
374 RefPtr
<InspectorValue
> arrayNode
= buildValue(start
, end
, &tokenEnd
, depth
+ 1);
377 array
->pushValue(arrayNode
);
379 // After a list value, we expect a comma or the end of the list.
381 token
= parseToken(start
, end
, &tokenStart
, &tokenEnd
);
382 if (token
== LIST_SEPARATOR
) {
384 token
= parseToken(start
, end
, &tokenStart
, &tokenEnd
);
385 if (token
== ARRAY_END
)
387 } else if (token
!= ARRAY_END
) {
388 // Unexpected value after list value. Bail out.
392 if (token
!= ARRAY_END
)
394 result
= array
.release();
398 RefPtr
<InspectorObject
> object
= InspectorObject::create();
400 token
= parseToken(start
, end
, &tokenStart
, &tokenEnd
);
401 while (token
!= OBJECT_END
) {
405 if (!decodeString(tokenStart
+ 1, tokenEnd
- 1, &key
))
409 token
= parseToken(start
, end
, &tokenStart
, &tokenEnd
);
410 if (token
!= OBJECT_PAIR_SEPARATOR
)
414 RefPtr
<InspectorValue
> value
= buildValue(start
, end
, &tokenEnd
, depth
+ 1);
417 object
->setValue(key
, value
);
420 // After a key/value pair, we expect a comma or the end of the
422 token
= parseToken(start
, end
, &tokenStart
, &tokenEnd
);
423 if (token
== LIST_SEPARATOR
) {
425 token
= parseToken(start
, end
, &tokenStart
, &tokenEnd
);
426 if (token
== OBJECT_END
)
428 } else if (token
!= OBJECT_END
) {
429 // Unexpected value after last object value. Bail out.
433 if (token
!= OBJECT_END
)
435 result
= object
.release();
440 // We got a token that's not a value.
443 *valueTokenEnd
= tokenEnd
;
444 return result
.release();
447 inline bool escapeChar(UChar c
, StringBuilder
* dst
)
450 case '\b': dst
->append("\\b", 2); break;
451 case '\f': dst
->append("\\f", 2); break;
452 case '\n': dst
->append("\\n", 2); break;
453 case '\r': dst
->append("\\r", 2); break;
454 case '\t': dst
->append("\\t", 2); break;
455 case '\\': dst
->append("\\\\", 2); break;
456 case '"': dst
->append("\\\"", 2); break;
463 inline void doubleQuoteString(const String
& str
, StringBuilder
* dst
)
466 for (unsigned i
= 0; i
< str
.length(); ++i
) {
468 if (!escapeChar(c
, dst
)) {
469 if (c
< 32 || c
> 126 || c
== '<' || c
== '>') {
470 // 1. Escaping <, > to prevent script execution.
471 // 2. Technically, we could also pass through c > 126 as UTF8, but this
472 // is also optional. It would also be a pain to implement here.
473 dst
->append(String::format("\\u%04X", c
));
481 } // anonymous namespace
483 bool InspectorValue::asBoolean(bool*) const
488 bool InspectorValue::asNumber(double*) const
493 bool InspectorValue::asNumber(float*) const
498 bool InspectorValue::asNumber(int*) const
503 bool InspectorValue::asNumber(unsigned*) const
508 bool InspectorValue::asNumber(long*) const
513 bool InspectorValue::asNumber(long long*) const
518 bool InspectorValue::asNumber(unsigned long*) const
523 bool InspectorValue::asNumber(unsigned long long*) const
528 bool InspectorValue::asString(String
*) const
533 bool InspectorValue::asValue(RefPtr
<InspectorValue
>* output
)
539 bool InspectorValue::asObject(RefPtr
<InspectorObject
>*)
544 bool InspectorValue::asArray(RefPtr
<InspectorArray
>*)
549 PassRefPtr
<InspectorObject
> InspectorValue::asObject()
554 PassRefPtr
<InspectorArray
> InspectorValue::asArray()
559 PassRefPtr
<InspectorValue
> InspectorValue::parseJSON(const String
& json
)
561 // FIXME: This whole file should just use StringView instead of UChar/length and avoid upconverting.
562 auto characters
= StringView(json
).upconvertedCharacters();
563 const UChar
* start
= characters
;
564 const UChar
* end
= start
+ json
.length();
565 const UChar
* tokenEnd
;
566 RefPtr
<InspectorValue
> value
= buildValue(start
, end
, &tokenEnd
, 0);
567 if (!value
|| tokenEnd
!= end
)
569 return value
.release();
572 String
InspectorValue::toJSONString() const
574 StringBuilder result
;
575 result
.reserveCapacity(512);
577 return result
.toString();
580 void InspectorValue::writeJSON(StringBuilder
* output
) const
582 ASSERT(m_type
== TypeNull
);
583 output
->append(nullString
, 4);
586 bool InspectorBasicValue::asBoolean(bool* output
) const
588 if (type() != TypeBoolean
)
590 *output
= m_boolValue
;
594 bool InspectorBasicValue::asNumber(double* output
) const
596 if (type() != TypeNumber
)
598 *output
= m_doubleValue
;
602 bool InspectorBasicValue::asNumber(float* output
) const
604 if (type() != TypeNumber
)
606 *output
= static_cast<float>(m_doubleValue
);
610 bool InspectorBasicValue::asNumber(int* output
) const
612 if (type() != TypeNumber
)
614 *output
= static_cast<int>(m_doubleValue
);
618 bool InspectorBasicValue::asNumber(unsigned* output
) const
620 if (type() != TypeNumber
)
622 *output
= static_cast<unsigned>(m_doubleValue
);
626 bool InspectorBasicValue::asNumber(long* output
) const
628 if (type() != TypeNumber
)
630 *output
= static_cast<long>(m_doubleValue
);
634 bool InspectorBasicValue::asNumber(long long* output
) const
636 if (type() != TypeNumber
)
638 *output
= static_cast<long long>(m_doubleValue
);
642 bool InspectorBasicValue::asNumber(unsigned long* output
) const
644 if (type() != TypeNumber
)
646 *output
= static_cast<unsigned long>(m_doubleValue
);
650 bool InspectorBasicValue::asNumber(unsigned long long* output
) const
652 if (type() != TypeNumber
)
654 *output
= static_cast<unsigned long long>(m_doubleValue
);
658 void InspectorBasicValue::writeJSON(StringBuilder
* output
) const
660 ASSERT(type() == TypeBoolean
|| type() == TypeNumber
);
661 if (type() == TypeBoolean
) {
663 output
->append(trueString
, 4);
665 output
->append(falseString
, 5);
666 } else if (type() == TypeNumber
) {
667 NumberToLStringBuffer buffer
;
668 if (!std::isfinite(m_doubleValue
)) {
669 output
->append(nullString
, 4);
672 DecimalNumber decimal
= m_doubleValue
;
674 if (decimal
.bufferLengthForStringDecimal() > WTF::NumberToStringBufferLength
) {
675 // Not enough room for decimal. Use exponential format.
676 if (decimal
.bufferLengthForStringExponential() > WTF::NumberToStringBufferLength
) {
677 // Fallback for an abnormal case if it's too little even for exponential.
678 output
->append("NaN", 3);
681 length
= decimal
.toStringExponential(buffer
, WTF::NumberToStringBufferLength
);
683 length
= decimal
.toStringDecimal(buffer
, WTF::NumberToStringBufferLength
);
684 output
->append(buffer
, length
);
688 bool InspectorString::asString(String
* output
) const
690 *output
= m_stringValue
;
694 void InspectorString::writeJSON(StringBuilder
* output
) const
696 ASSERT(type() == TypeString
);
697 doubleQuoteString(m_stringValue
, output
);
700 InspectorObjectBase::~InspectorObjectBase()
704 bool InspectorObjectBase::asObject(RefPtr
<InspectorObject
>* output
)
706 COMPILE_ASSERT(sizeof(InspectorObject
) == sizeof(InspectorObjectBase
), cannot_cast
);
707 *output
= static_cast<InspectorObject
*>(this);
711 PassRefPtr
<InspectorObject
> InspectorObjectBase::asObject()
713 return openAccessors();
716 InspectorObject
* InspectorObjectBase::openAccessors()
718 COMPILE_ASSERT(sizeof(InspectorObject
) == sizeof(InspectorObjectBase
), cannot_cast
);
719 return static_cast<InspectorObject
*>(this);
722 bool InspectorObjectBase::getBoolean(const String
& name
, bool* output
) const
724 RefPtr
<InspectorValue
> value
= get(name
);
727 return value
->asBoolean(output
);
730 bool InspectorObjectBase::getString(const String
& name
, String
* output
) const
732 RefPtr
<InspectorValue
> value
= get(name
);
735 return value
->asString(output
);
738 PassRefPtr
<InspectorObject
> InspectorObjectBase::getObject(const String
& name
) const
740 PassRefPtr
<InspectorValue
> value
= get(name
);
743 return value
->asObject();
746 PassRefPtr
<InspectorArray
> InspectorObjectBase::getArray(const String
& name
) const
748 PassRefPtr
<InspectorValue
> value
= get(name
);
751 return value
->asArray();
754 PassRefPtr
<InspectorValue
> InspectorObjectBase::get(const String
& name
) const
756 Dictionary::const_iterator it
= m_data
.find(name
);
757 if (it
== m_data
.end())
762 void InspectorObjectBase::remove(const String
& name
)
765 for (size_t i
= 0; i
< m_order
.size(); ++i
) {
766 if (m_order
[i
] == name
) {
773 void InspectorObjectBase::writeJSON(StringBuilder
* output
) const
776 for (size_t i
= 0; i
< m_order
.size(); ++i
) {
777 Dictionary::const_iterator it
= m_data
.find(m_order
[i
]);
778 ASSERT(it
!= m_data
.end());
781 doubleQuoteString(it
->key
, output
);
783 it
->value
->writeJSON(output
);
788 InspectorObjectBase::InspectorObjectBase()
789 : InspectorValue(TypeObject
)
795 InspectorArrayBase::~InspectorArrayBase()
799 bool InspectorArrayBase::asArray(RefPtr
<InspectorArray
>* output
)
801 COMPILE_ASSERT(sizeof(InspectorArrayBase
) == sizeof(InspectorArray
), cannot_cast
);
802 *output
= static_cast<InspectorArray
*>(this);
806 PassRefPtr
<InspectorArray
> InspectorArrayBase::asArray()
808 COMPILE_ASSERT(sizeof(InspectorArrayBase
) == sizeof(InspectorArray
), cannot_cast
);
809 return static_cast<InspectorArray
*>(this);
812 void InspectorArrayBase::writeJSON(StringBuilder
* output
) const
815 for (Vector
<RefPtr
<InspectorValue
>>::const_iterator it
= m_data
.begin(); it
!= m_data
.end(); ++it
) {
816 if (it
!= m_data
.begin())
818 (*it
)->writeJSON(output
);
823 InspectorArrayBase::InspectorArrayBase()
824 : InspectorValue(TypeArray
)
829 PassRefPtr
<InspectorValue
> InspectorArrayBase::get(size_t index
)
831 ASSERT_WITH_SECURITY_IMPLICATION(index
< m_data
.size());
832 return m_data
[index
];
835 PassRefPtr
<InspectorObject
> InspectorObject::create()
837 return adoptRef(new InspectorObject
);
840 PassRefPtr
<InspectorArray
> InspectorArray::create()
842 return adoptRef(new InspectorArray
);
845 PassRefPtr
<InspectorValue
> InspectorValue::null()
847 return adoptRef(new InspectorValue
);
850 PassRefPtr
<InspectorString
> InspectorString::create(const String
& value
)
852 return adoptRef(new InspectorString(value
));
855 PassRefPtr
<InspectorString
> InspectorString::create(const char* value
)
857 return adoptRef(new InspectorString(value
));
860 PassRefPtr
<InspectorBasicValue
> InspectorBasicValue::create(bool value
)
862 return adoptRef(new InspectorBasicValue(value
));
865 PassRefPtr
<InspectorBasicValue
> InspectorBasicValue::create(int value
)
867 return adoptRef(new InspectorBasicValue(value
));
870 PassRefPtr
<InspectorBasicValue
> InspectorBasicValue::create(double value
)
872 return adoptRef(new InspectorBasicValue(value
));
875 } // namespace Inspector