| // 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" |
| |
| #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; |
| using {{config.crdtp.namespace}}::cbor::InitialByteForEnvelope; |
| } // 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<Value> 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<DictionaryValue> 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<ListValue> 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<uint8_t> chars) override { |
| AddStringToParent(StringUtil::fromUTF8(chars.data(), chars.size())); |
| } |
| |
| void HandleString16(span<uint16_t> chars) override { |
| AddStringToParent( |
| StringUtil::fromUTF16LE(chars.data(), chars.size())); |
| } |
| |
| void HandleBinary(span<uint8_t> 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> 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<Value> 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<ContainerState> 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> Value::parseBinary(const uint8_t* data, size_t size) { |
| ValueParserHandler handler; |
| cbor::ParseCBOR(span<uint8_t>(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<uint8_t>* bytes) const { |
| DCHECK(m_type == TypeNull); |
| bytes->push_back(cbor::EncodeNull()); |
| } |
| |
| std::unique_ptr<Value> 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<uint8_t>* 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<Value> 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<uint8_t>* out) { |
| if (StringUtil::CharacterCount(s) == 0) { |
| cbor::EncodeString8(span<uint8_t>(nullptr, 0), out); // Empty string. |
| } else if (StringUtil::CharactersLatin1(s)) { |
| cbor::EncodeFromLatin1(span<uint8_t>(StringUtil::CharactersLatin1(s), |
| StringUtil::CharacterCount(s)), |
| out); |
| } else if (StringUtil::CharactersUTF16(s)) { |
| cbor::EncodeFromUTF16(span<uint16_t>(StringUtil::CharactersUTF16(s), |
| StringUtil::CharacterCount(s)), |
| out); |
| } else if (StringUtil::CharactersUTF8(s)) { |
| cbor::EncodeString8(span<uint8_t>(StringUtil::CharactersUTF8(s), |
| StringUtil::CharacterCount(s)), |
| out); |
| } |
| } |
| } // namespace |
| void StringValue::AppendSerialized(std::vector<uint8_t>* bytes) const { |
| EncodeString(m_stringValue, bytes); |
| } |
| |
| std::unique_ptr<Value> StringValue::clone() const |
| { |
| return StringValue::create(m_stringValue); |
| } |
| |
| bool BinaryValue::asBinary(Binary* output) const |
| { |
| *output = m_binaryValue; |
| return true; |
| } |
| |
| void BinaryValue::AppendSerialized(std::vector<uint8_t>* bytes) const { |
| cbor::EncodeBinary(span<uint8_t>(m_binaryValue.data(), |
| m_binaryValue.size()), bytes); |
| } |
| |
| std::unique_ptr<Value> 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> value) |
| { |
| set(name, value); |
| } |
| |
| void DictionaryValue::setObject(const String& name, std::unique_ptr<DictionaryValue> value) |
| { |
| set(name, value); |
| } |
| |
| void DictionaryValue::setArray(const String& name, std::unique_ptr<ListValue> 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<uint8_t>* 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<Value> DictionaryValue::clone() const |
| { |
| std::unique_ptr<DictionaryValue> 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<uint8_t>* 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<Value> ListValue::clone() const |
| { |
| std::unique_ptr<ListValue> result = ListValue::create(); |
| for (const std::unique_ptr<protocol::Value>& value : m_data) |
| result->pushValue(value->clone()); |
| return result; |
| } |
| |
| ListValue::ListValue() |
| : Value(TypeArray) |
| { |
| } |
| |
| void ListValue::pushValue(std::unique_ptr<protocol::Value> 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 %} |