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
unsigned int symbol = static_cast<unsigned int>(c);
474
String symbolCode = String::format("\\u%04X", symbol);
475
dst->append(symbolCode.characters(), symbolCode.length());
483
} // anonymous namespace
485
bool InspectorValue::asBoolean(bool*) const
490
bool InspectorValue::asNumber(double*) const
495
bool InspectorValue::asNumber(long*) const
500
bool InspectorValue::asNumber(int*) const
505
bool InspectorValue::asNumber(unsigned long*) const
510
bool InspectorValue::asNumber(unsigned int*) const
515
bool InspectorValue::asString(String*) const
520
bool InspectorValue::asValue(RefPtr<InspectorValue>* output)
526
bool InspectorValue::asObject(RefPtr<InspectorObject>*)
531
bool InspectorValue::asArray(RefPtr<InspectorArray>*)
536
PassRefPtr<InspectorObject> InspectorValue::asObject()
541
PassRefPtr<InspectorArray> InspectorValue::asArray()
546
PassRefPtr<InspectorValue> InspectorValue::parseJSON(const String& json)
548
const UChar* start = json.characters();
549
const UChar* end = json.characters() + json.length();
550
const UChar *tokenEnd;
551
RefPtr<InspectorValue> value = buildValue(start, end, &tokenEnd, 0);
552
if (!value || tokenEnd != end)
554
return value.release();
557
String InspectorValue::toJSONString() const
559
StringBuilder result;
560
result.reserveCapacity(512);
562
return result.toString();
565
void InspectorValue::writeJSON(StringBuilder* output) const
567
ASSERT(m_type == TypeNull);
568
output->append(nullString, 4);
571
bool InspectorBasicValue::asBoolean(bool* output) const
573
if (type() != TypeBoolean)
575
*output = m_boolValue;
579
bool InspectorBasicValue::asNumber(double* output) const
581
if (type() != TypeNumber)
583
*output = m_doubleValue;
587
bool InspectorBasicValue::asNumber(long* output) const
589
if (type() != TypeNumber)
591
*output = static_cast<long>(m_doubleValue);
595
bool InspectorBasicValue::asNumber(int* output) const
597
if (type() != TypeNumber)
599
*output = static_cast<int>(m_doubleValue);
603
bool InspectorBasicValue::asNumber(unsigned long* output) const
605
if (type() != TypeNumber)
607
*output = static_cast<unsigned long>(m_doubleValue);
611
bool InspectorBasicValue::asNumber(unsigned int* output) const
613
if (type() != TypeNumber)
615
*output = static_cast<unsigned int>(m_doubleValue);
619
void InspectorBasicValue::writeJSON(StringBuilder* output) const
621
ASSERT(type() == TypeBoolean || type() == TypeNumber);
622
if (type() == TypeBoolean) {
624
output->append(trueString, 4);
626
output->append(falseString, 5);
627
} else if (type() == TypeNumber) {
628
NumberToLStringBuffer buffer;
629
if (!isfinite(m_doubleValue)) {
630
output->append(nullString, 4);
633
DecimalNumber decimal = m_doubleValue;
635
if (decimal.bufferLengthForStringDecimal() > WTF::NumberToStringBufferLength) {
636
// Not enough room for decimal. Use exponential format.
637
if (decimal.bufferLengthForStringExponential() > WTF::NumberToStringBufferLength) {
638
// Fallback for an abnormal case if it's too little even for exponential.
639
output->append("NaN", 3);
642
length = decimal.toStringExponential(buffer, WTF::NumberToStringBufferLength);
644
length = decimal.toStringDecimal(buffer, WTF::NumberToStringBufferLength);
645
output->append(buffer, length);
649
bool InspectorString::asString(String* output) const
651
*output = m_stringValue;
655
void InspectorString::writeJSON(StringBuilder* output) const
657
ASSERT(type() == TypeString);
658
doubleQuoteString(m_stringValue, output);
661
InspectorObjectBase::~InspectorObjectBase()
665
bool InspectorObjectBase::asObject(RefPtr<InspectorObject>* output)
667
COMPILE_ASSERT(sizeof(InspectorObject) == sizeof(InspectorObjectBase), cannot_cast);
668
*output = static_cast<InspectorObject*>(this);
672
PassRefPtr<InspectorObject> InspectorObjectBase::asObject()
674
return openAccessors();
677
InspectorObject* InspectorObjectBase::openAccessors()
679
COMPILE_ASSERT(sizeof(InspectorObject) == sizeof(InspectorObjectBase), cannot_cast);
680
return static_cast<InspectorObject*>(this);
683
bool InspectorObjectBase::getBoolean(const String& name, bool* output) const
685
RefPtr<InspectorValue> value = get(name);
688
return value->asBoolean(output);
691
bool InspectorObjectBase::getString(const String& name, String* output) const
693
RefPtr<InspectorValue> value = get(name);
696
return value->asString(output);
699
PassRefPtr<InspectorObject> InspectorObjectBase::getObject(const String& name) const
701
PassRefPtr<InspectorValue> value = get(name);
704
return value->asObject();
707
PassRefPtr<InspectorArray> InspectorObjectBase::getArray(const String& name) const
709
PassRefPtr<InspectorValue> value = get(name);
712
return value->asArray();
715
PassRefPtr<InspectorValue> InspectorObjectBase::get(const String& name) const
717
Dictionary::const_iterator it = m_data.find(name);
718
if (it == m_data.end())
723
void InspectorObjectBase::remove(const String& name)
726
for (size_t i = 0; i < m_order.size(); ++i) {
727
if (m_order[i] == name) {
734
void InspectorObjectBase::writeJSON(StringBuilder* output) const
737
for (size_t i = 0; i < m_order.size(); ++i) {
738
Dictionary::const_iterator it = m_data.find(m_order[i]);
739
ASSERT(it != m_data.end());
742
doubleQuoteString(it->key, output);
744
it->value->writeJSON(output);
749
InspectorObjectBase::InspectorObjectBase()
750
: InspectorValue(TypeObject)
756
InspectorArrayBase::~InspectorArrayBase()
760
bool InspectorArrayBase::asArray(RefPtr<InspectorArray>* output)
762
COMPILE_ASSERT(sizeof(InspectorArrayBase) == sizeof(InspectorArray), cannot_cast);
763
*output = static_cast<InspectorArray*>(this);
767
PassRefPtr<InspectorArray> InspectorArrayBase::asArray()
769
COMPILE_ASSERT(sizeof(InspectorArrayBase) == sizeof(InspectorArray), cannot_cast);
770
return static_cast<InspectorArray*>(this);
773
void InspectorArrayBase::writeJSON(StringBuilder* output) const
776
for (Vector<RefPtr<InspectorValue> >::const_iterator it = m_data.begin(); it != m_data.end(); ++it) {
777
if (it != m_data.begin())
779
(*it)->writeJSON(output);
784
InspectorArrayBase::InspectorArrayBase()
785
: InspectorValue(TypeArray)
790
PassRefPtr<InspectorValue> InspectorArrayBase::get(size_t index)
792
ASSERT(index < m_data.size());
793
return m_data[index];
796
} // namespace WebCore