blob: 2d4463e2d688d62282bf09545099fc012d1a02a1 [file] [log] [blame]
// 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 <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;
// 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, 0);
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) {
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> 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 %}