b179dd8352
New revision: e8ba1a7665bdcd8336915d5ca4b390e0cf6b1f6f Change-Id: I6a916f003a29b0b9436ad031bbd43eddfa189e63 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1634938 Auto-Submit: Johannes Henkel <johannes@chromium.org> Reviewed-by: Alexei Filippov <alph@chromium.org> Commit-Queue: Alexei Filippov <alph@chromium.org> Cr-Commit-Position: refs/heads/master@{#61923}
716 lines
22 KiB
Plaintext
716 lines
22 KiB
Plaintext
// 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"
|
|
|
|
{% if config.encoding_lib.header %}
|
|
#include "{{config.encoding_lib.header}}"
|
|
{% endif %}
|
|
|
|
{% 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;
|
|
|
|
{% if config.encoding_lib.namespace %}
|
|
using {{"::".join(config.encoding_lib.namespace)}}::Error;
|
|
using {{"::".join(config.encoding_lib.namespace)}}::Status;
|
|
using {{"::".join(config.encoding_lib.namespace)}}::span;
|
|
namespace cbor {
|
|
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::CBORTokenTag;
|
|
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::CBORTokenizer;
|
|
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeBinary;
|
|
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeDouble;
|
|
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeFalse;
|
|
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeFromLatin1;
|
|
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeFromUTF16;
|
|
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeIndefiniteLengthArrayStart;
|
|
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeIndefiniteLengthMapStart;
|
|
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeInt32;
|
|
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeNull;
|
|
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeStop;
|
|
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeString8;
|
|
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeTrue;
|
|
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EnvelopeEncoder;
|
|
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::InitialByteForEnvelope;
|
|
} // namespace cbor
|
|
{% endif %}
|
|
|
|
// 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::fromUTF16(
|
|
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::fromUTF16(
|
|
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::writeBinary(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);
|
|
}
|
|
|
|
String Value::serializeToJSON() {
|
|
return toJSONString();
|
|
}
|
|
|
|
std::vector<uint8_t> Value::serializeToBinary() {
|
|
std::vector<uint8_t> 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<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::writeBinary(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::writeBinary(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);
|
|
}
|
|
|
|
void SerializedValue::writeBinary(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::writeBinary(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->writeBinary(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::writeBinary(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]->writeBinary(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 %}
|