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"
36 #include <wtf/DecimalNumber.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** tokenEnd)
192 return INVALID_TOKEN;
196 if (parseConstToken(start, end, tokenEnd, nullString))
200 if (parseConstToken(start, end, tokenEnd, trueString))
204 if (parseConstToken(start, end, tokenEnd, falseString))
208 *tokenEnd = start + 1;
211 *tokenEnd = start + 1;
214 *tokenEnd = start + 1;
215 return LIST_SEPARATOR;
217 *tokenEnd = start + 1;
220 *tokenEnd = start + 1;
223 *tokenEnd = start + 1;
224 return OBJECT_PAIR_SEPARATOR;
236 if (parseNumberToken(start, end, tokenEnd))
240 if (parseStringToken(start + 1, end, tokenEnd))
244 return INVALID_TOKEN;
247 inline int hexToInt(UChar c)
249 if ('0' <= c && c <= '9')
251 if ('A' <= c && c <= 'F')
253 if ('a' <= c && c <= 'f')
255 ASSERT_NOT_REACHED();
259 bool decodeString(const UChar* start, const UChar* end, Vector<UChar>* output)
261 while (start < end) {
292 c = (hexToInt(*start) << 4) +
293 hexToInt(*(start + 1));
297 c = (hexToInt(*start) << 12) +
298 (hexToInt(*(start + 1)) << 8) +
299 (hexToInt(*(start + 2)) << 4) +
300 hexToInt(*(start + 3));
311 bool decodeString(const UChar* start, const UChar* end, String* output)
319 Vector<UChar> buffer;
320 buffer.reserveCapacity(end - start);
321 if (!decodeString(start, end, &buffer))
323 *output = String(buffer.data(), buffer.size());
327 PassRefPtr<InspectorValue> buildValue(const UChar* start, const UChar* end, const UChar** valueTokenEnd, int depth)
329 if (depth > stackLimit)
332 RefPtr<InspectorValue> result;
333 const UChar* tokenEnd;
334 Token token = parseToken(start, end, &tokenEnd);
339 result = InspectorValue::null();
342 result = InspectorBasicValue::create(true);
345 result = InspectorBasicValue::create(false);
349 double value = charactersToDouble(start, tokenEnd - start, &ok);
352 result = InspectorBasicValue::create(value);
357 bool ok = decodeString(start + 1, tokenEnd - 1, &value);
360 result = InspectorString::create(value);
364 RefPtr<InspectorArray> array = InspectorArray::create();
366 token = parseToken(start, end, &tokenEnd);
367 while (token != ARRAY_END) {
368 RefPtr<InspectorValue> arrayNode = buildValue(start, end, &tokenEnd, depth + 1);
371 array->pushValue(arrayNode);
373 // After a list value, we expect a comma or the end of the list.
375 token = parseToken(start, end, &tokenEnd);
376 if (token == LIST_SEPARATOR) {
378 token = parseToken(start, end, &tokenEnd);
379 if (token == ARRAY_END)
381 } else if (token != ARRAY_END) {
382 // Unexpected value after list value. Bail out.
386 if (token != ARRAY_END)
388 result = array.release();
392 RefPtr<InspectorObject> object = InspectorObject::create();
394 token = parseToken(start, end, &tokenEnd);
395 while (token != OBJECT_END) {
399 if (!decodeString(start + 1, tokenEnd - 1, &key))
403 token = parseToken(start, end, &tokenEnd);
404 if (token != OBJECT_PAIR_SEPARATOR)
408 RefPtr<InspectorValue> value = buildValue(start, end, &tokenEnd, depth + 1);
411 object->setValue(key, value);
414 // After a key/value pair, we expect a comma or the end of the
416 token = parseToken(start, end, &tokenEnd);
417 if (token == LIST_SEPARATOR) {
419 token = parseToken(start, end, &tokenEnd);
420 if (token == OBJECT_END)
422 } else if (token != OBJECT_END) {
423 // Unexpected value after last object value. Bail out.
427 if (token != OBJECT_END)
429 result = object.release();
434 // We got a token that's not a value.
437 *valueTokenEnd = tokenEnd;
438 return result.release();
441 inline bool escapeChar(UChar c, Vector<UChar>* dst)
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;
457 inline void doubleQuoteString(const String& str, Vector<UChar>* dst)
460 for (unsigned i = 0; i < str.length(); ++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());
477 } // anonymous namespace
479 bool InspectorValue::asBoolean(bool*) const
484 bool InspectorValue::asNumber(double*) const
489 bool InspectorValue::asNumber(long*) const
494 bool InspectorValue::asNumber(int*) const
499 bool InspectorValue::asNumber(unsigned long*) const
504 bool InspectorValue::asNumber(unsigned int*) const
509 bool InspectorValue::asString(String*) const
514 bool InspectorValue::asValue(RefPtr<InspectorValue>* output)
520 bool InspectorValue::asObject(RefPtr<InspectorObject>*)
525 bool InspectorValue::asArray(RefPtr<InspectorArray>*)
530 PassRefPtr<InspectorObject> InspectorValue::asObject()
535 PassRefPtr<InspectorArray> InspectorValue::asArray()
540 PassRefPtr<InspectorValue> InspectorValue::parseJSON(const String& json)
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)
548 return value.release();
551 String InspectorValue::toJSONString() const
553 Vector<UChar> result;
554 result.reserveCapacity(512);
556 return String(result.data(), result.size());
559 void InspectorValue::writeJSON(Vector<UChar>* output) const
561 ASSERT(m_type == TypeNull);
562 output->append(nullString, 4);
565 bool InspectorBasicValue::asBoolean(bool* output) const
567 if (type() != TypeBoolean)
569 *output = m_boolValue;
573 bool InspectorBasicValue::asNumber(double* output) const
575 if (type() != TypeNumber)
577 *output = m_doubleValue;
581 bool InspectorBasicValue::asNumber(long* output) const
583 if (type() != TypeNumber)
585 *output = static_cast<long>(m_doubleValue);
589 bool InspectorBasicValue::asNumber(int* output) const
591 if (type() != TypeNumber)
593 *output = static_cast<int>(m_doubleValue);
597 bool InspectorBasicValue::asNumber(unsigned long* output) const
599 if (type() != TypeNumber)
601 *output = static_cast<unsigned long>(m_doubleValue);
605 bool InspectorBasicValue::asNumber(unsigned int* output) const
607 if (type() != TypeNumber)
609 *output = static_cast<unsigned int>(m_doubleValue);
613 void InspectorBasicValue::writeJSON(Vector<UChar>* output) const
615 ASSERT(type() == TypeBoolean || type() == TypeNumber);
616 if (type() == TypeBoolean) {
618 output->append(trueString, 4);
620 output->append(falseString, 5);
621 } else if (type() == TypeNumber) {
622 NumberToStringBuffer buffer;
623 unsigned length = DecimalNumber(m_doubleValue).toStringDecimal(buffer, WTF::NumberToStringBufferLength);
624 output->append(buffer, length);
628 bool InspectorString::asString(String* output) const
630 *output = m_stringValue;
634 void InspectorString::writeJSON(Vector<UChar>* output) const
636 ASSERT(type() == TypeString);
637 doubleQuoteString(m_stringValue, output);
640 InspectorObject::~InspectorObject()
644 bool InspectorObject::asObject(RefPtr<InspectorObject>* output)
650 PassRefPtr<InspectorObject> InspectorObject::asObject()
655 bool InspectorObject::getBoolean(const String& name, bool* output) const
657 RefPtr<InspectorValue> value = get(name);
660 return value->asBoolean(output);
663 bool InspectorObject::getString(const String& name, String* output) const
665 RefPtr<InspectorValue> value = get(name);
668 return value->asString(output);
671 PassRefPtr<InspectorObject> InspectorObject::getObject(const String& name) const
673 PassRefPtr<InspectorValue> value = get(name);
676 return value->asObject();
679 PassRefPtr<InspectorArray> InspectorObject::getArray(const String& name) const
681 PassRefPtr<InspectorValue> value = get(name);
684 return value->asArray();
687 PassRefPtr<InspectorValue> InspectorObject::get(const String& name) const
689 Dictionary::const_iterator it = m_data.find(name);
690 if (it == m_data.end())
695 void InspectorObject::remove(const String& name)
698 for (size_t i = 0; i < m_order.size(); ++i) {
699 if (m_order[i] == name) {
706 void InspectorObject::writeJSON(Vector<UChar>* output) const
709 for (size_t i = 0; i < m_order.size(); ++i) {
710 Dictionary::const_iterator it = m_data.find(m_order[i]);
711 ASSERT(it != m_data.end());
714 doubleQuoteString(it->first, output);
716 it->second->writeJSON(output);
721 InspectorObject::InspectorObject()
722 : InspectorValue(TypeObject)
728 InspectorArray::~InspectorArray()
732 bool InspectorArray::asArray(RefPtr<InspectorArray>* output)
738 PassRefPtr<InspectorArray> InspectorArray::asArray()
743 void InspectorArray::writeJSON(Vector<UChar>* output) const
746 for (Vector<RefPtr<InspectorValue> >::const_iterator it = m_data.begin(); it != m_data.end(); ++it) {
747 if (it != m_data.begin())
749 (*it)->writeJSON(output);
754 InspectorArray::InspectorArray()
755 : InspectorValue(TypeArray)
760 PassRefPtr<InspectorValue> InspectorArray::get(size_t index)
762 ASSERT(index < m_data.size());
763 return m_data[index];
766 } // namespace WebCore
768 #endif // ENABLE(INSPECTOR)