| // 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 { | |
| 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 <typename Char> | |
| 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; | |
| using {{config.crdtp.namespace}}::Error; | |
| using {{config.crdtp.namespace}}::Status; | |
| using {{config.crdtp.namespace}}::span; | |
| namespace cbor { | |
| using {{config.crdtp.namespace}}::cbor::CBORTokenTag; | |
| using {{config.crdtp.namespace}}::cbor::CBORTokenizer; | |
| 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 | |
| // Below are three parsing routines for CBOR, which cover enough | |
| // to roundtrip JSON messages. | |
| std::unique_ptr<DictionaryValue> parseMap(int32_t stack_depth, cbor::CBORTokenizer* tokenizer); | |
| std::unique_ptr<ListValue> parseArray(int32_t stack_depth, cbor::CBORTokenizer* tokenizer); | |
| std::unique_ptr<Value> 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<ListValue> 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<Value> 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> value = FundamentalValue::create(true); | |
| tokenizer->Next(); | |
| return value; | |
| } | |
| case cbor::CBORTokenTag::FALSE_VALUE: { | |
| std::unique_ptr<Value> value = FundamentalValue::create(false); | |
| tokenizer->Next(); | |
| return value; | |
| } | |
| case cbor::CBORTokenTag::NULL_VALUE: { | |
| std::unique_ptr<Value> value = FundamentalValue::null(); | |
| tokenizer->Next(); | |
| return value; | |
| } | |
| case cbor::CBORTokenTag::INT32: { | |
| std::unique_ptr<Value> value = FundamentalValue::create(tokenizer->GetInt32()); | |
| tokenizer->Next(); | |
| return value; | |
| } | |
| case cbor::CBORTokenTag::DOUBLE: { | |
| std::unique_ptr<Value> value = FundamentalValue::create(tokenizer->GetDouble()); | |
| tokenizer->Next(); | |
| return value; | |
| } | |
| case cbor::CBORTokenTag::STRING8: { | |
| span<uint8_t> str = tokenizer->GetString8(); | |
| std::unique_ptr<Value> value = | |
| StringValue::create(StringUtil::fromUTF8(str.data(), str.size())); | |
| tokenizer->Next(); | |
| return value; | |
| } | |
| case cbor::CBORTokenTag::STRING16: { | |
| span<uint8_t> wire = tokenizer->GetString16WireRep(); | |
| DCHECK_EQ(wire.size() & 1, 0u); | |
| std::unique_ptr<Value> value = StringValue::create(StringUtil::fromUTF16LE( | |
| reinterpret_cast<const uint16_t*>(wire.data()), wire.size() / 2)); | |
| tokenizer->Next(); | |
| return value; | |
| } | |
| case cbor::CBORTokenTag::BINARY: { | |
| span<uint8_t> 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<DictionaryValue> 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<uint8_t> key_span = tokenizer->GetString8(); | |
| key = StringUtil::fromUTF8(key_span.data(), key_span.size()); | |
| tokenizer->Next(); | |
| } else if (tokenizer->TokenTag() == cbor::CBORTokenTag::STRING16) { | |
| span<uint8_t> key_span = tokenizer->GetString16WireRep(); | |
| if (key_span.size() & 1) return nullptr; // UTF16 is 2 byte multiple. | |
| key = StringUtil::fromUTF16LE( | |
| reinterpret_cast<const uint16_t*>(key_span.data()), | |
| key_span.size() / 2); | |
| tokenizer->Next(); | |
| } 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> Value::parseBinary(const uint8_t* data, size_t size) { | |
| span<uint8_t> 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<Value> 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::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(); | |
| } | |
| String Value::toJSONString() const | |
| { | |
| StringBuilder result; | |
| StringUtil::builderReserve(result, 512); | |
| writeJSON(&result); | |
| return StringUtil::builderToString(result); | |
| } | |
| 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::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; | |
| } | |
| 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<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::writeJSON(StringBuilder* output) const | |
| { | |
| DCHECK(type() == TypeBinary); | |
| StringUtil::builderAppendQuotedString(*output, m_binaryValue.toBase64()); | |
| } | |
| 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); | |
| } | |
| void SerializedValue::writeJSON(StringBuilder* output) const | |
| { | |
| DCHECK(type() == TypeSerialized); | |
| StringUtil::builderAppend(*output, m_serializedJSON); | |
| } | |
| std::vector<uint8_t> SerializedValue::TakeSerialized() && { | |
| return std::move(m_serializedBinary); | |
| } | |
| void SerializedValue::AppendSerialized(std::vector<uint8_t>* output) const | |
| { | |
| DCHECK(type() == TypeSerialized); | |
| output->insert(output->end(), m_serializedBinary.begin(), m_serializedBinary.end()); | |
| } | |
| std::unique_ptr<Value> SerializedValue::clone() const | |
| { | |
| return std::unique_ptr<SerializedValue>(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> 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::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::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 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<protocol::Value>& value : m_data) { | |
| if (!first) | |
| StringUtil::builderAppend(*output, ','); | |
| value->writeJSON(output); | |
| first = false; | |
| } | |
| StringUtil::builderAppend(*output, ']'); | |
| } | |
| 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 std::move(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(); | |
| } | |
| void escapeLatinStringForJSON(const uint8_t* str, unsigned len, StringBuilder* dst) | |
| { | |
| escapeStringForJSONInternal<uint8_t>(str, len, dst); | |
| } | |
| void escapeWideStringForJSON(const uint16_t* str, unsigned len, StringBuilder* dst) | |
| { | |
| escapeStringForJSONInternal<uint16_t>(str, len, dst); | |
| } | |
| {% for namespace in config.protocol.namespace %} | |
| } // namespace {{namespace}} | |
| {% endfor %} |