Commit 6703647b authored by Andrey Kosyakov's avatar Andrey Kosyakov Committed by Commit Bot

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: 's avatarPavel Feldman <pfeldman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59614}
parent f781f522
...@@ -76,6 +76,8 @@ V8InspectorSessionImpl::V8InspectorSessionImpl(V8InspectorImpl* inspector, ...@@ -76,6 +76,8 @@ V8InspectorSessionImpl::V8InspectorSessionImpl(V8InspectorImpl* inspector,
m_state = protocol::DictionaryValue::create(); m_state = protocol::DictionaryValue::create();
} }
m_state->getBoolean("use_binary_protocol", &use_binary_protocol_);
m_runtimeAgent.reset(new V8RuntimeAgentImpl( m_runtimeAgent.reset(new V8RuntimeAgentImpl(
this, this, agentState(protocol::Runtime::Metainfo::domainName))); this, this, agentState(protocol::Runtime::Metainfo::domainName)));
protocol::Runtime::Dispatcher::wire(&m_dispatcher, m_runtimeAgent.get()); protocol::Runtime::Dispatcher::wire(&m_dispatcher, m_runtimeAgent.get());
...@@ -330,7 +332,11 @@ void V8InspectorSessionImpl::dispatchProtocolMessage( ...@@ -330,7 +332,11 @@ void V8InspectorSessionImpl::dispatchProtocolMessage(
const StringView& message) { const StringView& message) {
bool binary_protocol = bool binary_protocol =
message.is8Bit() && message.length() && message.characters8()[0] == 0xD8; 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; int callId;
std::unique_ptr<protocol::Value> parsed_message; std::unique_ptr<protocol::Value> parsed_message;
if (binary_protocol) { if (binary_protocol) {
......
...@@ -2,7 +2,7 @@ Name: inspector protocol ...@@ -2,7 +2,7 @@ Name: inspector protocol
Short Name: inspector_protocol Short Name: inspector_protocol
URL: https://chromium.googlesource.com/deps/inspector_protocol/ URL: https://chromium.googlesource.com/deps/inspector_protocol/
Version: 0 Version: 0
Revision: ec358ccfd63a2a657c147329c7793d217e278a58 Revision: c40253f87c475880d1bdad4a90cf21c38dadf4ac
License: BSD License: BSD
License File: LICENSE License File: LICENSE
Security Critical: no Security Critical: no
......
...@@ -15,34 +15,9 @@ namespace {{namespace}} { ...@@ -15,34 +15,9 @@ namespace {{namespace}} {
// ===== encoding/cbor.cc ===== // ===== encoding/cbor.cc =====
using namespace cbor;
namespace { 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. // See RFC 7049 Section 2.3, Table 2.
static constexpr uint8_t kEncodedTrue = static constexpr uint8_t kEncodedTrue =
...@@ -53,38 +28,13 @@ static constexpr uint8_t kEncodedNull = ...@@ -53,38 +28,13 @@ static constexpr uint8_t kEncodedNull =
EncodeInitialByte(MajorType::SIMPLE_VALUE, 22); EncodeInitialByte(MajorType::SIMPLE_VALUE, 22);
static constexpr uint8_t kInitialByteForDouble = static constexpr uint8_t kInitialByteForDouble =
EncodeInitialByte(MajorType::SIMPLE_VALUE, 27); EncodeInitialByte(MajorType::SIMPLE_VALUE, 27);
} // namespace } // namespace
uint8_t EncodeTrue() { return kEncodedTrue; } uint8_t EncodeTrue() { return kEncodedTrue; }
uint8_t EncodeFalse() { return kEncodedFalse; } uint8_t EncodeFalse() { return kEncodedFalse; }
uint8_t EncodeNull() { return kEncodedNull; } 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() { uint8_t EncodeIndefiniteLengthArrayStart() {
return kInitialByteIndefiniteLengthArray; return kInitialByteIndefiniteLengthArray;
} }
...@@ -122,7 +72,7 @@ void WriteTokenStart(MajorType type, uint64_t value, ...@@ -122,7 +72,7 @@ void WriteTokenStart(MajorType type, uint64_t value,
if (value < 24) { if (value < 24) {
// Values 0-23 are encoded directly into the additional info of the // Values 0-23 are encoded directly into the additional info of the
// initial byte. // initial byte.
encoded->push_back(EncodeInitialByte(type, /*additiona_info=*/value)); encoded->push_back(EncodeInitialByte(type, /*additional_info=*/value));
return; return;
} }
if (value <= std::numeric_limits<uint8_t>::max()) { if (value <= std::numeric_limits<uint8_t>::max()) {
...@@ -156,9 +106,9 @@ namespace { ...@@ -156,9 +106,9 @@ namespace {
// See also: https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html // See also: https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
template <typename T> template <typename T>
T ReadBytesMostSignificantByteFirst(span<uint8_t> in) { 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; 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); result |= T(in[sizeof(T) - 1 - shift_bytes]) << (shift_bytes * 8);
return result; return result;
} }
...@@ -185,19 +135,22 @@ int8_t ReadTokenStart(span<uint8_t> bytes, MajorType* type, uint64_t* value) { ...@@ -185,19 +135,22 @@ int8_t ReadTokenStart(span<uint8_t> bytes, MajorType* type, uint64_t* value) {
} }
if (additional_information == kAdditionalInformation2Bytes) { if (additional_information == kAdditionalInformation2Bytes) {
// Values 256-65535: 1 initial byte + 2 bytes payload. // 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)); *value = ReadBytesMostSignificantByteFirst<uint16_t>(bytes.subspan(1));
return 3; return 3;
} }
if (additional_information == kAdditionalInformation4Bytes) { if (additional_information == kAdditionalInformation4Bytes) {
// 32 bit uint: 1 initial byte + 4 bytes payload. // 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)); *value = ReadBytesMostSignificantByteFirst<uint32_t>(bytes.subspan(1));
return 5; return 5;
} }
if (additional_information == kAdditionalInformation8Bytes) { if (additional_information == kAdditionalInformation8Bytes) {
// 64 bit uint: 1 initial byte + 8 bytes payload. // 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)); *value = ReadBytesMostSignificantByteFirst<uint64_t>(bytes.subspan(1));
return 9; return 9;
} }
...@@ -205,7 +158,6 @@ int8_t ReadTokenStart(span<uint8_t> bytes, MajorType* type, uint64_t* value) { ...@@ -205,7 +158,6 @@ int8_t ReadTokenStart(span<uint8_t> bytes, MajorType* type, uint64_t* value) {
} }
} // namespace cbor_internals } // namespace cbor_internals
using cbor_internals::MajorType;
using cbor_internals::WriteTokenStart; using cbor_internals::WriteTokenStart;
using cbor_internals::ReadTokenStart; using cbor_internals::ReadTokenStart;
...@@ -669,7 +621,8 @@ void CBORTokenizer::ReadNextToken(bool enter_envelope) { ...@@ -669,7 +621,8 @@ void CBORTokenizer::ReadNextToken(bool enter_envelope) {
SetError(Error::CBOR_INVALID_BINARY); SetError(Error::CBOR_INVALID_BINARY);
return; return;
} }
SetToken(CBORTokenTag::BINARY, std::ptrdiff_t(token_byte_length)); SetToken(CBORTokenTag::BINARY,
static_cast<std::ptrdiff_t>(token_byte_length));
return; return;
} }
case kInitialByteForDouble: { // DOUBLE case kInitialByteForDouble: { // DOUBLE
...@@ -696,7 +649,7 @@ void CBORTokenizer::ReadNextToken(bool enter_envelope) { ...@@ -696,7 +649,7 @@ void CBORTokenizer::ReadNextToken(bool enter_envelope) {
// Make sure the payload is contained within the message. // Make sure the payload is contained within the message.
if (token_start_internal_value_ + kEncodedEnvelopeHeaderSize + if (token_start_internal_value_ + kEncodedEnvelopeHeaderSize +
status_.pos > status_.pos >
size_t(bytes_.size())) { static_cast<std::size_t>(bytes_.size())) {
SetError(Error::CBOR_INVALID_ENVELOPE); SetError(Error::CBOR_INVALID_ENVELOPE);
return; return;
} }
...@@ -731,8 +684,8 @@ void CBORTokenizer::ReadNextToken(bool enter_envelope) { ...@@ -731,8 +684,8 @@ void CBORTokenizer::ReadNextToken(bool enter_envelope) {
SetToken(CBORTokenTag::INT32, token_start_length); SetToken(CBORTokenTag::INT32, token_start_length);
return; return;
case MajorType::STRING: { // STRING8. case MajorType::STRING: { // STRING8.
if (!success || if (!success || remainder.size() < static_cast<int64_t>(
remainder.size() < int64_t(token_start_internal_value_)) { token_start_internal_value_)) {
SetError(Error::CBOR_INVALID_STRING8); SetError(Error::CBOR_INVALID_STRING8);
return; return;
} }
...@@ -742,7 +695,8 @@ void CBORTokenizer::ReadNextToken(bool enter_envelope) { ...@@ -742,7 +695,8 @@ void CBORTokenizer::ReadNextToken(bool enter_envelope) {
} }
case MajorType::BYTE_STRING: { // STRING16. case MajorType::BYTE_STRING: { // STRING16.
if (!success || 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. // Must be divisible by 2 since UTF16 is 2 bytes per character.
token_start_internal_value_ & 1) { token_start_internal_value_ & 1) {
SetError(Error::CBOR_INVALID_STRING16); SetError(Error::CBOR_INVALID_STRING16);
...@@ -774,6 +728,75 @@ void CBORTokenizer::SetError(Error error) { ...@@ -774,6 +728,75 @@ void CBORTokenizer::SetError(Error error) {
status_.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 %} {% for namespace in config.protocol.namespace %}
} // namespace {{namespace}} } // namespace {{namespace}}
......
...@@ -135,34 +135,95 @@ class JSONParserHandler { ...@@ -135,34 +135,95 @@ class JSONParserHandler {
// ===== encoding/cbor_internals.h ===== // ===== encoding/cbor_internals.h =====
namespace cbor {
enum class MajorType;
}
namespace cbor_internals { namespace cbor_internals {
// The major types from RFC 7049 Section 2.1.
enum class MajorType {
UNSIGNED = 0,
NEGATIVE = 1,
BYTE_STRING = 2,
STRING = 3,
ARRAY = 4,
MAP = 5,
TAG = 6,
SIMPLE_VALUE = 7
};
// Reads the start of a token with definitive size from |bytes|. // Reads the start of a token with definitive size from |bytes|.
// |type| is the major type as specified in RFC 7049 Section 2.1. // |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 // |value| is the payload (e.g. for MajorType::UNSIGNED) or is the size
// (e.g. for BYTE_STRING). // (e.g. for BYTE_STRING).
// If successful, returns the number of bytes read. Otherwise returns -1. // If successful, returns the number of bytes read. Otherwise returns -1.
int8_t ReadTokenStart(span<uint8_t> bytes, MajorType* type, uint64_t* value); 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, // 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. // or it may be the payload if the value is an unsigned integer.
void WriteTokenStart(MajorType type, uint64_t value, void WriteTokenStart(cbor::MajorType type, uint64_t value,
std::vector<uint8_t>* encoded); std::vector<uint8_t>* encoded);
} // namespace cbor_internals } // namespace cbor_internals
// ===== encoding/cbor.h ===== // ===== encoding/cbor.h =====
namespace cbor {
// The major types from RFC 7049 Section 2.1.
enum class MajorType {
UNSIGNED = 0,
NEGATIVE = 1,
BYTE_STRING = 2,
STRING = 3,
ARRAY = 4,
MAP = 5,
TAG = 6,
SIMPLE_VALUE = 7
};
// 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 (static_cast<uint8_t>(type) << kMajorTypeBitShift) |
(additional_info & kAdditionalInformationMask);
}
// 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 // The binary encoding for the inspector protocol follows the CBOR specification
// (RFC 7049). Additional constraints: // (RFC 7049). Additional constraints:
// - Only indefinite length maps and arrays are supported. // - Only indefinite length maps and arrays are supported.
...@@ -231,7 +292,7 @@ class EnvelopeEncoder { ...@@ -231,7 +292,7 @@ class EnvelopeEncoder {
bool EncodeStop(std::vector<uint8_t>* out); bool EncodeStop(std::vector<uint8_t>* out);
private: 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 // This can be used to convert from JSON to CBOR, by passing the
...@@ -342,10 +403,13 @@ class CBORTokenizer { ...@@ -342,10 +403,13 @@ class CBORTokenizer {
CBORTokenTag token_tag_; CBORTokenTag token_tag_;
struct Status status_; struct Status status_;
std::ptrdiff_t token_byte_length_; std::ptrdiff_t token_byte_length_;
cbor_internals::MajorType token_start_type_; cbor::MajorType token_start_type_;
uint64_t token_start_internal_value_; uint64_t token_start_internal_value_;
}; };
void DumpCBOR(span<uint8_t> cbor);
{% for namespace in config.protocol.namespace %} {% for namespace in config.protocol.namespace %}
} // namespace {{namespace}} } // namespace {{namespace}}
{% endfor %} {% endfor %}
......
...@@ -168,6 +168,7 @@ std::unique_ptr<DictionaryValue> parseMap( ...@@ -168,6 +168,7 @@ std::unique_ptr<DictionaryValue> parseMap(
String key; String key;
if (tokenizer->TokenTag() == CBORTokenTag::STRING8) { if (tokenizer->TokenTag() == CBORTokenTag::STRING8) {
span<uint8_t> key_span = tokenizer->GetString8(); span<uint8_t> key_span = tokenizer->GetString8();
tokenizer->Next();
key = StringUtil::fromUTF8(key_span.data(), key_span.size()); key = StringUtil::fromUTF8(key_span.data(), key_span.size());
} else if (tokenizer->TokenTag() == CBORTokenTag::STRING16) { } else if (tokenizer->TokenTag() == CBORTokenTag::STRING16) {
return nullptr; // STRING16 not supported yet. return nullptr; // STRING16 not supported yet.
...@@ -178,6 +179,7 @@ std::unique_ptr<DictionaryValue> parseMap( ...@@ -178,6 +179,7 @@ std::unique_ptr<DictionaryValue> parseMap(
// Parse value. // Parse value.
auto value = parseValue(stack_depth, tokenizer); auto value = parseValue(stack_depth, tokenizer);
if (!value) return nullptr; if (!value) return nullptr;
dict->setValue(key, std::move(value));
} }
tokenizer->Next(); tokenizer->Next();
return dict; return dict;
......
...@@ -39,7 +39,8 @@ public: ...@@ -39,7 +39,8 @@ public:
TypeBinary, TypeBinary,
TypeObject, TypeObject,
TypeArray, TypeArray,
TypeSerialized TypeSerialized,
TypeImported
}; };
ValueType type() const { return m_type; } ValueType type() const { return m_type; }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/json/json_reader.h" #include "base/json/json_reader.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/values.h" #include "base/values.h"
...@@ -229,6 +230,75 @@ Binary Binary::fromSpan(const uint8_t* data, size_t size) { ...@@ -229,6 +230,75 @@ Binary Binary::fromSpan(const uint8_t* data, size_t size) {
new base::RefCountedBytes(data, 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 %} {% for namespace in config.protocol.namespace %}
} // namespace {{namespace}} } // namespace {{namespace}}
{% endfor %} {% endfor %}
...@@ -134,6 +134,11 @@ class {{config.lib.export_macro}} Binary { ...@@ -134,6 +134,11 @@ class {{config.lib.export_macro}} Binary {
std::unique_ptr<Value> toProtocolValue(const base::Value* value, int depth); std::unique_ptr<Value> toProtocolValue(const base::Value* value, int depth);
std::unique_ptr<base::Value> toBaseValue(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 %} {% for namespace in config.protocol.namespace %}
} // namespace {{namespace}} } // namespace {{namespace}}
{% endfor %} {% endfor %}
......
...@@ -15,6 +15,17 @@ ...@@ -15,6 +15,17 @@
{% for namespace in config.protocol.namespace %} {% for namespace in config.protocol.namespace %}
namespace {{namespace}} { namespace {{namespace}} {
{% endfor %} {% 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 {{domain.domain}} {
namespace API { namespace API {
...@@ -48,11 +59,8 @@ namespace {{param.name | to_title_case}}Enum { ...@@ -48,11 +59,8 @@ namespace {{param.name | to_title_case}}Enum {
{% for type in domain.types %} {% 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 %} {% 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: 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}}> 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); static std::unique_ptr<protocol::{{domain.domain}}::API::{{type.id}}> fromBinary(const uint8_t* data, size_t length);
}; };
......
...@@ -17,6 +17,37 @@ ...@@ -17,6 +17,37 @@
{% for namespace in config.protocol.namespace %} {% for namespace in config.protocol.namespace %}
namespace {{namespace}} { namespace {{namespace}} {
{% endfor %} {% 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 %} {% 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 %} {% 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 ...@@ -29,32 +60,17 @@ struct ValueConversions<{{"::".join(config.imported.namespace)}}::{{domain.domai
return nullptr; return nullptr;
} }
// TODO(pfeldman): toggle to true and delete the json branch when binary is ready. std::vector<uint8_t> binary;
bool binary_protocol = false; value->writeBinary(&binary);
std::unique_ptr<{{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}> result; auto result = {{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}::fromBinary(binary.data(), binary.size());
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"}});
}
if (!result) if (!result)
errors->addError("cannot parse"); errors->addError("cannot parse");
return result; 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. return ImportedValue::fromExported(exported);
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);
}
} }
static std::unique_ptr<protocol::Value> toValue(const std::unique_ptr<{{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}>& value) 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 ...@@ -62,6 +78,7 @@ struct ValueConversions<{{"::".join(config.imported.namespace)}}::{{domain.domai
return toValue(value.get()); return toValue(value.get());
} }
}; };
{% endfor %} {% endfor %}
{% for namespace in config.protocol.namespace %} {% for namespace in config.protocol.namespace %}
......
...@@ -105,9 +105,9 @@ std::unique_ptr<{{type.id}}> {{type.id}}::clone() const ...@@ -105,9 +105,9 @@ std::unique_ptr<{{type.id}}> {{type.id}}::clone() const
return {{config.exported.to_string_out % "json"}}; 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 // static
......
...@@ -106,7 +106,7 @@ public: ...@@ -106,7 +106,7 @@ public:
std::unique_ptr<{{type.id}}> clone() const; std::unique_ptr<{{type.id}}> clone() const;
{% if protocol.is_exported(domain.domain, type.id) %} {% if protocol.is_exported(domain.domain, type.id) %}
{{config.exported.string_out}} toJSONString() const override; {{config.exported.string_out}} toJSONString() const override;
std::vector<uint8_t> toBinary() const override; void writeBinary(std::vector<uint8_t>* out) const override;
{% endif %} {% endif %}
template<int STATE> template<int STATE>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment