dec192fd2f
This lets us accept spec-compliant CBOR tag for message envelopes. This also includes a change in v8-inspector-session-impl.cc that relaxes an envelope check to allow spec-compliant envelopes. Change-Id: Id77c1e0fc4b62d78e8580f81ef38d50e3eb54a1d Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3662540 Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Commit-Queue: Andrey Kosyakov <caseq@chromium.org> Cr-Commit-Position: refs/heads/main@{#80761}
543 lines
15 KiB
Plaintext
543 lines
15 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"
|
|
|
|
#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;
|
|
} // 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 %}
|