[webkit-changes] [60774] trunk/WebCore
Eric Seidel
eric at webkit.org
Tue Jun 8 16:41:56 PDT 2010
On Tue, Jun 8, 2010 at 4:40 PM, Oliver Hunt <oliver at apple.com> wrote:
> Why do we need this? why can't we just use the same logic used for
> postMessage? Having multiple different functions to do object serialisation
> seems unnecessary.
> --Oliver
>
>
> On Jun 7, 2010, at 4:33 AM, eric at webkit.org wrote:
>
> Revision 60774 Author eric at webkit.org Date 2010-06-07 04:33:11 -0700 (Mon,
> 07 Jun 2010)
>
> Log Message
>
> 2010-06-07 Pavel Podivilov <podivilov at chromium.org>
>
> Reviewed by Pavel Feldman.
>
> Web Inspector: Implement JSON parsing for InspectorValue.
> https://bugs.webkit.org/show_bug.cgi?id=40064
>
> * inspector/InspectorValues.cpp:
> (WebCore::):
> (WebCore::InspectorValue::asBool):
> (WebCore::InspectorValue::asNumber):
> (WebCore::InspectorValue::asString):
> (WebCore::InspectorValue::asObject):
> (WebCore::InspectorValue::asArray):
> (WebCore::InspectorValue::readJSON):
> (WebCore::InspectorValue::writeJSON):
> (WebCore::InspectorBasicValue::asBool):
> (WebCore::InspectorBasicValue::asNumber):
> (WebCore::InspectorBasicValue::writeJSON):
> (WebCore::InspectorString::asString):
> (WebCore::InspectorObject::asObject):
> (WebCore::InspectorObject::getBool):
> (WebCore::InspectorObject::getNumber):
> (WebCore::InspectorObject::getString):
> (WebCore::InspectorObject::getObject):
> (WebCore::InspectorObject::getArray):
> (WebCore::InspectorObject::get):
> (WebCore::InspectorArray::asArray):
> * inspector/InspectorValues.h:
> (WebCore::InspectorObject::begin):
> (WebCore::InspectorObject::end):
>
> Modified Paths
>
> trunk/WebCore/ChangeLog
> trunk/WebCore/inspector/InspectorValues.cpp
> trunk/WebCore/inspector/InspectorValues.h
>
> Diff
>
> Modified: trunk/WebCore/ChangeLog (60773 => 60774)
>
> --- trunk/WebCore/ChangeLog 2010-06-07 11:24:14 UTC (rev 60773)
> +++ trunk/WebCore/ChangeLog 2010-06-07 11:33:11 UTC (rev 60774)
> @@ -1,3 +1,35 @@
> +2010-06-07 Pavel Podivilov <podivilov at chromium.org>
> +
> + Reviewed by Pavel Feldman.
> +
> + Web Inspector: Implement JSON parsing for InspectorValue.
> + https://bugs.webkit.org/show_bug.cgi?id=40064
> +
> + * inspector/InspectorValues.cpp:
> + (WebCore::):
> + (WebCore::InspectorValue::asBool):
> + (WebCore::InspectorValue::asNumber):
> + (WebCore::InspectorValue::asString):
> + (WebCore::InspectorValue::asObject):
> + (WebCore::InspectorValue::asArray):
> + (WebCore::InspectorValue::readJSON):
> + (WebCore::InspectorValue::writeJSON):
> + (WebCore::InspectorBasicValue::asBool):
> + (WebCore::InspectorBasicValue::asNumber):
> + (WebCore::InspectorBasicValue::writeJSON):
> + (WebCore::InspectorString::asString):
> + (WebCore::InspectorObject::asObject):
> + (WebCore::InspectorObject::getBool):
> + (WebCore::InspectorObject::getNumber):
> + (WebCore::InspectorObject::getString):
> + (WebCore::InspectorObject::getObject):
> + (WebCore::InspectorObject::getArray):
> + (WebCore::InspectorObject::get):
> + (WebCore::InspectorArray::asArray):
> + * inspector/InspectorValues.h:
> + (WebCore::InspectorObject::begin):
> + (WebCore::InspectorObject::end):
> +
> 2010-06-07 Jocelyn Turcotte <jocelyn.turcotte at nokia.com>
>
> Reviewed by Simon Hausmann.
>
> Modified: trunk/WebCore/inspector/InspectorValues.cpp (60773 => 60774)
>
> --- trunk/WebCore/inspector/InspectorValues.cpp 2010-06-07 11:24:14 UTC (rev
> 60773)
> +++ trunk/WebCore/inspector/InspectorValues.cpp 2010-06-07 11:33:11 UTC (rev
> 60774)
> @@ -35,6 +35,407 @@
>
> namespace WebCore {
>
> +namespace {
> +
> +static const int stackLimit = 1000;
> +
> +enum Token {
> + OBJECT_BEGIN,
> + OBJECT_END,
> + ARRAY_BEGIN,
> + ARRAY_END,
> + STRING,
> + NUMBER,
> + BOOL_TRUE,
> + BOOL_FALSE,
> + NULL_TOKEN,
> + LIST_SEPARATOR,
> + OBJECT_PAIR_SEPARATOR,
> + INVALID_TOKEN,
> +};
> +
> +const char* const nullString = "null";
> +const char* const trueString = "true";
> +const char* const falseString = "false";
> +
> +bool parseConstToken(const UChar* start, const UChar* end, const UChar**
> tokenEnd, const char* token)
> +{
> + while (start < end && *token != '\0' && *start++ == *token++) { }
> + if (*token != '\0')
> + return false;
> + *tokenEnd = start;
> + return true;
> +}
> +
> +bool readInt(const UChar* start, const UChar* end, const UChar** tokenEnd,
> bool canHaveLeadingZeros)
> +{
> + if (start == end)
> + return false;
> + bool haveLeadingZero = '0' == *start;
> + int length = 0;
> + while (start < end && '0' <= *start && *start <= '9') {
> + ++start;
> + ++length;
> + }
> + if (!length)
> + return false;
> + if (!canHaveLeadingZeros && length > 1 && haveLeadingZero)
> + return false;
> + *tokenEnd = start;
> + return true;
> +}
> +
> +bool parseNumberToken(const UChar* start, const UChar* end, const UChar**
> tokenEnd)
> +{
> + // We just grab the number here. We validate the size in DecodeNumber.
> + // According to RFC4627, a valid number is: [minus] int [frac] [exp]
> + if (start == end)
> + return false;
> + UChar c = *start;
> + if ('-' == c)
> + ++start;
> +
> + if (!readInt(start, end, &start, false))
> + return false;
> + if (start == end) {
> + *tokenEnd = start;
> + return true;
> + }
> +
> + // Optional fraction part
> + c = *start;
> + if ('.' == c) {
> + ++start;
> + if (!readInt(start, end, &start, true))
> + return false;
> + if (start == end) {
> + *tokenEnd = start;
> + return true;
> + }
> + c = *start;
> + }
> +
> + // Optional exponent part
> + if ('e' == c || 'E' == c) {
> + ++start;
> + if (start == end)
> + return false;
> + c = *start;
> + if ('-' == c || '+' == c) {
> + ++start;
> + if (start == end)
> + return false;
> + }
> + if (!readInt(start, end, &start, true))
> + return false;
> + }
> +
> + *tokenEnd = start;
> + return true;
> +}
> +
> +bool readHexDigits(const UChar* start, const UChar* end, const UChar**
> tokenEnd, int digits)
> +{
> + if (end - start < digits)
> + return false;
> + for (int i = 0; i < digits; ++i) {
> + UChar c = *start++;
> + if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c
> && c <= 'F')))
> + return false;
> + }
> + *tokenEnd = start;
> + return true;
> +}
> +
> +bool parseStringToken(const UChar* start, const UChar* end, const UChar**
> tokenEnd)
> +{
> + while (start < end) {
> + UChar c = *start++;
> + if ('\\' == c) {
> + c = *start++;
> + // Make sure the escaped char is valid.
> + switch (c) {
> + case 'x':
> + if (!readHexDigits(start, end, &start, 2))
> + return false;
> + break;
> + case 'u':
> + if (!readHexDigits(start, end, &start, 4))
> + return false;
> + break;
> + case '\\':
> + case '/':
> + case 'b':
> + case 'f':
> + case 'n':
> + case 'r':
> + case 't':
> + case 'v':
> + case '"':
> + break;
> + default:
> + return false;
> + }
> + } else if ('"' == c) {
> + *tokenEnd = start;
> + return true;
> + }
> + }
> + return false;
> +}
> +
> +Token parseToken(const UChar* start, const UChar* end, const UChar**
> tokenEnd)
> +{
> + if (start == end)
> + return INVALID_TOKEN;
> +
> + switch (*start) {
> + case 'n':
> + if (parseConstToken(start, end, tokenEnd, nullString))
> + return NULL_TOKEN;
> + break;
> + case 't':
> + if (parseConstToken(start, end, tokenEnd, trueString))
> + return BOOL_TRUE;
> + break;
> + case 'f':
> + if (parseConstToken(start, end, tokenEnd, falseString))
> + return BOOL_FALSE;
> + break;
> + case '[':
> + *tokenEnd = start + 1;
> + return ARRAY_BEGIN;
> + case ']':
> + *tokenEnd = start + 1;
> + return ARRAY_END;
> + case ',':
> + *tokenEnd = start + 1;
> + return LIST_SEPARATOR;
> + case '{':
> + *tokenEnd = start + 1;
> + return OBJECT_BEGIN;
> + case '}':
> + *tokenEnd = start + 1;
> + return OBJECT_END;
> + case ':':
> + *tokenEnd = start + 1;
> + return OBJECT_PAIR_SEPARATOR;
> + case '0':
> + case '1':
> + case '2':
> + case '3':
> + case '4':
> + case '5':
> + case '6':
> + case '7':
> + case '8':
> + case '9':
> + case '-':
> + if (parseNumberToken(start, end, tokenEnd))
> + return NUMBER;
> + break;
> + case '"':
> + if (parseStringToken(start + 1, end, tokenEnd))
> + return STRING;
> + break;
> + }
> + return INVALID_TOKEN;
> +}
> +
> +inline int hexToInt(UChar c)
> +{
> + if ('0' <= c && c <= '9')
> + return c - '0';
> + if ('A' <= c && c <= 'F')
> + return c - 'A' + 10;
> + if ('a' <= c && c <= 'f')
> + return c - 'a' + 10;
> + ASSERT_NOT_REACHED();
> + return 0;
> +}
> +
> +bool decodeString(const UChar* start, const UChar* end, Vector<UChar>*
> output)
> +{
> + while (start < end) {
> + UChar c = *start++;
> + if ('\\' != c) {
> + output->append(c);
> + continue;
> + }
> + c = *start++;
> + switch (c) {
> + case '"':
> + case '/':
> + case '\\':
> + break;
> + case 'b':
> + c = '\b';
> + break;
> + case 'f':
> + c = '\f';
> + break;
> + case 'n':
> + c = '\n';
> + break;
> + case 'r':
> + c = '\r';
> + break;
> + case 't':
> + c = '\t';
> + break;
> + case 'v':
> + c = '\v';
> + break;
> + case 'x':
> + c = (hexToInt(*start) << 4) +
> + hexToInt(*(start + 1));
> + start += 2;
> + break;
> + case 'u':
> + c = (hexToInt(*start) << 12) +
> + (hexToInt(*(start + 1)) << 8) +
> + (hexToInt(*(start + 2)) << 4) +
> + hexToInt(*(start + 3));
> + start += 4;
> + break;
> + default:
> + return false;
> + }
> + output->append(c);
> + }
> + return true;
> +}
> +
> +bool decodeString(const UChar* start, const UChar* end, String* output)
> +{
> + if (start == end) {
> + *output = "";
> + return true;
> + }
> + if (start > end)
> + return false;
> + Vector<UChar> buffer;
> + buffer.reserveCapacity(end - start);
> + if (!decodeString(start, end, &buffer))
> + return false;
> + *output = String(buffer.data(), buffer.size());
> + return true;
> +}
> +
> +PassRefPtr<InspectorValue> buildValue(const UChar* start, const UChar* end,
> const UChar** valueTokenEnd, int depth)
> +{
> + if (depth > stackLimit)
> + return 0;
> +
> + RefPtr<InspectorValue> result;
> + const UChar* tokenEnd;
> + Token token = parseToken(start, end, &tokenEnd);
> + switch (token) {
> + case INVALID_TOKEN:
> + return 0;
> + case NULL_TOKEN:
> + result = InspectorValue::null();
> + break;
> + case BOOL_TRUE:
> + result = InspectorBasicValue::create(true);
> + break;
> + case BOOL_FALSE:
> + result = InspectorBasicValue::create(false);
> + break;
> + case NUMBER: {
> + bool ok;
> + double value = charactersToDouble(start, tokenEnd - start, &ok);
> + if (!ok)
> + return 0;
> + result = InspectorBasicValue::create(value);
> + break;
> + }
> + case STRING: {
> + String value;
> + bool ok = decodeString(start + 1, tokenEnd - 1, &value);
> + if (!ok)
> + return 0;
> + result = InspectorString::create(value);
> + break;
> + }
> + case ARRAY_BEGIN: {
> + RefPtr<InspectorArray> array = InspectorArray::create();
> + start = tokenEnd;
> + token = parseToken(start, end, &tokenEnd);
> + while (token != ARRAY_END) {
> + RefPtr<InspectorValue> arrayNode = buildValue(start, end,
> &tokenEnd, depth + 1);
> + if (!arrayNode)
> + return 0;
> + array->push(arrayNode);
> +
> + // After a list value, we expect a comma or the end of the
> list.
> + start = tokenEnd;
> + token = parseToken(start, end, &tokenEnd);
> + if (token == LIST_SEPARATOR) {
> + start = tokenEnd;
> + token = parseToken(start, end, &tokenEnd);
> + if (token == ARRAY_END)
> + return 0;
> + } else if (token != ARRAY_END) {
> + // Unexpected value after list value. Bail out.
> + return 0;
> + }
> + }
> + if (token != ARRAY_END)
> + return 0;
> + result = array.release();
> + break;
> + }
> + case OBJECT_BEGIN: {
> + RefPtr<InspectorObject> object = InspectorObject::create();
> + start = tokenEnd;
> + token = parseToken(start, end, &tokenEnd);
> + while (token != OBJECT_END) {
> + if (token != STRING)
> + return 0;
> + String key;
> + if (!decodeString(start + 1, tokenEnd - 1, &key))
> + return 0;
> + start = tokenEnd;
> +
> + token = parseToken(start, end, &tokenEnd);
> + if (token != OBJECT_PAIR_SEPARATOR)
> + return 0;
> + start = tokenEnd;
> +
> + RefPtr<InspectorValue> value = buildValue(start, end,
> &tokenEnd, depth + 1);
> + if (!value)
> + return 0;
> + object->set(key, value);
> + start = tokenEnd;
> +
> + // After a key/value pair, we expect a comma or the end of the
> + // object.
> + token = parseToken(start, end, &tokenEnd);
> + if (token == LIST_SEPARATOR) {
> + start = tokenEnd;
> + token = parseToken(start, end, &tokenEnd);
> + if (token == OBJECT_END)
> + return 0;
> + } else if (token != OBJECT_END) {
> + // Unexpected value after last object value. Bail out.
> + return 0;
> + }
> + }
> + if (token != OBJECT_END)
> + return 0;
> + result = object.release();
> + break;
> + }
> +
> + default:
> + // We got a token that's not a value.
> + return 0;
> + }
> + *valueTokenEnd = tokenEnd;
> + return result.release();
> +}
> +
> inline bool escapeChar(UChar c, Vector<UChar>* dst)
> {
> switch (c) {
> @@ -71,6 +472,44 @@
> dst->append('"');
> }
>
> +} // anonymous namespace
> +
> +bool InspectorValue::asBool(bool*) const
> +{
> + return false;
> +}
> +
> +bool InspectorValue::asNumber(double*) const
> +{
> + return false;
> +}
> +
> +bool InspectorValue::asString(String*) const
> +{
> + return false;
> +}
> +
> +PassRefPtr<InspectorObject> InspectorValue::asObject()
> +{
> + return 0;
> +}
> +
> +PassRefPtr<InspectorArray> InspectorValue::asArray()
> +{
> + return 0;
> +}
> +
> +PassRefPtr<InspectorValue> InspectorValue::readJSON(const String& json)
> +{
> + const UChar* start = json.characters();
> + const UChar* end = json.characters() + json.length();
> + const UChar *tokenEnd;
> + RefPtr<InspectorValue> value = buildValue(start, end, &tokenEnd, 0);
> + if (!value || tokenEnd != end)
> + return 0;
> + return value.release();
> +}
> +
> String InspectorValue::toJSONString() const
> {
> Vector<UChar> result;
> @@ -82,29 +521,104 @@
> void InspectorValue::writeJSON(Vector<UChar>* output) const
> {
> ASSERT(m_type == TypeNull);
> - output->append("null", 4);
> + output->append(nullString, 4);
> }
>
> +bool InspectorBasicValue::asBool(bool* output) const
> +{
> + if (type() != TypeBoolean)
> + return false;
> + *output = m_boolValue;
> + return true;
> +}
> +
> +bool InspectorBasicValue::asNumber(double* output) const
> +{
> + if (type() != TypeDouble)
> + return false;
> + *output = m_doubleValue;
> + return true;
> +}
> +
> void InspectorBasicValue::writeJSON(Vector<UChar>* output) const
> {
> ASSERT(type() == TypeBoolean || type() == TypeDouble);
> if (type() == TypeBoolean) {
> if (m_boolValue)
> - output->append("true", 4);
> + output->append(trueString, 4);
> else
> - output->append("false", 5);
> + output->append(falseString, 5);
> } else if (type() == TypeDouble) {
> String value = String::format("%f", m_doubleValue);
> output->append(value.characters(), value.length());
> }
> }
>
> +bool InspectorString::asString(String* output) const
> +{
> + *output = m_stringValue;
> + return true;
> +}
> +
> void InspectorString::writeJSON(Vector<UChar>* output) const
> {
> ASSERT(type() == TypeString);
> doubleQuoteString(m_stringValue, output);
> }
>
> +PassRefPtr<InspectorObject> InspectorObject::asObject()
> +{
> + return this;
> +}
> +
> +bool InspectorObject::getBool(const String& name, bool* output) const
> +{
> + RefPtr<InspectorValue> value = get(name);
> + if (!value)
> + return false;
> + return value->asBool(output);
> +}
> +
> +bool InspectorObject::getNumber(const String& name, double* output) const
> +{
> + RefPtr<InspectorValue> value = get(name);
> + if (!value)
> + return false;
> + return value->asNumber(output);
> +}
> +
> +bool InspectorObject::getString(const String& name, String* output) const
> +{
> + RefPtr<InspectorValue> value = get(name);
> + if (!value)
> + return false;
> + return value->asString(output);
> +}
> +
> +PassRefPtr<InspectorObject> InspectorObject::getObject(const String& name)
> const
> +{
> + PassRefPtr<InspectorValue> value = get(name);
> + if (!value)
> + return false;
> + return value->asObject();
> +}
> +
> +PassRefPtr<InspectorArray> InspectorObject::getArray(const String& name)
> const
> +{
> + PassRefPtr<InspectorValue> value = get(name);
> + if (!value)
> + return false;
> + return value->asArray();
> +}
> +
> +PassRefPtr<InspectorValue> InspectorObject::get(const String& name) const
> +{
> + Dictionary::const_iterator it = m_data.find(name);
> + if (it == m_data.end())
> + return 0;
> + return it->second;
> +}
> +
> void InspectorObject::writeJSON(Vector<UChar>* output) const
> {
> output->append('{');
> @@ -120,6 +634,11 @@
> output->append('}');
> }
>
> +PassRefPtr<InspectorArray> InspectorArray::asArray()
> +{
> + return this;
> +}
> +
> void InspectorArray::writeJSON(Vector<UChar>* output) const
> {
> output->append('[');
>
> Modified: trunk/WebCore/inspector/InspectorValues.h (60773 => 60774)
>
> --- trunk/WebCore/inspector/InspectorValues.h 2010-06-07 11:24:14 UTC (rev
> 60773)
> +++ trunk/WebCore/inspector/InspectorValues.h 2010-06-07 11:33:11 UTC (rev
> 60774)
> @@ -42,6 +42,8 @@
>
> namespace WebCore {
>
> +class InspectorArray;
> +class InspectorObject;
> class String;
>
> class InspectorValue : public RefCounted<InspectorValue> {
> @@ -65,6 +67,14 @@
>
> Type type() const { return m_type; }
>
> + virtual bool asBool(bool* output) const;
> + virtual bool asNumber(double* output) const;
> + virtual bool asString(String* output) const;
> + virtual PassRefPtr<InspectorObject> asObject();
> + virtual PassRefPtr<InspectorArray> asArray();
> +
> + static PassRefPtr<InspectorValue> readJSON(const String& json);
> +
> String toJSONString() const;
> virtual void writeJSON(Vector<UChar>* output) const;
>
> @@ -93,6 +103,9 @@
> return adoptRef(new InspectorBasicValue(value));
> }
>
> + virtual bool asBool(bool* output) const;
> + virtual bool asNumber(double* output) const;
> +
> virtual void writeJSON(Vector<UChar>* output) const;
>
> private:
> @@ -117,6 +130,9 @@
> {
> return adoptRef(new InspectorString(value));
> }
> +
> + virtual bool asString(String* output) const;
> +
> virtual void writeJSON(Vector<UChar>* output) const;
>
> private:
> @@ -127,23 +143,43 @@
> };
>
> class InspectorObject : public InspectorValue {
> +private:
> + typedef HashMap<String, RefPtr<InspectorValue> > Dictionary;
> +
> public:
> + typedef Dictionary::iterator iterator;
> + typedef Dictionary::const_iterator const_iterator;
> +
> +public:
> static PassRefPtr<InspectorObject> create()
> {
> return adoptRef(new InspectorObject());
> }
> ~InspectorObject() { }
>
> + virtual PassRefPtr<InspectorObject> asObject();
> +
> void setBool(const String& name, bool);
> void setNumber(const String& name, double);
> void setString(const String& name, const String&);
> void set(const String& name, PassRefPtr<InspectorValue>);
>
> + bool getBool(const String& name, bool* output) const;
> + bool getNumber(const String& name, double* output) const;
> + bool getString(const String& name, String* output) const;
> + PassRefPtr<InspectorObject> getObject(const String& name) const;
> + PassRefPtr<InspectorArray> getArray(const String& name) const;
> + PassRefPtr<InspectorValue> get(const String& name) const;
> +
> virtual void writeJSON(Vector<UChar>* output) const;
>
> + iterator begin() { return m_data.begin(); }
> + iterator end() { return m_data.end(); }
> + const_iterator begin() const { return m_data.begin(); }
> + const_iterator end() const { return m_data.end(); }
> +
> private:
> InspectorObject() : InspectorValue(TypeObject) { }
> - typedef HashMap<String, RefPtr<InspectorValue> > Dictionary;
> Dictionary m_data;
> Vector<String> m_order;
> };
> @@ -156,6 +192,8 @@
> }
> ~InspectorArray() { }
>
> + virtual PassRefPtr<InspectorArray> asArray();
> +
> void pushBool(bool);
> void pushNumber(double);
> void pushString(const String&);
> @@ -214,4 +252,3 @@
>
> #endif // ENABLE(INSPECTOR)
> #endif // !defined(InspectorValues_h)
> -
>
> _______________________________________________
> webkit-changes mailing list
> webkit-changes at lists.webkit.org
> http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes
>
>
More information about the webkit-changes
mailing list