|  | /* | 
|  | * Copyright (C) 2010 Google Inc. All rights reserved. | 
|  | * | 
|  | * Redistribution and use in source and binary forms, with or without | 
|  | * modification, are permitted provided that the following conditions are | 
|  | * met: | 
|  | * | 
|  | *     * Redistributions of source code must retain the above copyright | 
|  | * notice, this list of conditions and the following disclaimer. | 
|  | *     * Redistributions in binary form must reproduce the above | 
|  | * copyright notice, this list of conditions and the following disclaimer | 
|  | * in the documentation and/or other materials provided with the | 
|  | * distribution. | 
|  | *     * Neither the name of Google Inc. nor the names of its | 
|  | * contributors may be used to endorse or promote products derived from | 
|  | * this software without specific prior written permission. | 
|  | * | 
|  | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
|  | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
|  | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
|  | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
|  | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
|  | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
|  | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|  | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | */ | 
|  |  | 
|  | #include "platform/json/JSONValues.h" | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <cmath> | 
|  | #include "platform/Decimal.h" | 
|  | #include "platform/wtf/MathExtras.h" | 
|  | #include "platform/wtf/text/StringBuilder.h" | 
|  |  | 
|  | namespace blink { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | inline bool EscapeChar(UChar c, StringBuilder* dst) { | 
|  | switch (c) { | 
|  | case '\b': | 
|  | dst->Append("\\b"); | 
|  | break; | 
|  | case '\f': | 
|  | dst->Append("\\f"); | 
|  | break; | 
|  | case '\n': | 
|  | dst->Append("\\n"); | 
|  | break; | 
|  | case '\r': | 
|  | dst->Append("\\r"); | 
|  | break; | 
|  | case '\t': | 
|  | dst->Append("\\t"); | 
|  | break; | 
|  | case '\\': | 
|  | dst->Append("\\\\"); | 
|  | break; | 
|  | case '"': | 
|  | dst->Append("\\\""); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | const LChar kHexDigits[17] = "0123456789ABCDEF"; | 
|  |  | 
|  | void AppendUnsignedAsHex(UChar number, StringBuilder* dst) { | 
|  | dst->Append("\\u"); | 
|  | for (size_t i = 0; i < 4; ++i) { | 
|  | dst->Append(kHexDigits[(number & 0xF000) >> 12]); | 
|  | number <<= 4; | 
|  | } | 
|  | } | 
|  |  | 
|  | void WriteIndent(int depth, StringBuilder* output) { | 
|  | for (int i = 0; i < depth; ++i) | 
|  | output->Append("  "); | 
|  | } | 
|  |  | 
|  | }  // anonymous namespace | 
|  |  | 
|  | const char* kJSONNullString = "null"; | 
|  | const char* kJSONTrueString = "true"; | 
|  | const char* kJSONFalseString = "false"; | 
|  |  | 
|  | void EscapeStringForJSON(const String& str, StringBuilder* dst) { | 
|  | for (unsigned i = 0; i < str.length(); ++i) { | 
|  | UChar c = str[i]; | 
|  | if (!EscapeChar(c, dst)) { | 
|  | if (c < 32 || c > 126 || c == '<' || c == '>') { | 
|  | // 1. Escaping <, > to prevent script execution. | 
|  | // 2. Technically, we could also pass through c > 126 as UTF8, but this | 
|  | //    is also optional. It would also be a pain to implement here. | 
|  | AppendUnsignedAsHex(c, dst); | 
|  | } else { | 
|  | dst->Append(c); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void DoubleQuoteStringForJSON(const String& str, StringBuilder* dst) { | 
|  | dst->Append('"'); | 
|  | EscapeStringForJSON(str, dst); | 
|  | dst->Append('"'); | 
|  | } | 
|  |  | 
|  | String JSONValue::QuoteString(const String& input) { | 
|  | StringBuilder builder; | 
|  | DoubleQuoteStringForJSON(input, &builder); | 
|  | return builder.ToString(); | 
|  | } | 
|  |  | 
|  | bool JSONValue::AsBoolean(bool*) const { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool JSONValue::AsDouble(double*) const { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool JSONValue::AsInteger(int*) const { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool JSONValue::AsString(String*) const { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | String JSONValue::ToJSONString() const { | 
|  | StringBuilder result; | 
|  | result.ReserveCapacity(512); | 
|  | WriteJSON(&result); | 
|  | return result.ToString(); | 
|  | } | 
|  |  | 
|  | String JSONValue::ToPrettyJSONString() const { | 
|  | StringBuilder result; | 
|  | result.ReserveCapacity(512); | 
|  | PrettyWriteJSON(&result); | 
|  | return result.ToString(); | 
|  | } | 
|  |  | 
|  | void JSONValue::WriteJSON(StringBuilder* output) const { | 
|  | DCHECK(type_ == kTypeNull); | 
|  | output->Append(kJSONNullString, 4); | 
|  | } | 
|  |  | 
|  | void JSONValue::PrettyWriteJSON(StringBuilder* output) const { | 
|  | PrettyWriteJSONInternal(output, 0); | 
|  | output->Append('\n'); | 
|  | } | 
|  |  | 
|  | void JSONValue::PrettyWriteJSONInternal(StringBuilder* output, | 
|  | int depth) const { | 
|  | WriteJSON(output); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<JSONValue> JSONValue::Clone() const { | 
|  | return JSONValue::Null(); | 
|  | } | 
|  |  | 
|  | bool JSONBasicValue::AsBoolean(bool* output) const { | 
|  | if (GetType() != kTypeBoolean) | 
|  | return false; | 
|  | *output = bool_value_; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool JSONBasicValue::AsDouble(double* output) const { | 
|  | if (GetType() == kTypeDouble) { | 
|  | *output = double_value_; | 
|  | return true; | 
|  | } | 
|  | if (GetType() == kTypeInteger) { | 
|  | *output = integer_value_; | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool JSONBasicValue::AsInteger(int* output) const { | 
|  | if (GetType() != kTypeInteger) | 
|  | return false; | 
|  | *output = integer_value_; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void JSONBasicValue::WriteJSON(StringBuilder* output) const { | 
|  | DCHECK(GetType() == kTypeBoolean || GetType() == kTypeInteger || | 
|  | GetType() == kTypeDouble); | 
|  | if (GetType() == kTypeBoolean) { | 
|  | if (bool_value_) | 
|  | output->Append(kJSONTrueString, 4); | 
|  | else | 
|  | output->Append(kJSONFalseString, 5); | 
|  | } else if (GetType() == kTypeDouble) { | 
|  | if (!std::isfinite(double_value_)) { | 
|  | output->Append(kJSONNullString, 4); | 
|  | return; | 
|  | } | 
|  | output->Append(Decimal::FromDouble(double_value_).ToString()); | 
|  | } else if (GetType() == kTypeInteger) { | 
|  | output->Append(String::Number(integer_value_)); | 
|  | } | 
|  | } | 
|  |  | 
|  | std::unique_ptr<JSONValue> JSONBasicValue::Clone() const { | 
|  | switch (GetType()) { | 
|  | case kTypeDouble: | 
|  | return JSONBasicValue::Create(double_value_); | 
|  | case kTypeInteger: | 
|  | return JSONBasicValue::Create(integer_value_); | 
|  | case kTypeBoolean: | 
|  | return JSONBasicValue::Create(bool_value_); | 
|  | default: | 
|  | NOTREACHED(); | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | bool JSONString::AsString(String* output) const { | 
|  | *output = string_value_; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void JSONString::WriteJSON(StringBuilder* output) const { | 
|  | DCHECK(GetType() == kTypeString); | 
|  | DoubleQuoteStringForJSON(string_value_, output); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<JSONValue> JSONString::Clone() const { | 
|  | return JSONString::Create(string_value_); | 
|  | } | 
|  |  | 
|  | JSONObject::~JSONObject() = default; | 
|  |  | 
|  | void JSONObject::SetBoolean(const String& name, bool value) { | 
|  | SetValue(name, JSONBasicValue::Create(value)); | 
|  | } | 
|  |  | 
|  | void JSONObject::SetInteger(const String& name, int value) { | 
|  | SetValue(name, JSONBasicValue::Create(value)); | 
|  | } | 
|  |  | 
|  | void JSONObject::SetDouble(const String& name, double value) { | 
|  | SetValue(name, JSONBasicValue::Create(value)); | 
|  | } | 
|  |  | 
|  | void JSONObject::SetString(const String& name, const String& value) { | 
|  | SetValue(name, JSONString::Create(value)); | 
|  | } | 
|  |  | 
|  | void JSONObject::SetValue(const String& name, | 
|  | std::unique_ptr<JSONValue> value) { | 
|  | Set(name, value); | 
|  | } | 
|  |  | 
|  | void JSONObject::SetObject(const String& name, | 
|  | std::unique_ptr<JSONObject> value) { | 
|  | Set(name, value); | 
|  | } | 
|  |  | 
|  | void JSONObject::SetArray(const String& name, | 
|  | std::unique_ptr<JSONArray> value) { | 
|  | Set(name, value); | 
|  | } | 
|  |  | 
|  | bool JSONObject::GetBoolean(const String& name, bool* output) const { | 
|  | JSONValue* value = Get(name); | 
|  | if (!value) | 
|  | return false; | 
|  | return value->AsBoolean(output); | 
|  | } | 
|  |  | 
|  | bool JSONObject::GetInteger(const String& name, int* output) const { | 
|  | JSONValue* value = Get(name); | 
|  | if (!value) | 
|  | return false; | 
|  | return value->AsInteger(output); | 
|  | } | 
|  |  | 
|  | bool JSONObject::GetDouble(const String& name, double* output) const { | 
|  | JSONValue* value = Get(name); | 
|  | if (!value) | 
|  | return false; | 
|  | return value->AsDouble(output); | 
|  | } | 
|  |  | 
|  | bool JSONObject::GetString(const String& name, String* output) const { | 
|  | JSONValue* value = Get(name); | 
|  | if (!value) | 
|  | return false; | 
|  | return value->AsString(output); | 
|  | } | 
|  |  | 
|  | JSONObject* JSONObject::GetJSONObject(const String& name) const { | 
|  | return JSONObject::Cast(Get(name)); | 
|  | } | 
|  |  | 
|  | JSONArray* JSONObject::GetArray(const String& name) const { | 
|  | return JSONArray::Cast(Get(name)); | 
|  | } | 
|  |  | 
|  | JSONValue* JSONObject::Get(const String& name) const { | 
|  | Dictionary::const_iterator it = data_.find(name); | 
|  | if (it == data_.end()) | 
|  | return nullptr; | 
|  | return it->value.get(); | 
|  | } | 
|  |  | 
|  | JSONObject::Entry JSONObject::at(size_t index) const { | 
|  | const String key = order_[index]; | 
|  | return std::make_pair(key, data_.find(key)->value.get()); | 
|  | } | 
|  |  | 
|  | bool JSONObject::BooleanProperty(const String& name, bool default_value) const { | 
|  | bool result = default_value; | 
|  | GetBoolean(name, &result); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | int JSONObject::IntegerProperty(const String& name, int default_value) const { | 
|  | int result = default_value; | 
|  | GetInteger(name, &result); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | double JSONObject::DoubleProperty(const String& name, | 
|  | double default_value) const { | 
|  | double result = default_value; | 
|  | GetDouble(name, &result); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | void JSONObject::Remove(const String& name) { | 
|  | data_.erase(name); | 
|  | for (size_t i = 0; i < order_.size(); ++i) { | 
|  | if (order_[i] == name) { | 
|  | order_.EraseAt(i); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void JSONObject::WriteJSON(StringBuilder* output) const { | 
|  | output->Append('{'); | 
|  | for (size_t i = 0; i < order_.size(); ++i) { | 
|  | Dictionary::const_iterator it = data_.find(order_[i]); | 
|  | CHECK(it != data_.end()); | 
|  | if (i) | 
|  | output->Append(','); | 
|  | DoubleQuoteStringForJSON(it->key, output); | 
|  | output->Append(':'); | 
|  | it->value->WriteJSON(output); | 
|  | } | 
|  | output->Append('}'); | 
|  | } | 
|  |  | 
|  | void JSONObject::PrettyWriteJSONInternal(StringBuilder* output, | 
|  | int depth) const { | 
|  | output->Append("{\n"); | 
|  | for (size_t i = 0; i < order_.size(); ++i) { | 
|  | Dictionary::const_iterator it = data_.find(order_[i]); | 
|  | CHECK(it != data_.end()); | 
|  | if (i) | 
|  | output->Append(",\n"); | 
|  | WriteIndent(depth + 1, output); | 
|  | DoubleQuoteStringForJSON(it->key, output); | 
|  | output->Append(": "); | 
|  | it->value->PrettyWriteJSONInternal(output, depth + 1); | 
|  | } | 
|  | output->Append('\n'); | 
|  | WriteIndent(depth, output); | 
|  | output->Append('}'); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<JSONValue> JSONObject::Clone() const { | 
|  | std::unique_ptr<JSONObject> result = JSONObject::Create(); | 
|  | for (size_t i = 0; i < order_.size(); ++i) { | 
|  | String key = order_[i]; | 
|  | Dictionary::const_iterator value = data_.find(key); | 
|  | DCHECK(value != data_.end() && value->value); | 
|  | result->SetValue(key, value->value->Clone()); | 
|  | } | 
|  | return std::move(result); | 
|  | } | 
|  |  | 
|  | JSONObject::JSONObject() : JSONValue(kTypeObject), data_(), order_() {} | 
|  |  | 
|  | JSONArray::~JSONArray() = default; | 
|  |  | 
|  | void JSONArray::WriteJSON(StringBuilder* output) const { | 
|  | output->Append('['); | 
|  | bool first = true; | 
|  | for (const std::unique_ptr<JSONValue>& value : data_) { | 
|  | if (!first) | 
|  | output->Append(','); | 
|  | value->WriteJSON(output); | 
|  | first = false; | 
|  | } | 
|  | output->Append(']'); | 
|  | } | 
|  |  | 
|  | void JSONArray::PrettyWriteJSONInternal(StringBuilder* output, | 
|  | int depth) const { | 
|  | output->Append('['); | 
|  | bool first = true; | 
|  | bool last_inserted_new_line = false; | 
|  | for (const std::unique_ptr<JSONValue>& value : data_) { | 
|  | bool insert_new_line = value->GetType() == JSONValue::kTypeObject || | 
|  | value->GetType() == JSONValue::kTypeArray || | 
|  | value->GetType() == JSONValue::kTypeString; | 
|  | if (first) { | 
|  | if (insert_new_line) { | 
|  | output->Append('\n'); | 
|  | WriteIndent(depth + 1, output); | 
|  | } | 
|  | first = false; | 
|  | } else { | 
|  | output->Append(','); | 
|  | if (last_inserted_new_line) { | 
|  | output->Append('\n'); | 
|  | WriteIndent(depth + 1, output); | 
|  | } else { | 
|  | output->Append(' '); | 
|  | } | 
|  | } | 
|  | value->PrettyWriteJSONInternal(output, depth + 1); | 
|  | last_inserted_new_line = insert_new_line; | 
|  | } | 
|  | if (last_inserted_new_line) { | 
|  | output->Append('\n'); | 
|  | WriteIndent(depth, output); | 
|  | } | 
|  | output->Append(']'); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<JSONValue> JSONArray::Clone() const { | 
|  | std::unique_ptr<JSONArray> result = JSONArray::Create(); | 
|  | for (const std::unique_ptr<JSONValue>& value : data_) | 
|  | result->PushValue(value->Clone()); | 
|  | return std::move(result); | 
|  | } | 
|  |  | 
|  | JSONArray::JSONArray() : JSONValue(kTypeArray) {} | 
|  |  | 
|  | void JSONArray::PushBoolean(bool value) { | 
|  | data_.push_back(JSONBasicValue::Create(value)); | 
|  | } | 
|  |  | 
|  | void JSONArray::PushInteger(int value) { | 
|  | data_.push_back(JSONBasicValue::Create(value)); | 
|  | } | 
|  |  | 
|  | void JSONArray::PushDouble(double value) { | 
|  | data_.push_back(JSONBasicValue::Create(value)); | 
|  | } | 
|  |  | 
|  | void JSONArray::PushString(const String& value) { | 
|  | data_.push_back(JSONString::Create(value)); | 
|  | } | 
|  |  | 
|  | void JSONArray::PushValue(std::unique_ptr<JSONValue> value) { | 
|  | DCHECK(value); | 
|  | data_.push_back(std::move(value)); | 
|  | } | 
|  |  | 
|  | void JSONArray::PushObject(std::unique_ptr<JSONObject> value) { | 
|  | DCHECK(value); | 
|  | data_.push_back(std::move(value)); | 
|  | } | 
|  |  | 
|  | void JSONArray::PushArray(std::unique_ptr<JSONArray> value) { | 
|  | DCHECK(value); | 
|  | data_.push_back(std::move(value)); | 
|  | } | 
|  |  | 
|  | JSONValue* JSONArray::at(size_t index) const { | 
|  | DCHECK_LT(index, data_.size()); | 
|  | return data_[index].get(); | 
|  | } | 
|  |  | 
|  | }  // namespace blink |