// This file is generated by Values_cpp.template. // Copyright 2016 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //#include "Values.h" #include "{{config.crdtp.dir}}/cbor.h" {% for namespace in config.protocol.namespace %} namespace {{namespace}} { {% endfor %} namespace { using {{config.crdtp.namespace}}::Status; using {{config.crdtp.namespace}}::ParserHandler; using {{config.crdtp.namespace}}::span; namespace cbor { using {{config.crdtp.namespace}}::cbor::ParseCBOR; using {{config.crdtp.namespace}}::cbor::EncodeBinary; using {{config.crdtp.namespace}}::cbor::EncodeDouble; using {{config.crdtp.namespace}}::cbor::EncodeFalse; using {{config.crdtp.namespace}}::cbor::EncodeFromLatin1; using {{config.crdtp.namespace}}::cbor::EncodeFromUTF16; using {{config.crdtp.namespace}}::cbor::EncodeIndefiniteLengthArrayStart; using {{config.crdtp.namespace}}::cbor::EncodeIndefiniteLengthMapStart; using {{config.crdtp.namespace}}::cbor::EncodeInt32; using {{config.crdtp.namespace}}::cbor::EncodeNull; using {{config.crdtp.namespace}}::cbor::EncodeStop; using {{config.crdtp.namespace}}::cbor::EncodeString8; using {{config.crdtp.namespace}}::cbor::EncodeTrue; using {{config.crdtp.namespace}}::cbor::EnvelopeEncoder; } // namespace cbor // Uses the parsing events received from driver of |ParserHandler| // (e.g. cbor::ParseCBOR) into a protocol::Value instance. class ValueParserHandler : public ParserHandler { public: // Provides the parsed protocol::Value. std::unique_ptr ReleaseRoot() { return std::move(root_); } // The first parsing error encountered; |status().ok()| is the default. Status status() const { return status_; } private: // // Implementation of ParserHandler. // void HandleMapBegin() override { if (!status_.ok()) return; std::unique_ptr dict = DictionaryValue::create(); DictionaryValue* dict_ptr = dict.get(); AddValueToParent(std::move(dict)); stack_.emplace_back(dict_ptr); } void HandleMapEnd() override { if (!status_.ok()) return; DCHECK(!stack_.empty()); DCHECK(stack_.back().is_dict); stack_.pop_back(); } void HandleArrayBegin() override { if (!status_.ok()) return; std::unique_ptr list = ListValue::create(); ListValue* list_ptr = list.get(); AddValueToParent(std::move(list)); stack_.emplace_back(list_ptr); } void HandleArrayEnd() override { if (!status_.ok()) return; DCHECK(!stack_.empty()); DCHECK(!stack_.back().is_dict); stack_.pop_back(); } void HandleString8(span chars) override { AddStringToParent(StringUtil::fromUTF8(chars.data(), chars.size())); } void HandleString16(span chars) override { AddStringToParent( StringUtil::fromUTF16LE(chars.data(), chars.size())); } void HandleBinary(span bytes) override { AddValueToParent( BinaryValue::create(Binary::fromSpan(bytes.data(), bytes.size()))); } void HandleDouble(double value) override { AddValueToParent(FundamentalValue::create(value)); } void HandleInt32(int32_t value) override { AddValueToParent(FundamentalValue::create(value)); } void HandleBool(bool value) override { AddValueToParent(FundamentalValue::create(value)); } void HandleNull() override { AddValueToParent(Value::null()); } void HandleError(Status error) override { status_ = error; } // // Adding strings and values to the parent value. // Strings are handled separately because they can be keys for // dictionary values. // void AddStringToParent(String str) { if (!status_.ok()) return; if (!root_) { DCHECK(!key_is_pending_); root_ = StringValue::create(str); } else if (stack_.back().is_dict) { // If we already have a pending key, then this is the value of the // key/value pair. Otherwise, it's the new pending key. if (key_is_pending_) { stack_.back().dict->setString(pending_key_, str); key_is_pending_ = false; } else { pending_key_ = std::move(str); key_is_pending_ = true; } } else { // Top of the stack is a list. DCHECK(!key_is_pending_); stack_.back().list->pushValue(StringValue::create(str)); } } void AddValueToParent(std::unique_ptr value) { if (!status_.ok()) return; if (!root_) { DCHECK(!key_is_pending_); root_ = std::move(value); } else if (stack_.back().is_dict) { DCHECK(key_is_pending_); stack_.back().dict->setValue(pending_key_, std::move(value)); key_is_pending_ = false; } else { // Top of the stack is a list. DCHECK(!key_is_pending_); stack_.back().list->pushValue(std::move(value)); } } // |status_.ok()| is the default; if we receive an error event // we keep the first one and stop modifying any other state. Status status_; // The root of the parsed protocol::Value tree. std::unique_ptr root_; // If root_ is a list or a dictionary, this stack keeps track of // the container we're currently parsing as well as its ancestors. struct ContainerState { ContainerState(DictionaryValue* dict) : is_dict(true), dict(dict) {} ContainerState(ListValue* list) : is_dict(false), list(list) {} bool is_dict; union { DictionaryValue* dict; ListValue* list; }; }; std::vector stack_; // For maps, keys and values are alternating events, so we keep the // key around and process it when the value arrives. bool key_is_pending_ = false; String pending_key_; }; } // anonymous namespace // static std::unique_ptr Value::parseBinary(const uint8_t* data, size_t size) { ValueParserHandler handler; cbor::ParseCBOR(span(data, size), &handler); // TODO(johannes): We have decent error info in handler.status(); provide // a richer interface that makes this available to client code. if (handler.status().ok()) return handler.ReleaseRoot(); 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::AppendSerialized(std::vector* bytes) const { DCHECK(m_type == TypeNull); bytes->push_back(cbor::EncodeNull()); } std::unique_ptr Value::clone() const { return Value::null(); } 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::AppendSerialized(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; } 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::AppendSerialized(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::AppendSerialized(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); } 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::AppendSerialized(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->AppendSerialized(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 result; } DictionaryValue::DictionaryValue() : Value(TypeObject) { } ListValue::~ListValue() { } void ListValue::AppendSerialized(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]->AppendSerialized(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 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 %}