2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 * Copyright (C) 2014 University of Washington. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include "InspectorValues.h"
35 #include <wtf/DecimalNumber.h>
37 #include <wtf/text/StringBuilder.h>
43 static const int stackLimit
= 1000;
56 OBJECT_PAIR_SEPARATOR
,
60 const char* const nullString
= "null";
61 const char* const trueString
= "true";
62 const char* const falseString
= "false";
64 bool parseConstToken(const UChar
* start
, const UChar
* end
, const UChar
** tokenEnd
, const char* token
)
66 while (start
< end
&& *token
!= '\0' && *start
++ == *token
++) { }
75 bool readInt(const UChar
* start
, const UChar
* end
, const UChar
** tokenEnd
, bool canHaveLeadingZeros
)
80 bool haveLeadingZero
= '0' == *start
;
82 while (start
< end
&& '0' <= *start
&& *start
<= '9') {
90 if (!canHaveLeadingZeros
&& length
> 1 && haveLeadingZero
)
97 bool parseNumberToken(const UChar
* start
, const UChar
* end
, const UChar
** tokenEnd
)
99 // We just grab the number here. We validate the size in DecodeNumber.
100 // According to RFC4627, a valid number is: [minus] int [frac] [exp]
108 if (!readInt(start
, end
, &start
, false))
116 // Optional fraction part
120 if (!readInt(start
, end
, &start
, true))
129 // Optional exponent part
130 if ('e' == c
|| 'E' == c
) {
135 if ('-' == c
|| '+' == c
) {
140 if (!readInt(start
, end
, &start
, true))
148 bool readHexDigits(const UChar
* start
, const UChar
* end
, const UChar
** tokenEnd
, int digits
)
150 if (end
- start
< digits
)
153 for (int i
= 0; i
< digits
; ++i
) {
155 if (!(('0' <= c
&& c
<= '9') || ('a' <= c
&& c
<= 'f') || ('A' <= c
&& c
<= 'F')))
163 bool parseStringToken(const UChar
* start
, const UChar
* end
, const UChar
** tokenEnd
)
165 while (start
< end
) {
169 // Make sure the escaped char is valid.
172 if (!readHexDigits(start
, end
, &start
, 2))
176 if (!readHexDigits(start
, end
, &start
, 4))
192 } else if ('"' == c
) {
201 Token
parseToken(const UChar
* start
, const UChar
* end
, const UChar
** tokenStart
, const UChar
** tokenEnd
)
203 while (start
< end
&& isSpaceOrNewline(*start
))
207 return INVALID_TOKEN
;
213 if (parseConstToken(start
, end
, tokenEnd
, nullString
))
217 if (parseConstToken(start
, end
, tokenEnd
, trueString
))
221 if (parseConstToken(start
, end
, tokenEnd
, falseString
))
225 *tokenEnd
= start
+ 1;
228 *tokenEnd
= start
+ 1;
231 *tokenEnd
= start
+ 1;
232 return LIST_SEPARATOR
;
234 *tokenEnd
= start
+ 1;
237 *tokenEnd
= start
+ 1;
240 *tokenEnd
= start
+ 1;
241 return OBJECT_PAIR_SEPARATOR
;
253 if (parseNumberToken(start
, end
, tokenEnd
))
257 if (parseStringToken(start
+ 1, end
, tokenEnd
))
262 return INVALID_TOKEN
;
265 inline int hexToInt(UChar c
)
267 if ('0' <= c
&& c
<= '9')
269 if ('A' <= c
&& c
<= 'F')
271 if ('a' <= c
&& c
<= 'f')
274 ASSERT_NOT_REACHED();
278 bool decodeString(const UChar
* start
, const UChar
* end
, StringBuilder
& output
)
280 while (start
< end
) {
311 c
= (hexToInt(*start
) << 4) +
312 hexToInt(*(start
+ 1));
316 c
= (hexToInt(*start
) << 12) +
317 (hexToInt(*(start
+ 1)) << 8) +
318 (hexToInt(*(start
+ 2)) << 4) +
319 hexToInt(*(start
+ 3));
331 bool decodeString(const UChar
* start
, const UChar
* end
, String
& output
)
334 output
= emptyString();
341 StringBuilder buffer
;
342 buffer
.reserveCapacity(end
- start
);
343 if (!decodeString(start
, end
, buffer
))
346 output
= buffer
.toString();
350 RefPtr
<InspectorValue
> buildValue(const UChar
* start
, const UChar
* end
, const UChar
** valueTokenEnd
, int depth
)
352 if (depth
> stackLimit
)
355 RefPtr
<InspectorValue
> result
;
356 const UChar
* tokenStart
;
357 const UChar
* tokenEnd
;
358 Token token
= parseToken(start
, end
, &tokenStart
, &tokenEnd
);
363 result
= InspectorValue::null();
366 result
= InspectorBasicValue::create(true);
369 result
= InspectorBasicValue::create(false);
373 double value
= charactersToDouble(tokenStart
, tokenEnd
- tokenStart
, &ok
);
376 result
= InspectorBasicValue::create(value
);
381 bool ok
= decodeString(tokenStart
+ 1, tokenEnd
- 1, value
);
384 result
= InspectorString::create(value
);
388 Ref
<InspectorArray
> array
= InspectorArray::create();
390 token
= parseToken(start
, end
, &tokenStart
, &tokenEnd
);
391 while (token
!= ARRAY_END
) {
392 RefPtr
<InspectorValue
> arrayNode
= buildValue(start
, end
, &tokenEnd
, depth
+ 1);
395 array
->pushValue(WTF::move(arrayNode
));
397 // After a list value, we expect a comma or the end of the list.
399 token
= parseToken(start
, end
, &tokenStart
, &tokenEnd
);
400 if (token
== LIST_SEPARATOR
) {
402 token
= parseToken(start
, end
, &tokenStart
, &tokenEnd
);
403 if (token
== ARRAY_END
)
405 } else if (token
!= ARRAY_END
) {
406 // Unexpected value after list value. Bail out.
410 if (token
!= ARRAY_END
)
412 result
= WTF::move(array
);
416 Ref
<InspectorObject
> object
= InspectorObject::create();
418 token
= parseToken(start
, end
, &tokenStart
, &tokenEnd
);
419 while (token
!= OBJECT_END
) {
423 if (!decodeString(tokenStart
+ 1, tokenEnd
- 1, key
))
427 token
= parseToken(start
, end
, &tokenStart
, &tokenEnd
);
428 if (token
!= OBJECT_PAIR_SEPARATOR
)
432 RefPtr
<InspectorValue
> value
= buildValue(start
, end
, &tokenEnd
, depth
+ 1);
435 object
->setValue(key
, WTF::move(value
));
438 // After a key/value pair, we expect a comma or the end of the
440 token
= parseToken(start
, end
, &tokenStart
, &tokenEnd
);
441 if (token
== LIST_SEPARATOR
) {
443 token
= parseToken(start
, end
, &tokenStart
, &tokenEnd
);
444 if (token
== OBJECT_END
)
446 } else if (token
!= OBJECT_END
) {
447 // Unexpected value after last object value. Bail out.
451 if (token
!= OBJECT_END
)
453 result
= WTF::move(object
);
458 // We got a token that's not a value.
461 *valueTokenEnd
= tokenEnd
;
462 return result
.release();
465 inline bool escapeChar(UChar c
, StringBuilder
& dst
)
468 case '\b': dst
.appendLiteral("\\b"); break;
469 case '\f': dst
.appendLiteral("\\f"); break;
470 case '\n': dst
.appendLiteral("\\n"); break;
471 case '\r': dst
.appendLiteral("\\r"); break;
472 case '\t': dst
.appendLiteral("\\t"); break;
473 case '\\': dst
.appendLiteral("\\\\"); break;
474 case '"': dst
.appendLiteral("\\\""); break;
481 inline void doubleQuoteString(const String
& str
, StringBuilder
& dst
)
484 for (unsigned i
= 0; i
< str
.length(); ++i
) {
486 if (!escapeChar(c
, dst
)) {
487 if (c
< 32 || c
> 126 || c
== '<' || c
== '>') {
488 // 1. Escaping <, > to prevent script execution.
489 // 2. Technically, we could also pass through c > 126 as UTF8, but this
490 // is also optional. It would also be a pain to implement here.
491 dst
.append(String::format("\\u%04X", c
));
499 } // anonymous namespace
501 bool InspectorValue::asBoolean(bool&) const
506 bool InspectorValue::asDouble(double&) const
511 bool InspectorValue::asDouble(float&) const
516 bool InspectorValue::asInteger(int&) const
521 bool InspectorValue::asInteger(unsigned&) const
526 bool InspectorValue::asInteger(long&) const
531 bool InspectorValue::asInteger(long long&) const
536 bool InspectorValue::asInteger(unsigned long&) const
541 bool InspectorValue::asInteger(unsigned long long&) const
546 bool InspectorValue::asString(String
&) const
551 bool InspectorValue::asValue(RefPtr
<InspectorValue
>& output
)
557 bool InspectorValue::asObject(RefPtr
<InspectorObject
>&)
562 bool InspectorValue::asArray(RefPtr
<InspectorArray
>&)
567 bool InspectorValue::parseJSON(const String
& jsonInput
, RefPtr
<InspectorValue
>& output
)
569 // FIXME: This whole file should just use StringView instead of UChar/length and avoid upconverting.
570 auto characters
= StringView(jsonInput
).upconvertedCharacters();
571 const UChar
* start
= characters
;
572 const UChar
* end
= start
+ jsonInput
.length();
573 const UChar
* tokenEnd
;
574 RefPtr
<InspectorValue
> result
= buildValue(start
, end
, &tokenEnd
, 0);
575 if (!result
|| tokenEnd
!= end
)
578 output
= result
.release();
582 String
InspectorValue::toJSONString() const
584 StringBuilder result
;
585 result
.reserveCapacity(512);
587 return result
.toString();
590 void InspectorValue::writeJSON(StringBuilder
& output
) const
592 ASSERT(m_type
== Type::Null
);
594 output
.appendLiteral("null");
597 bool InspectorBasicValue::asBoolean(bool& output
) const
599 if (type() != Type::Boolean
)
602 output
= m_booleanValue
;
606 bool InspectorBasicValue::asDouble(double& output
) const
608 if (type() != Type::Double
)
611 output
= m_doubleValue
;
615 bool InspectorBasicValue::asDouble(float& output
) const
617 if (type() != Type::Double
)
620 output
= static_cast<float>(m_doubleValue
);
624 bool InspectorBasicValue::asInteger(int& output
) const
626 if (type() != Type::Integer
&& type() != Type::Double
)
629 output
= static_cast<int>(m_doubleValue
);
633 bool InspectorBasicValue::asInteger(unsigned& output
) const
635 if (type() != Type::Integer
&& type() != Type::Double
)
638 output
= static_cast<unsigned>(m_doubleValue
);
642 bool InspectorBasicValue::asInteger(long& output
) const
644 if (type() != Type::Integer
&& type() != Type::Double
)
647 output
= static_cast<long>(m_doubleValue
);
651 bool InspectorBasicValue::asInteger(long long& output
) const
653 if (type() != Type::Integer
&& type() != Type::Double
)
656 output
= static_cast<long long>(m_doubleValue
);
660 bool InspectorBasicValue::asInteger(unsigned long& output
) const
662 if (type() != Type::Integer
&& type() != Type::Double
)
665 output
= static_cast<unsigned long>(m_doubleValue
);
669 bool InspectorBasicValue::asInteger(unsigned long long& output
) const
671 if (type() != Type::Integer
&& type() != Type::Double
)
674 output
= static_cast<unsigned long long>(m_doubleValue
);
678 void InspectorBasicValue::writeJSON(StringBuilder
& output
) const
680 ASSERT(type() == Type::Boolean
|| type() == Type::Double
|| type() == Type::Integer
);
682 if (type() == Type::Boolean
) {
684 output
.appendLiteral("true");
686 output
.appendLiteral("false");
687 } else if (type() == Type::Double
|| type() == Type::Integer
) {
688 NumberToLStringBuffer buffer
;
689 if (!std::isfinite(m_doubleValue
)) {
690 output
.appendLiteral("null");
693 DecimalNumber decimal
= m_doubleValue
;
695 if (decimal
.bufferLengthForStringDecimal() > WTF::NumberToStringBufferLength
) {
696 // Not enough room for decimal. Use exponential format.
697 if (decimal
.bufferLengthForStringExponential() > WTF::NumberToStringBufferLength
) {
698 // Fallback for an abnormal case if it's too little even for exponential.
699 output
.appendLiteral("NaN");
702 length
= decimal
.toStringExponential(buffer
, WTF::NumberToStringBufferLength
);
704 length
= decimal
.toStringDecimal(buffer
, WTF::NumberToStringBufferLength
);
705 output
.append(buffer
, length
);
709 bool InspectorString::asString(String
& output
) const
711 output
= m_stringValue
;
715 void InspectorString::writeJSON(StringBuilder
& output
) const
717 ASSERT(type() == Type::String
);
718 doubleQuoteString(m_stringValue
, output
);
721 InspectorObjectBase::~InspectorObjectBase()
725 bool InspectorObjectBase::asObject(RefPtr
<InspectorObject
>& output
)
727 COMPILE_ASSERT(sizeof(InspectorObject
) == sizeof(InspectorObjectBase
), cannot_cast
);
729 output
= static_cast<InspectorObject
*>(this);
733 InspectorObject
* InspectorObjectBase::openAccessors()
735 COMPILE_ASSERT(sizeof(InspectorObject
) == sizeof(InspectorObjectBase
), cannot_cast
);
737 return static_cast<InspectorObject
*>(this);
740 bool InspectorObjectBase::getBoolean(const String
& name
, bool& output
) const
742 RefPtr
<InspectorValue
> value
;
743 if (!getValue(name
, value
))
746 return value
->asBoolean(output
);
749 bool InspectorObjectBase::getString(const String
& name
, String
& output
) const
751 RefPtr
<InspectorValue
> value
;
752 if (!getValue(name
, value
))
755 return value
->asString(output
);
758 bool InspectorObjectBase::getObject(const String
& name
, RefPtr
<InspectorObject
>& output
) const
760 RefPtr
<InspectorValue
> value
;
761 if (!getValue(name
, value
))
764 return value
->asObject(output
);
767 bool InspectorObjectBase::getArray(const String
& name
, RefPtr
<InspectorArray
>& output
) const
769 RefPtr
<InspectorValue
> value
;
770 if (!getValue(name
, value
))
773 return value
->asArray(output
);
776 bool InspectorObjectBase::getValue(const String
& name
, RefPtr
<InspectorValue
>& output
) const
778 Dictionary::const_iterator findResult
= m_data
.find(name
);
779 if (findResult
== m_data
.end())
782 output
= findResult
->value
;
786 void InspectorObjectBase::remove(const String
& name
)
789 m_order
.removeFirst(name
);
792 void InspectorObjectBase::writeJSON(StringBuilder
& output
) const
795 for (size_t i
= 0; i
< m_order
.size(); ++i
) {
796 auto findResult
= m_data
.find(m_order
[i
]);
797 ASSERT(findResult
!= m_data
.end());
800 doubleQuoteString(findResult
->key
, output
);
802 findResult
->value
->writeJSON(output
);
807 InspectorObjectBase::InspectorObjectBase()
808 : InspectorValue(Type::Object
)
814 InspectorArrayBase::~InspectorArrayBase()
818 bool InspectorArrayBase::asArray(RefPtr
<InspectorArray
>& output
)
820 COMPILE_ASSERT(sizeof(InspectorArrayBase
) == sizeof(InspectorArray
), cannot_cast
);
821 output
= static_cast<InspectorArray
*>(this);
825 void InspectorArrayBase::writeJSON(StringBuilder
& output
) const
828 for (Vector
<RefPtr
<InspectorValue
>>::const_iterator it
= m_data
.begin(); it
!= m_data
.end(); ++it
) {
829 if (it
!= m_data
.begin())
831 (*it
)->writeJSON(output
);
836 InspectorArrayBase::InspectorArrayBase()
837 : InspectorValue(Type::Array
)
842 RefPtr
<InspectorValue
> InspectorArrayBase::get(size_t index
) const
844 ASSERT_WITH_SECURITY_IMPLICATION(index
< m_data
.size());
845 return m_data
[index
];
848 Ref
<InspectorObject
> InspectorObject::create()
850 return adoptRef(*new InspectorObject
);
853 Ref
<InspectorArray
> InspectorArray::create()
855 return adoptRef(*new InspectorArray
);
858 Ref
<InspectorValue
> InspectorValue::null()
860 return adoptRef(*new InspectorValue
);
863 Ref
<InspectorString
> InspectorString::create(const String
& value
)
865 return adoptRef(*new InspectorString(value
));
868 Ref
<InspectorString
> InspectorString::create(const char* value
)
870 return adoptRef(*new InspectorString(value
));
873 Ref
<InspectorBasicValue
> InspectorBasicValue::create(bool value
)
875 return adoptRef(*new InspectorBasicValue(value
));
878 Ref
<InspectorBasicValue
> InspectorBasicValue::create(int value
)
880 return adoptRef(*new InspectorBasicValue(value
));
883 Ref
<InspectorBasicValue
> InspectorBasicValue::create(double value
)
885 return adoptRef(*new InspectorBasicValue(value
));
888 } // namespace Inspector