enclose-io/compiler

View on GitHub
lts/tools/inspector_protocol/lib/Values_cpp.template

Summary

Maintainability
Test Coverage
// 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, 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) {
      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 %}