// This file is generated by Values_cpp.template. // 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': StringUtil::builderAppend(*dst, "\\b"); break; case '\f': StringUtil::builderAppend(*dst, "\\f"); break; case '\n': StringUtil::builderAppend(*dst, "\\n"); break; case '\r': StringUtil::builderAppend(*dst, "\\r"); break; case '\t': StringUtil::builderAppend(*dst, "\\t"); break; case '\\': StringUtil::builderAppend(*dst, "\\\\"); break; case '"': StringUtil::builderAppend(*dst, "\\\""); break; default: return false; } return true; } const char hexDigits[17] = "0123456789ABCDEF"; void appendUnsignedAsHex(uint16_t number, StringBuilder* dst) { StringUtil::builderAppend(*dst, "\\u"); for (size_t i = 0; i < 4; ++i) { uint16_t c = hexDigits[(number & 0xF000) >> 12]; StringUtil::builderAppend(*dst, c); number <<= 4; } } template void escapeStringForJSONInternal(const Char* str, unsigned len, StringBuilder* dst) { for (unsigned i = 0; i < len; ++i) { Char c = str[i]; if (escapeChar(c, dst)) continue; if (c < 32 || c > 126) { appendUnsignedAsHex(c, dst); } else { StringUtil::builderAppend(*dst, c); } } } // When parsing CBOR, we limit recursion depth for objects and arrays // to this constant. static constexpr int kStackLimitValues = 1000; // Below are three parsing routines for CBOR, which cover enough // to roundtrip JSON messages. std::unique_ptr parseMap(int32_t stack_depth, cbor::CBORTokenizer* tokenizer); std::unique_ptr parseArray(int32_t stack_depth, cbor::CBORTokenizer* tokenizer); std::unique_ptr parseValue(int32_t stack_depth, cbor::CBORTokenizer* tokenizer); // |bytes| must start with the indefinite length array byte, so basically, // ParseArray may only be called after an indefinite length array has been // detected. std::unique_ptr parseArray(int32_t stack_depth, cbor::CBORTokenizer* tokenizer) { DCHECK(tokenizer->TokenTag() == cbor::CBORTokenTag::ARRAY_START); tokenizer->Next(); auto list = ListValue::create(); while (tokenizer->TokenTag() != cbor::CBORTokenTag::STOP) { // Error::CBOR_UNEXPECTED_EOF_IN_ARRAY if (tokenizer->TokenTag() == cbor::CBORTokenTag::DONE) return nullptr; if (tokenizer->TokenTag() == cbor::CBORTokenTag::ERROR_VALUE) return nullptr; // Parse value. auto value = parseValue(stack_depth, tokenizer); if (!value) return nullptr; list->pushValue(std::move(value)); } tokenizer->Next(); return list; } std::unique_ptr parseValue( int32_t stack_depth, cbor::CBORTokenizer* tokenizer) { // Error::CBOR_STACK_LIMIT_EXCEEDED if (stack_depth > kStackLimitValues) return nullptr; // Skip past the envelope to get to what's inside. if (tokenizer->TokenTag() == cbor::CBORTokenTag::ENVELOPE) tokenizer->EnterEnvelope(); switch (tokenizer->TokenTag()) { case cbor::CBORTokenTag::ERROR_VALUE: return nullptr; case cbor::CBORTokenTag::DONE: // Error::CBOR_UNEXPECTED_EOF_EXPECTED_VALUE return nullptr; case cbor::CBORTokenTag::TRUE_VALUE: { std::unique_ptr value = FundamentalValue::create(true); tokenizer->Next(); return value; } case cbor::CBORTokenTag::FALSE_VALUE: { std::unique_ptr value = FundamentalValue::create(false); tokenizer->Next(); return value; } case cbor::CBORTokenTag::NULL_VALUE: { std::unique_ptr value = FundamentalValue::null(); tokenizer->Next(); return value; } case cbor::CBORTokenTag::INT32: { std::unique_ptr value = FundamentalValue::create(tokenizer->GetInt32()); tokenizer->Next(); return value; } case cbor::CBORTokenTag::DOUBLE: { std::unique_ptr value = FundamentalValue::create(tokenizer->GetDouble()); tokenizer->Next(); return value; } case cbor::CBORTokenTag::STRING8: { span str = tokenizer->GetString8(); std::unique_ptr value = StringValue::create(StringUtil::fromUTF8(str.data(), str.size())); tokenizer->Next(); return value; } case cbor::CBORTokenTag::STRING16: { span wire = tokenizer->GetString16WireRep(); DCHECK_EQ(wire.size() & 1, 0u); std::unique_ptr value = StringValue::create(StringUtil::fromUTF16( reinterpret_cast(wire.data()), wire.size() / 2)); tokenizer->Next(); return value; } case cbor::CBORTokenTag::BINARY: { span payload = tokenizer->GetBinary(); tokenizer->Next(); return BinaryValue::create(Binary::fromSpan(payload.data(), payload.size())); } case cbor::CBORTokenTag::MAP_START: return parseMap(stack_depth + 1, tokenizer); case cbor::CBORTokenTag::ARRAY_START: return parseArray(stack_depth + 1, tokenizer); default: // Error::CBOR_UNSUPPORTED_VALUE return nullptr; } } // |bytes| must start with the indefinite length array byte, so basically, // ParseArray may only be called after an indefinite length array has been // detected. std::unique_ptr parseMap( int32_t stack_depth, cbor::CBORTokenizer* tokenizer) { auto dict = DictionaryValue::create(); tokenizer->Next(); while (tokenizer->TokenTag() != cbor::CBORTokenTag::STOP) { if (tokenizer->TokenTag() == cbor::CBORTokenTag::DONE) { // Error::CBOR_UNEXPECTED_EOF_IN_MAP return nullptr; } if (tokenizer->TokenTag() == cbor::CBORTokenTag::ERROR_VALUE) return nullptr; // Parse key. String key; if (tokenizer->TokenTag() == cbor::CBORTokenTag::STRING8) { span key_span = tokenizer->GetString8(); key = StringUtil::fromUTF8(key_span.data(), key_span.size()); tokenizer->Next(); } else if (tokenizer->TokenTag() == cbor::CBORTokenTag::STRING16) { return nullptr; // STRING16 not supported yet. } else { // Error::CBOR_INVALID_MAP_KEY return nullptr; } // Parse value. auto value = parseValue(stack_depth, tokenizer); if (!value) return nullptr; dict->setValue(key, std::move(value)); } tokenizer->Next(); return dict; } } // anonymous namespace // static std::unique_ptr Value::parseBinary(const uint8_t* data, size_t size) { span bytes(data, size); // Error::CBOR_NO_INPUT if (bytes.empty()) return nullptr; // Error::CBOR_INVALID_START_BYTE if (bytes[0] != cbor::InitialByteForEnvelope()) return nullptr; cbor::CBORTokenizer tokenizer(bytes); if (tokenizer.TokenTag() == cbor::CBORTokenTag::ERROR_VALUE) return nullptr; // We checked for the envelope start byte above, so the tokenizer // must agree here, since it's not an error. DCHECK(tokenizer.TokenTag() == cbor::CBORTokenTag::ENVELOPE); tokenizer.EnterEnvelope(); // Error::MAP_START_EXPECTED if (tokenizer.TokenTag() != cbor::CBORTokenTag::MAP_START) return nullptr; std::unique_ptr result = parseMap(/*stack_depth=*/1, &tokenizer); if (!result) return nullptr; if (tokenizer.TokenTag() == cbor::CBORTokenTag::DONE) return result; if (tokenizer.TokenTag() == cbor::CBORTokenTag::ERROR_VALUE) return nullptr; // Error::CBOR_TRAILING_JUNK return nullptr; } 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::asBinary(Binary*) const { return false; } void Value::writeJSON(StringBuilder* output) const { DCHECK(m_type == TypeNull); StringUtil::builderAppend(*output, nullValueString, 4); } void Value::writeBinary(std::vector* bytes) const { DCHECK(m_type == TypeNull); bytes->push_back(cbor::EncodeNull()); } std::unique_ptr Value::clone() const { return Value::null(); } String Value::toJSONString() const { StringBuilder result; StringUtil::builderReserve(result, 512); writeJSON(&result); return StringUtil::builderToString(result); } String Value::serializeToJSON() { return toJSONString(); } std::vector Value::serializeToBinary() { std::vector bytes; writeBinary(&bytes); return bytes; } 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) StringUtil::builderAppend(*output, trueValueString, 4); else StringUtil::builderAppend(*output, falseValueString, 5); } else if (type() == TypeDouble) { if (!std::isfinite(m_doubleValue)) { StringUtil::builderAppend(*output, nullValueString, 4); return; } StringUtil::builderAppend(*output, StringUtil::fromDouble(m_doubleValue)); } else if (type() == TypeInteger) { StringUtil::builderAppend(*output, StringUtil::fromInteger(m_integerValue)); } } void FundamentalValue::writeBinary(std::vector* bytes) const { switch (type()) { case TypeDouble: cbor::EncodeDouble(m_doubleValue, bytes); return; case TypeInteger: cbor::EncodeInt32(m_integerValue, bytes); return; case TypeBoolean: bytes->push_back(m_boolValue ? cbor::EncodeTrue() : cbor::EncodeFalse()); return; default: DCHECK(false); } } 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); StringUtil::builderAppendQuotedString(*output, m_stringValue); } namespace { // This routine distinguishes between the current encoding for a given // string |s|, and calls encoding routines that will // - Ensure that all ASCII strings end up being encoded as UTF8 in // the wire format - e.g., EncodeFromUTF16 will detect ASCII and // do the (trivial) transcode to STRING8 on the wire, but if it's // not ASCII it'll do STRING16. // - Select a format that's cheap to convert to. E.g., we don't // have LATIN1 on the wire, so we call EncodeFromLatin1 which // transcodes to UTF8 if needed. void EncodeString(const String& s, std::vector* out) { if (StringUtil::CharacterCount(s) == 0) { cbor::EncodeString8(span(nullptr, 0), out); // Empty string. } else if (StringUtil::CharactersLatin1(s)) { cbor::EncodeFromLatin1(span(StringUtil::CharactersLatin1(s), StringUtil::CharacterCount(s)), out); } else if (StringUtil::CharactersUTF16(s)) { cbor::EncodeFromUTF16(span(StringUtil::CharactersUTF16(s), StringUtil::CharacterCount(s)), out); } else if (StringUtil::CharactersUTF8(s)) { cbor::EncodeString8(span(StringUtil::CharactersUTF8(s), StringUtil::CharacterCount(s)), out); } } } // namespace void StringValue::writeBinary(std::vector* bytes) const { EncodeString(m_stringValue, bytes); } std::unique_ptr StringValue::clone() const { return StringValue::create(m_stringValue); } bool BinaryValue::asBinary(Binary* output) const { *output = m_binaryValue; return true; } void BinaryValue::writeJSON(StringBuilder* output) const { DCHECK(type() == TypeBinary); StringUtil::builderAppendQuotedString(*output, m_binaryValue.toBase64()); } void BinaryValue::writeBinary(std::vector* bytes) const { cbor::EncodeBinary(span(m_binaryValue.data(), m_binaryValue.size()), bytes); } std::unique_ptr BinaryValue::clone() const { return BinaryValue::create(m_binaryValue); } void SerializedValue::writeJSON(StringBuilder* output) const { DCHECK(type() == TypeSerialized); StringUtil::builderAppend(*output, m_serializedJSON); } void SerializedValue::writeBinary(std::vector* output) const { DCHECK(type() == TypeSerialized); output->insert(output->end(), m_serializedBinary.begin(), m_serializedBinary.end()); } std::unique_ptr SerializedValue::clone() const { return std::unique_ptr(new SerializedValue(m_serializedJSON, m_serializedBinary)); } 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 { StringUtil::builderAppend(*output, '{'); 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) StringUtil::builderAppend(*output, ','); StringUtil::builderAppendQuotedString(*output, it->first); StringUtil::builderAppend(*output, ':'); it->second->writeJSON(output); } StringUtil::builderAppend(*output, '}'); } void DictionaryValue::writeBinary(std::vector* bytes) const { cbor::EnvelopeEncoder encoder; encoder.EncodeStart(bytes); bytes->push_back(cbor::EncodeIndefiniteLengthMapStart()); for (size_t i = 0; i < m_order.size(); ++i) { const String& key = m_order[i]; Dictionary::const_iterator value = m_data.find(key); DCHECK(value != m_data.cend() && value->second); EncodeString(key, bytes); value->second->writeBinary(bytes); } bytes->push_back(cbor::EncodeStop()); encoder.EncodeStop(bytes); } 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 { StringUtil::builderAppend(*output, '['); bool first = true; for (const std::unique_ptr& value : m_data) { if (!first) StringUtil::builderAppend(*output, ','); value->writeJSON(output); first = false; } StringUtil::builderAppend(*output, ']'); } void ListValue::writeBinary(std::vector* bytes) const { cbor::EnvelopeEncoder encoder; encoder.EncodeStart(bytes); bytes->push_back(cbor::EncodeIndefiniteLengthArrayStart()); for (size_t i = 0; i < m_data.size(); ++i) { m_data[i]->writeBinary(bytes); } bytes->push_back(cbor::EncodeStop()); encoder.EncodeStop(bytes); } 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(); } void escapeLatinStringForJSON(const uint8_t* str, unsigned len, StringBuilder* dst) { escapeStringForJSONInternal(str, len, dst); } void escapeWideStringForJSON(const uint16_t* str, unsigned len, StringBuilder* dst) { escapeStringForJSONInternal(str, len, dst); } {% for namespace in config.protocol.namespace %} } // namespace {{namespace}} {% endfor %}