DevTools protocol roll
... to revision c40253f87c475880d1bdad4a90cf21c38dadf4ac Also, preseve binary protocol when restoring session. Bug: chromium:929862 Change-Id: Icb1cb04b42ca7238b46e2978337b36e32398665f Reviewed-on: https://chromium-review.googlesource.com/c/1474556 Commit-Queue: Andrey Kosyakov <caseq@chromium.org> Commit-Queue: Pavel Feldman <pfeldman@chromium.org> Reviewed-by: Pavel Feldman <pfeldman@chromium.org> Cr-Commit-Position: refs/heads/master@{#59614}
This commit is contained in:
parent
f781f522af
commit
6703647b93
@ -76,6 +76,8 @@ V8InspectorSessionImpl::V8InspectorSessionImpl(V8InspectorImpl* inspector,
|
||||
m_state = protocol::DictionaryValue::create();
|
||||
}
|
||||
|
||||
m_state->getBoolean("use_binary_protocol", &use_binary_protocol_);
|
||||
|
||||
m_runtimeAgent.reset(new V8RuntimeAgentImpl(
|
||||
this, this, agentState(protocol::Runtime::Metainfo::domainName)));
|
||||
protocol::Runtime::Dispatcher::wire(&m_dispatcher, m_runtimeAgent.get());
|
||||
@ -330,7 +332,11 @@ void V8InspectorSessionImpl::dispatchProtocolMessage(
|
||||
const StringView& message) {
|
||||
bool binary_protocol =
|
||||
message.is8Bit() && message.length() && message.characters8()[0] == 0xD8;
|
||||
if (binary_protocol) use_binary_protocol_ = true;
|
||||
if (binary_protocol) {
|
||||
use_binary_protocol_ = true;
|
||||
m_state->setBoolean("use_binary_protocol", true);
|
||||
}
|
||||
|
||||
int callId;
|
||||
std::unique_ptr<protocol::Value> parsed_message;
|
||||
if (binary_protocol) {
|
||||
|
2
third_party/inspector_protocol/README.v8
vendored
2
third_party/inspector_protocol/README.v8
vendored
@ -2,7 +2,7 @@ Name: inspector protocol
|
||||
Short Name: inspector_protocol
|
||||
URL: https://chromium.googlesource.com/deps/inspector_protocol/
|
||||
Version: 0
|
||||
Revision: ec358ccfd63a2a657c147329c7793d217e278a58
|
||||
Revision: c40253f87c475880d1bdad4a90cf21c38dadf4ac
|
||||
License: BSD
|
||||
License File: LICENSE
|
||||
Security Critical: no
|
||||
|
153
third_party/inspector_protocol/lib/CBOR_cpp.template
vendored
153
third_party/inspector_protocol/lib/CBOR_cpp.template
vendored
@ -15,34 +15,9 @@ namespace {{namespace}} {
|
||||
|
||||
// ===== encoding/cbor.cc =====
|
||||
|
||||
using namespace cbor;
|
||||
|
||||
namespace {
|
||||
using cbor_internals::MajorType;
|
||||
|
||||
// Indicates the number of bits the "initial byte" needs to be shifted to the
|
||||
// right after applying |kMajorTypeMask| to produce the major type in the
|
||||
// lowermost bits.
|
||||
static constexpr uint8_t kMajorTypeBitShift = 5u;
|
||||
// Mask selecting the low-order 5 bits of the "initial byte", which is where
|
||||
// the additional information is encoded.
|
||||
static constexpr uint8_t kAdditionalInformationMask = 0x1f;
|
||||
// Mask selecting the high-order 3 bits of the "initial byte", which indicates
|
||||
// the major type of the encoded value.
|
||||
static constexpr uint8_t kMajorTypeMask = 0xe0;
|
||||
// Indicates the integer is in the following byte.
|
||||
static constexpr uint8_t kAdditionalInformation1Byte = 24u;
|
||||
// Indicates the integer is in the next 2 bytes.
|
||||
static constexpr uint8_t kAdditionalInformation2Bytes = 25u;
|
||||
// Indicates the integer is in the next 4 bytes.
|
||||
static constexpr uint8_t kAdditionalInformation4Bytes = 26u;
|
||||
// Indicates the integer is in the next 8 bytes.
|
||||
static constexpr uint8_t kAdditionalInformation8Bytes = 27u;
|
||||
|
||||
// Encodes the initial byte, consisting of the |type| in the first 3 bits
|
||||
// followed by 5 bits of |additional_info|.
|
||||
constexpr uint8_t EncodeInitialByte(MajorType type, uint8_t additional_info) {
|
||||
return (uint8_t(type) << kMajorTypeBitShift) |
|
||||
(additional_info & kAdditionalInformationMask);
|
||||
}
|
||||
|
||||
// See RFC 7049 Section 2.3, Table 2.
|
||||
static constexpr uint8_t kEncodedTrue =
|
||||
@ -53,38 +28,13 @@ static constexpr uint8_t kEncodedNull =
|
||||
EncodeInitialByte(MajorType::SIMPLE_VALUE, 22);
|
||||
static constexpr uint8_t kInitialByteForDouble =
|
||||
EncodeInitialByte(MajorType::SIMPLE_VALUE, 27);
|
||||
|
||||
} // namespace
|
||||
|
||||
uint8_t EncodeTrue() { return kEncodedTrue; }
|
||||
uint8_t EncodeFalse() { return kEncodedFalse; }
|
||||
uint8_t EncodeNull() { return kEncodedNull; }
|
||||
|
||||
namespace {
|
||||
// TAG 24 indicates that what follows is a byte string which is
|
||||
// encoded in CBOR format. We use this as a wrapper for
|
||||
// maps and arrays, allowing us to skip them, because the
|
||||
// byte string carries its size (byte length).
|
||||
// https://tools.ietf.org/html/rfc7049#section-2.4.4.1
|
||||
static constexpr uint8_t kInitialByteForEnvelope =
|
||||
EncodeInitialByte(MajorType::TAG, 24);
|
||||
// The initial byte for a byte string with at most 2^32 bytes
|
||||
// of payload. This is used for envelope encoding, even if
|
||||
// the byte string is shorter.
|
||||
static constexpr uint8_t kInitialByteFor32BitLengthByteString =
|
||||
EncodeInitialByte(MajorType::BYTE_STRING, 26);
|
||||
|
||||
// See RFC 7049 Section 2.2.1, indefinite length arrays / maps have additional
|
||||
// info = 31.
|
||||
static constexpr uint8_t kInitialByteIndefiniteLengthArray =
|
||||
EncodeInitialByte(MajorType::ARRAY, 31);
|
||||
static constexpr uint8_t kInitialByteIndefiniteLengthMap =
|
||||
EncodeInitialByte(MajorType::MAP, 31);
|
||||
// See RFC 7049 Section 2.3, Table 1; this is used for finishing indefinite
|
||||
// length maps / arrays.
|
||||
static constexpr uint8_t kStopByte =
|
||||
EncodeInitialByte(MajorType::SIMPLE_VALUE, 31);
|
||||
} // namespace
|
||||
|
||||
uint8_t EncodeIndefiniteLengthArrayStart() {
|
||||
return kInitialByteIndefiniteLengthArray;
|
||||
}
|
||||
@ -122,7 +72,7 @@ void WriteTokenStart(MajorType type, uint64_t value,
|
||||
if (value < 24) {
|
||||
// Values 0-23 are encoded directly into the additional info of the
|
||||
// initial byte.
|
||||
encoded->push_back(EncodeInitialByte(type, /*additiona_info=*/value));
|
||||
encoded->push_back(EncodeInitialByte(type, /*additional_info=*/value));
|
||||
return;
|
||||
}
|
||||
if (value <= std::numeric_limits<uint8_t>::max()) {
|
||||
@ -156,9 +106,9 @@ namespace {
|
||||
// See also: https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
|
||||
template <typename T>
|
||||
T ReadBytesMostSignificantByteFirst(span<uint8_t> in) {
|
||||
assert(size_t(in.size()) >= sizeof(T));
|
||||
assert(static_cast<std::size_t>(in.size()) >= sizeof(T));
|
||||
T result = 0;
|
||||
for (size_t shift_bytes = 0; shift_bytes < sizeof(T); ++shift_bytes)
|
||||
for (std::size_t shift_bytes = 0; shift_bytes < sizeof(T); ++shift_bytes)
|
||||
result |= T(in[sizeof(T) - 1 - shift_bytes]) << (shift_bytes * 8);
|
||||
return result;
|
||||
}
|
||||
@ -185,19 +135,22 @@ int8_t ReadTokenStart(span<uint8_t> bytes, MajorType* type, uint64_t* value) {
|
||||
}
|
||||
if (additional_information == kAdditionalInformation2Bytes) {
|
||||
// Values 256-65535: 1 initial byte + 2 bytes payload.
|
||||
if (static_cast<size_t>(bytes.size()) < 1 + sizeof(uint16_t)) return -1;
|
||||
if (static_cast<std::size_t>(bytes.size()) < 1 + sizeof(uint16_t))
|
||||
return -1;
|
||||
*value = ReadBytesMostSignificantByteFirst<uint16_t>(bytes.subspan(1));
|
||||
return 3;
|
||||
}
|
||||
if (additional_information == kAdditionalInformation4Bytes) {
|
||||
// 32 bit uint: 1 initial byte + 4 bytes payload.
|
||||
if (static_cast<size_t>(bytes.size()) < 1 + sizeof(uint32_t)) return -1;
|
||||
if (static_cast<std::size_t>(bytes.size()) < 1 + sizeof(uint32_t))
|
||||
return -1;
|
||||
*value = ReadBytesMostSignificantByteFirst<uint32_t>(bytes.subspan(1));
|
||||
return 5;
|
||||
}
|
||||
if (additional_information == kAdditionalInformation8Bytes) {
|
||||
// 64 bit uint: 1 initial byte + 8 bytes payload.
|
||||
if (static_cast<size_t>(bytes.size()) < 1 + sizeof(uint64_t)) return -1;
|
||||
if (static_cast<std::size_t>(bytes.size()) < 1 + sizeof(uint64_t))
|
||||
return -1;
|
||||
*value = ReadBytesMostSignificantByteFirst<uint64_t>(bytes.subspan(1));
|
||||
return 9;
|
||||
}
|
||||
@ -205,7 +158,6 @@ int8_t ReadTokenStart(span<uint8_t> bytes, MajorType* type, uint64_t* value) {
|
||||
}
|
||||
} // namespace cbor_internals
|
||||
|
||||
using cbor_internals::MajorType;
|
||||
using cbor_internals::WriteTokenStart;
|
||||
using cbor_internals::ReadTokenStart;
|
||||
|
||||
@ -669,7 +621,8 @@ void CBORTokenizer::ReadNextToken(bool enter_envelope) {
|
||||
SetError(Error::CBOR_INVALID_BINARY);
|
||||
return;
|
||||
}
|
||||
SetToken(CBORTokenTag::BINARY, std::ptrdiff_t(token_byte_length));
|
||||
SetToken(CBORTokenTag::BINARY,
|
||||
static_cast<std::ptrdiff_t>(token_byte_length));
|
||||
return;
|
||||
}
|
||||
case kInitialByteForDouble: { // DOUBLE
|
||||
@ -696,7 +649,7 @@ void CBORTokenizer::ReadNextToken(bool enter_envelope) {
|
||||
// Make sure the payload is contained within the message.
|
||||
if (token_start_internal_value_ + kEncodedEnvelopeHeaderSize +
|
||||
status_.pos >
|
||||
size_t(bytes_.size())) {
|
||||
static_cast<std::size_t>(bytes_.size())) {
|
||||
SetError(Error::CBOR_INVALID_ENVELOPE);
|
||||
return;
|
||||
}
|
||||
@ -731,8 +684,8 @@ void CBORTokenizer::ReadNextToken(bool enter_envelope) {
|
||||
SetToken(CBORTokenTag::INT32, token_start_length);
|
||||
return;
|
||||
case MajorType::STRING: { // STRING8.
|
||||
if (!success ||
|
||||
remainder.size() < int64_t(token_start_internal_value_)) {
|
||||
if (!success || remainder.size() < static_cast<int64_t>(
|
||||
token_start_internal_value_)) {
|
||||
SetError(Error::CBOR_INVALID_STRING8);
|
||||
return;
|
||||
}
|
||||
@ -742,7 +695,8 @@ void CBORTokenizer::ReadNextToken(bool enter_envelope) {
|
||||
}
|
||||
case MajorType::BYTE_STRING: { // STRING16.
|
||||
if (!success ||
|
||||
remainder.size() < int64_t(token_start_internal_value_) ||
|
||||
remainder.size() <
|
||||
static_cast<int64_t>(token_start_internal_value_) ||
|
||||
// Must be divisible by 2 since UTF16 is 2 bytes per character.
|
||||
token_start_internal_value_ & 1) {
|
||||
SetError(Error::CBOR_INVALID_STRING16);
|
||||
@ -774,6 +728,75 @@ void CBORTokenizer::SetError(Error error) {
|
||||
status_.error = error;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void DumpCBOR(span<uint8_t> cbor) {
|
||||
std::string indent;
|
||||
CBORTokenizer tokenizer(cbor);
|
||||
while (true) {
|
||||
fprintf(stderr, "%s", indent.c_str());
|
||||
switch (tokenizer.TokenTag()) {
|
||||
case CBORTokenTag::ERROR_VALUE:
|
||||
fprintf(stderr, "ERROR {status.error=%d, status.pos=%ld}\n",
|
||||
tokenizer.Status().error, tokenizer.Status().pos);
|
||||
return;
|
||||
case CBORTokenTag::DONE:
|
||||
fprintf(stderr, "DONE\n");
|
||||
return;
|
||||
case CBORTokenTag::TRUE_VALUE:
|
||||
fprintf(stderr, "TRUE_VALUE\n");
|
||||
break;
|
||||
case CBORTokenTag::FALSE_VALUE:
|
||||
fprintf(stderr, "FALSE_VALUE\n");
|
||||
break;
|
||||
case CBORTokenTag::NULL_VALUE:
|
||||
fprintf(stderr, "NULL_VALUE\n");
|
||||
break;
|
||||
case CBORTokenTag::INT32:
|
||||
fprintf(stderr, "INT32 [%d]\n", tokenizer.GetInt32());
|
||||
break;
|
||||
case CBORTokenTag::DOUBLE:
|
||||
fprintf(stderr, "DOUBLE [%lf]\n", tokenizer.GetDouble());
|
||||
break;
|
||||
case CBORTokenTag::STRING8: {
|
||||
span<uint8_t> v = tokenizer.GetString8();
|
||||
std::string t(v.begin(), v.end());
|
||||
fprintf(stderr, "STRING8 [%s]\n", t.c_str());
|
||||
break;
|
||||
}
|
||||
case CBORTokenTag::STRING16: {
|
||||
span<uint8_t> v = tokenizer.GetString16WireRep();
|
||||
std::string t(v.begin(), v.end());
|
||||
fprintf(stderr, "STRING16 [%s]\n", t.c_str());
|
||||
break;
|
||||
}
|
||||
case CBORTokenTag::BINARY: {
|
||||
span<uint8_t> v = tokenizer.GetBinary();
|
||||
std::string t(v.begin(), v.end());
|
||||
fprintf(stderr, "BINARY [%s]\n", t.c_str());
|
||||
break;
|
||||
}
|
||||
case CBORTokenTag::MAP_START:
|
||||
fprintf(stderr, "MAP_START\n");
|
||||
indent += " ";
|
||||
break;
|
||||
case CBORTokenTag::ARRAY_START:
|
||||
fprintf(stderr, "ARRAY_START\n");
|
||||
indent += " ";
|
||||
break;
|
||||
case CBORTokenTag::STOP:
|
||||
fprintf(stderr, "STOP\n");
|
||||
indent.erase(0, 2);
|
||||
break;
|
||||
case CBORTokenTag::ENVELOPE:
|
||||
fprintf(stderr, "ENVELOPE\n");
|
||||
tokenizer.EnterEnvelope();
|
||||
continue;
|
||||
}
|
||||
tokenizer.Next();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
{% for namespace in config.protocol.namespace %}
|
||||
} // namespace {{namespace}}
|
||||
|
@ -135,7 +135,31 @@ class JSONParserHandler {
|
||||
|
||||
// ===== encoding/cbor_internals.h =====
|
||||
|
||||
namespace cbor {
|
||||
enum class MajorType;
|
||||
}
|
||||
|
||||
namespace cbor_internals {
|
||||
|
||||
// Reads the start of a token with definitive size from |bytes|.
|
||||
// |type| is the major type as specified in RFC 7049 Section 2.1.
|
||||
// |value| is the payload (e.g. for MajorType::UNSIGNED) or is the size
|
||||
// (e.g. for BYTE_STRING).
|
||||
// If successful, returns the number of bytes read. Otherwise returns -1.
|
||||
int8_t ReadTokenStart(span<uint8_t> bytes, cbor::MajorType* type,
|
||||
uint64_t* value);
|
||||
|
||||
// Writes the start of a token with |type|. The |value| may indicate the size,
|
||||
// or it may be the payload if the value is an unsigned integer.
|
||||
void WriteTokenStart(cbor::MajorType type, uint64_t value,
|
||||
std::vector<uint8_t>* encoded);
|
||||
} // namespace cbor_internals
|
||||
|
||||
// ===== encoding/cbor.h =====
|
||||
|
||||
|
||||
namespace cbor {
|
||||
|
||||
// The major types from RFC 7049 Section 2.1.
|
||||
enum class MajorType {
|
||||
UNSIGNED = 0,
|
||||
@ -148,20 +172,57 @@ enum class MajorType {
|
||||
SIMPLE_VALUE = 7
|
||||
};
|
||||
|
||||
// Reads the start of a token with definitive size from |bytes|.
|
||||
// |type| is the major type as specified in RFC 7049 Section 2.1.
|
||||
// |value| is the payload (e.g. for MajorType::UNSIGNED) or is the size
|
||||
// (e.g. for BYTE_STRING).
|
||||
// If successful, returns the number of bytes read. Otherwise returns -1.
|
||||
int8_t ReadTokenStart(span<uint8_t> bytes, MajorType* type, uint64_t* value);
|
||||
// Indicates the number of bits the "initial byte" needs to be shifted to the
|
||||
// right after applying |kMajorTypeMask| to produce the major type in the
|
||||
// lowermost bits.
|
||||
static constexpr uint8_t kMajorTypeBitShift = 5u;
|
||||
// Mask selecting the low-order 5 bits of the "initial byte", which is where
|
||||
// the additional information is encoded.
|
||||
static constexpr uint8_t kAdditionalInformationMask = 0x1f;
|
||||
// Mask selecting the high-order 3 bits of the "initial byte", which indicates
|
||||
// the major type of the encoded value.
|
||||
static constexpr uint8_t kMajorTypeMask = 0xe0;
|
||||
// Indicates the integer is in the following byte.
|
||||
static constexpr uint8_t kAdditionalInformation1Byte = 24u;
|
||||
// Indicates the integer is in the next 2 bytes.
|
||||
static constexpr uint8_t kAdditionalInformation2Bytes = 25u;
|
||||
// Indicates the integer is in the next 4 bytes.
|
||||
static constexpr uint8_t kAdditionalInformation4Bytes = 26u;
|
||||
// Indicates the integer is in the next 8 bytes.
|
||||
static constexpr uint8_t kAdditionalInformation8Bytes = 27u;
|
||||
|
||||
// Writes the start of a token with |type|. The |value| may indicate the size,
|
||||
// or it may be the payload if the value is an unsigned integer.
|
||||
void WriteTokenStart(MajorType type, uint64_t value,
|
||||
std::vector<uint8_t>* encoded);
|
||||
} // namespace cbor_internals
|
||||
// Encodes the initial byte, consisting of the |type| in the first 3 bits
|
||||
// followed by 5 bits of |additional_info|.
|
||||
constexpr uint8_t EncodeInitialByte(MajorType type, uint8_t additional_info) {
|
||||
return (static_cast<uint8_t>(type) << kMajorTypeBitShift) |
|
||||
(additional_info & kAdditionalInformationMask);
|
||||
}
|
||||
|
||||
// ===== encoding/cbor.h =====
|
||||
// TAG 24 indicates that what follows is a byte string which is
|
||||
// encoded in CBOR format. We use this as a wrapper for
|
||||
// maps and arrays, allowing us to skip them, because the
|
||||
// byte string carries its size (byte length).
|
||||
// https://tools.ietf.org/html/rfc7049#section-2.4.4.1
|
||||
static constexpr uint8_t kInitialByteForEnvelope =
|
||||
EncodeInitialByte(MajorType::TAG, 24);
|
||||
// The initial byte for a byte string with at most 2^32 bytes
|
||||
// of payload. This is used for envelope encoding, even if
|
||||
// the byte string is shorter.
|
||||
static constexpr uint8_t kInitialByteFor32BitLengthByteString =
|
||||
EncodeInitialByte(MajorType::BYTE_STRING, 26);
|
||||
|
||||
// See RFC 7049 Section 2.2.1, indefinite length arrays / maps have additional
|
||||
// info = 31.
|
||||
static constexpr uint8_t kInitialByteIndefiniteLengthArray =
|
||||
EncodeInitialByte(MajorType::ARRAY, 31);
|
||||
static constexpr uint8_t kInitialByteIndefiniteLengthMap =
|
||||
EncodeInitialByte(MajorType::MAP, 31);
|
||||
// See RFC 7049 Section 2.3, Table 1; this is used for finishing indefinite
|
||||
// length maps / arrays.
|
||||
static constexpr uint8_t kStopByte =
|
||||
EncodeInitialByte(MajorType::SIMPLE_VALUE, 31);
|
||||
|
||||
} // namespace cbor
|
||||
|
||||
// The binary encoding for the inspector protocol follows the CBOR specification
|
||||
// (RFC 7049). Additional constraints:
|
||||
@ -231,7 +292,7 @@ class EnvelopeEncoder {
|
||||
bool EncodeStop(std::vector<uint8_t>* out);
|
||||
|
||||
private:
|
||||
std::vector<uint8_t>::size_type byte_size_pos_ = 0;
|
||||
std::size_t byte_size_pos_ = 0;
|
||||
};
|
||||
|
||||
// This can be used to convert from JSON to CBOR, by passing the
|
||||
@ -342,10 +403,13 @@ class CBORTokenizer {
|
||||
CBORTokenTag token_tag_;
|
||||
struct Status status_;
|
||||
std::ptrdiff_t token_byte_length_;
|
||||
cbor_internals::MajorType token_start_type_;
|
||||
cbor::MajorType token_start_type_;
|
||||
uint64_t token_start_internal_value_;
|
||||
};
|
||||
|
||||
void DumpCBOR(span<uint8_t> cbor);
|
||||
|
||||
|
||||
{% for namespace in config.protocol.namespace %}
|
||||
} // namespace {{namespace}}
|
||||
{% endfor %}
|
||||
|
@ -168,6 +168,7 @@ std::unique_ptr<DictionaryValue> parseMap(
|
||||
String key;
|
||||
if (tokenizer->TokenTag() == CBORTokenTag::STRING8) {
|
||||
span<uint8_t> key_span = tokenizer->GetString8();
|
||||
tokenizer->Next();
|
||||
key = StringUtil::fromUTF8(key_span.data(), key_span.size());
|
||||
} else if (tokenizer->TokenTag() == CBORTokenTag::STRING16) {
|
||||
return nullptr; // STRING16 not supported yet.
|
||||
@ -178,6 +179,7 @@ std::unique_ptr<DictionaryValue> parseMap(
|
||||
// Parse value.
|
||||
auto value = parseValue(stack_depth, tokenizer);
|
||||
if (!value) return nullptr;
|
||||
dict->setValue(key, std::move(value));
|
||||
}
|
||||
tokenizer->Next();
|
||||
return dict;
|
||||
|
@ -39,7 +39,8 @@ public:
|
||||
TypeBinary,
|
||||
TypeObject,
|
||||
TypeArray,
|
||||
TypeSerialized
|
||||
TypeSerialized,
|
||||
TypeImported
|
||||
};
|
||||
|
||||
ValueType type() const { return m_type; }
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "base/json/json_reader.h"
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/values.h"
|
||||
|
||||
@ -229,6 +230,75 @@ Binary Binary::fromSpan(const uint8_t* data, size_t size) {
|
||||
new base::RefCountedBytes(data, size)));
|
||||
}
|
||||
|
||||
namespace {
|
||||
int32_t ReadEnvelopeSize(const uint8_t* in) {
|
||||
return (in[0] << 24) + (in[1] << 16) + (in[2] << 8) + in[3];
|
||||
}
|
||||
|
||||
void WriteEnvelopeSize(uint32_t value, uint8_t* out) {
|
||||
*(out++) = (value >> 24) & 0xFF;
|
||||
*(out++) = (value >> 16) & 0xFF;
|
||||
*(out++) = (value >> 8) & 0xFF;
|
||||
*(out++) = (value) & 0xFF;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool AppendStringValueToMapBinary(base::StringPiece in,
|
||||
base::StringPiece key, base::StringPiece value, std::string* out) {
|
||||
if (in.size() < 1 + 1 + 4 + 1 + 1)
|
||||
return false;
|
||||
const uint8_t* envelope = reinterpret_cast<const uint8_t*>(in.data());
|
||||
if (cbor::kInitialByteForEnvelope != envelope[0])
|
||||
return false;
|
||||
if (cbor::kInitialByteFor32BitLengthByteString != envelope[1])
|
||||
return false;
|
||||
if (cbor::kInitialByteIndefiniteLengthMap != envelope[6])
|
||||
return false;
|
||||
|
||||
uint32_t envelope_size = ReadEnvelopeSize(envelope + 2);
|
||||
if (envelope_size + 2 + 4 != in.size())
|
||||
return false;
|
||||
if (cbor::kStopByte != static_cast<uint8_t>(*in.rbegin()))
|
||||
return false;
|
||||
|
||||
std::vector<uint8_t> encoded_entry;
|
||||
encoded_entry.reserve(1 + 4 + key.size() + 1 + 4 + value.size());
|
||||
span<uint8_t> key_span(
|
||||
reinterpret_cast<const uint8_t*>(key.data()), key.size());
|
||||
EncodeString8(key_span, &encoded_entry);
|
||||
span<uint8_t> value_span(
|
||||
reinterpret_cast<const uint8_t*>(value.data()), value.size());
|
||||
EncodeString8(value_span, &encoded_entry);
|
||||
|
||||
out->clear();
|
||||
out->reserve(in.size() + encoded_entry.size());
|
||||
out->append(in.begin(), in.end() - 1);
|
||||
out->append(reinterpret_cast<const char*>(encoded_entry.data()),
|
||||
encoded_entry.size());
|
||||
out->append(1, static_cast<char>(cbor::kStopByte));
|
||||
std::size_t new_size = envelope_size + out->size() - in.size();
|
||||
if (new_size > static_cast<std::size_t>(
|
||||
std::numeric_limits<uint32_t>::max())) {
|
||||
return false;
|
||||
}
|
||||
WriteEnvelopeSize(new_size, reinterpret_cast<uint8_t*>(&*out->begin() + 2));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AppendStringValueToMapJSON(base::StringPiece in,
|
||||
base::StringPiece key, base::StringPiece value, std::string* out) {
|
||||
if (!in.length() || *in.rbegin() != '}')
|
||||
return false;
|
||||
std::string suffix =
|
||||
base::StringPrintf(", \"%s\": \"%s\"}", key.begin(), value.begin());
|
||||
out->clear();
|
||||
out->reserve(in.length() + suffix.length() - 1);
|
||||
out->append(in.data(), in.length() - 1);
|
||||
out->append(suffix);
|
||||
return true;
|
||||
}
|
||||
|
||||
{% for namespace in config.protocol.namespace %}
|
||||
} // namespace {{namespace}}
|
||||
{% endfor %}
|
||||
|
@ -134,6 +134,11 @@ class {{config.lib.export_macro}} Binary {
|
||||
std::unique_ptr<Value> toProtocolValue(const base::Value* value, int depth);
|
||||
std::unique_ptr<base::Value> toBaseValue(Value* value, int depth);
|
||||
|
||||
bool AppendStringValueToMapBinary(base::StringPiece in,
|
||||
base::StringPiece key, base::StringPiece value, std::string* out);
|
||||
bool AppendStringValueToMapJSON(base::StringPiece in,
|
||||
base::StringPiece key, base::StringPiece value, std::string* out);
|
||||
|
||||
{% for namespace in config.protocol.namespace %}
|
||||
} // namespace {{namespace}}
|
||||
{% endfor %}
|
||||
|
@ -15,6 +15,17 @@
|
||||
{% for namespace in config.protocol.namespace %}
|
||||
namespace {{namespace}} {
|
||||
{% endfor %}
|
||||
|
||||
#ifndef {{"_".join(config.protocol.namespace)}}_exported_api_h
|
||||
#define {{"_".join(config.protocol.namespace)}}_exported_api_h
|
||||
class {{config.exported.export_macro}} Exported {
|
||||
public:
|
||||
virtual {{config.exported.string_out}} toJSONString() const = 0;
|
||||
virtual void writeBinary(std::vector<uint8_t>* out) const = 0;
|
||||
virtual ~Exported() { }
|
||||
};
|
||||
#endif // !defined({{"_".join(config.protocol.namespace)}}_exported_api_h)
|
||||
|
||||
namespace {{domain.domain}} {
|
||||
namespace API {
|
||||
|
||||
@ -48,11 +59,8 @@ namespace {{param.name | to_title_case}}Enum {
|
||||
{% for type in domain.types %}
|
||||
{% if not (type.type == "object") or not ("properties" in type) or not protocol.is_exported(domain.domain, type.id) %}{% continue %}{% endif %}
|
||||
|
||||
class {{config.exported.export_macro}} {{type.id}} {
|
||||
class {{config.exported.export_macro}} {{type.id}} : public Exported {
|
||||
public:
|
||||
virtual {{config.exported.string_out}} toJSONString() const = 0;
|
||||
virtual std::vector<uint8_t> toBinary() const = 0;
|
||||
virtual ~{{type.id}}() { }
|
||||
static std::unique_ptr<protocol::{{domain.domain}}::API::{{type.id}}> fromJSONString(const {{config.exported.string_in}}& json);
|
||||
static std::unique_ptr<protocol::{{domain.domain}}::API::{{type.id}}> fromBinary(const uint8_t* data, size_t length);
|
||||
};
|
||||
|
@ -17,6 +17,37 @@
|
||||
{% for namespace in config.protocol.namespace %}
|
||||
namespace {{namespace}} {
|
||||
{% endfor %}
|
||||
|
||||
using Exported = {{"::".join(config.imported.namespace)}}::Exported;
|
||||
|
||||
#ifndef {{"_".join(config.protocol.namespace)}}_imported_imported_h
|
||||
#define {{"_".join(config.protocol.namespace)}}_imported_imported_h
|
||||
|
||||
class {{config.lib.export_macro}} ImportedValue : public Value {
|
||||
public:
|
||||
static std::unique_ptr<ImportedValue> fromExported(const Exported* value) {
|
||||
return std::unique_ptr<ImportedValue>(new ImportedValue(value));
|
||||
}
|
||||
|
||||
void writeJSON(StringBuilder* output) const override {
|
||||
auto json = m_exported->toJSONString();
|
||||
String local_json = ({{config.imported.from_imported_string % "std::move(json)"}});
|
||||
StringUtil::builderAppend(*output, local_json);
|
||||
}
|
||||
void writeBinary(std::vector<uint8_t>* output) const override {
|
||||
m_exported->writeBinary(output);
|
||||
}
|
||||
std::unique_ptr<Value> clone() const override {
|
||||
return std::unique_ptr<Value>(new ImportedValue(m_exported));
|
||||
}
|
||||
|
||||
private:
|
||||
explicit ImportedValue(const Exported* exported) : Value(TypeImported), m_exported(exported) { }
|
||||
const Exported* m_exported;
|
||||
};
|
||||
|
||||
#endif // !defined({{"_".join(config.protocol.namespace)}}_imported_imported_h)
|
||||
|
||||
{% for type in domain.types %}
|
||||
{% if not (type.type == "object") or not ("properties" in type) or not protocol.is_imported(domain.domain, type.id) %}{% continue %}{% endif %}
|
||||
|
||||
@ -29,32 +60,17 @@ struct ValueConversions<{{"::".join(config.imported.namespace)}}::{{domain.domai
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// TODO(pfeldman): toggle to true and delete the json branch when binary is ready.
|
||||
bool binary_protocol = false;
|
||||
std::unique_ptr<{{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}> result;
|
||||
if (binary_protocol) {
|
||||
std::vector<uint8_t> binary = value->serializeToBinary();
|
||||
result = {{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}::fromBinary(binary.data(), binary.size());
|
||||
} else {
|
||||
String json = value->serializeToJSON();
|
||||
result = {{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}::fromJSONString({{config.imported.to_imported_string % "json"}});
|
||||
}
|
||||
std::vector<uint8_t> binary;
|
||||
value->writeBinary(&binary);
|
||||
auto result = {{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}::fromBinary(binary.data(), binary.size());
|
||||
if (!result)
|
||||
errors->addError("cannot parse");
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::unique_ptr<protocol::Value> toValue(const {{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}* value)
|
||||
static std::unique_ptr<protocol::Value> toValue(const {{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}* exported)
|
||||
{
|
||||
// TODO(pfeldman): toggle to true and delete the json branch when binary is ready.
|
||||
bool binary_protocol = false;
|
||||
if (binary_protocol) {
|
||||
return SerializedValue::fromBinary(value->toBinary());
|
||||
} else {
|
||||
auto json = value->toJSONString();
|
||||
String local_json = ({{config.imported.from_imported_string % "std::move(json)"}});
|
||||
return SerializedValue::fromJSON(local_json);
|
||||
}
|
||||
return ImportedValue::fromExported(exported);
|
||||
}
|
||||
|
||||
static std::unique_ptr<protocol::Value> toValue(const std::unique_ptr<{{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}>& value)
|
||||
@ -62,6 +78,7 @@ struct ValueConversions<{{"::".join(config.imported.namespace)}}::{{domain.domai
|
||||
return toValue(value.get());
|
||||
}
|
||||
};
|
||||
|
||||
{% endfor %}
|
||||
|
||||
{% for namespace in config.protocol.namespace %}
|
||||
|
@ -105,9 +105,9 @@ std::unique_ptr<{{type.id}}> {{type.id}}::clone() const
|
||||
return {{config.exported.to_string_out % "json"}};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> {{type.id}}::toBinary() const
|
||||
void {{type.id}}::writeBinary(std::vector<uint8_t>* out) const
|
||||
{
|
||||
return toValue()->serializeToBinary();
|
||||
toValue()->writeBinary(out);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -106,7 +106,7 @@ public:
|
||||
std::unique_ptr<{{type.id}}> clone() const;
|
||||
{% if protocol.is_exported(domain.domain, type.id) %}
|
||||
{{config.exported.string_out}} toJSONString() const override;
|
||||
std::vector<uint8_t> toBinary() const override;
|
||||
void writeBinary(std::vector<uint8_t>* out) const override;
|
||||
{% endif %}
|
||||
|
||||
template<int STATE>
|
||||
|
Loading…
Reference in New Issue
Block a user