// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //#include "Values.h" {% for namespace in config.protocol.namespace %} namespace {{namespace}} { {% endfor %} namespace { const char* const nullValueString = "null"; const char* const trueValueString = "true"; const char* const falseValueString = "false"; inline bool escapeChar(uint16_t 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 char hexDigits[17] = "0123456789ABCDEF"; void appendUnsignedAsHex(uint16_t number, StringBuilder* dst) { dst->append("\\u"); for (size_t i = 0; i < 4; ++i) { uint16_t c = hexDigits[(number & 0xF000) >> 12]; dst->append(c); number <<= 4; } } void escapeStringForJSON(const String& str, StringBuilder* dst) { for (unsigned i = 0; i < str.length(); ++i) { uint16_t 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('"'); } } // anonymous namespace bool Value::asBoolean(bool*) const { return false; } bool Value::asDouble(double*) const { return false; } bool Value::asInteger(int*) const { return false; } bool Value::asString(String*) const { return false; } bool Value::asSerialized(String*) const { return false; } void Value::writeJSON(StringBuilder* output) const { DCHECK(m_type == TypeNull); output->append(nullValueString, 4); } std::unique_ptr Value::clone() const { return Value::null(); } String Value::serialize() { StringBuilder result; StringUtil::builderReserve(result, 512); writeJSON(&result); return result.toString(); } bool FundamentalValue::asBoolean(bool* output) const { if (type() != TypeBoolean) return false; *output = m_boolValue; return true; } bool FundamentalValue::asDouble(double* output) const { if (type() == TypeDouble) { *output = m_doubleValue; return true; } if (type() == TypeInteger) { *output = m_integerValue; return true; } return false; } bool FundamentalValue::asInteger(int* output) const { if (type() != TypeInteger) return false; *output = m_integerValue; return true; } void FundamentalValue::writeJSON(StringBuilder* output) const { DCHECK(type() == TypeBoolean || type() == TypeInteger || type() == TypeDouble); if (type() == TypeBoolean) { if (m_boolValue) output->append(trueValueString, 4); else output->append(falseValueString, 5); } else if (type() == TypeDouble) { if (!std::isfinite(m_doubleValue)) { output->append(nullValueString, 4); return; } output->append(StringUtil::fromDouble(m_doubleValue)); } else if (type() == TypeInteger) { output->append(StringUtil::fromInteger(m_integerValue)); } } std::unique_ptr FundamentalValue::clone() const { switch (type()) { case TypeDouble: return FundamentalValue::create(m_doubleValue); case TypeInteger: return FundamentalValue::create(m_integerValue); case TypeBoolean: return FundamentalValue::create(m_boolValue); default: DCHECK(false); } return nullptr; } bool StringValue::asString(String* output) const { *output = m_stringValue; return true; } void StringValue::writeJSON(StringBuilder* output) const { DCHECK(type() == TypeString); doubleQuoteStringForJSON(m_stringValue, output); } std::unique_ptr StringValue::clone() const { return StringValue::create(m_stringValue); } bool SerializedValue::asSerialized(String* output) const { *output = m_serializedValue; return true; } void SerializedValue::writeJSON(StringBuilder* output) const { DCHECK(type() == TypeSerialized); output->append(m_serializedValue); } std::unique_ptr SerializedValue::clone() const { return SerializedValue::create(m_serializedValue); } DictionaryValue::~DictionaryValue() { } void DictionaryValue::setBoolean(const String& name, bool value) { setValue(name, FundamentalValue::create(value)); } void DictionaryValue::setInteger(const String& name, int value) { setValue(name, FundamentalValue::create(value)); } void DictionaryValue::setDouble(const String& name, double value) { setValue(name, FundamentalValue::create(value)); } void DictionaryValue::setString(const String& name, const String& value) { setValue(name, StringValue::create(value)); } void DictionaryValue::setValue(const String& name, std::unique_ptr value) { set(name, value); } void DictionaryValue::setObject(const String& name, std::unique_ptr value) { set(name, value); } void DictionaryValue::setArray(const String& name, std::unique_ptr value) { set(name, value); } bool DictionaryValue::getBoolean(const String& name, bool* output) const { protocol::Value* value = get(name); if (!value) return false; return value->asBoolean(output); } bool DictionaryValue::getInteger(const String& name, int* output) const { Value* value = get(name); if (!value) return false; return value->asInteger(output); } bool DictionaryValue::getDouble(const String& name, double* output) const { Value* value = get(name); if (!value) return false; return value->asDouble(output); } bool DictionaryValue::getString(const String& name, String* output) const { protocol::Value* value = get(name); if (!value) return false; return value->asString(output); } DictionaryValue* DictionaryValue::getObject(const String& name) const { return DictionaryValue::cast(get(name)); } protocol::ListValue* DictionaryValue::getArray(const String& name) const { return ListValue::cast(get(name)); } protocol::Value* DictionaryValue::get(const String& name) const { Dictionary::const_iterator it = m_data.find(name); if (it == m_data.end()) return nullptr; return it->second.get(); } DictionaryValue::Entry DictionaryValue::at(size_t index) const { const String key = m_order[index]; return std::make_pair(key, m_data.find(key)->second.get()); } bool DictionaryValue::booleanProperty(const String& name, bool defaultValue) const { bool result = defaultValue; getBoolean(name, &result); return result; } int DictionaryValue::integerProperty(const String& name, int defaultValue) const { int result = defaultValue; getInteger(name, &result); return result; } double DictionaryValue::doubleProperty(const String& name, double defaultValue) const { double result = defaultValue; getDouble(name, &result); return result; } void DictionaryValue::remove(const String& name) { m_data.erase(name); m_order.erase(std::remove(m_order.begin(), m_order.end(), name), m_order.end()); } void DictionaryValue::writeJSON(StringBuilder* output) const { output->append('{'); for (size_t i = 0; i < m_order.size(); ++i) { Dictionary::const_iterator it = m_data.find(m_order[i]); CHECK(it != m_data.end()); if (i) output->append(','); doubleQuoteStringForJSON(it->first, output); output->append(':'); it->second->writeJSON(output); } output->append('}'); } std::unique_ptr DictionaryValue::clone() const { std::unique_ptr result = DictionaryValue::create(); for (size_t i = 0; i < m_order.size(); ++i) { String key = m_order[i]; Dictionary::const_iterator value = m_data.find(key); DCHECK(value != m_data.cend() && value->second); result->setValue(key, value->second->clone()); } return std::move(result); } DictionaryValue::DictionaryValue() : Value(TypeObject) { } ListValue::~ListValue() { } void ListValue::writeJSON(StringBuilder* output) const { output->append('['); bool first = true; for (const std::unique_ptr& value : m_data) { if (!first) output->append(','); value->writeJSON(output); first = false; } output->append(']'); } std::unique_ptr ListValue::clone() const { std::unique_ptr result = ListValue::create(); for (const std::unique_ptr& value : m_data) result->pushValue(value->clone()); return std::move(result); } ListValue::ListValue() : Value(TypeArray) { } void ListValue::pushValue(std::unique_ptr value) { DCHECK(value); m_data.push_back(std::move(value)); } protocol::Value* ListValue::at(size_t index) { DCHECK_LT(index, m_data.size()); return m_data[index].get(); } {% for namespace in config.protocol.namespace %} } // namespace {{namespace}} {% endfor %}