blob: d8aacbdf1a8fc858c792ad3ce17ca2f46baebe7e [file] [log] [blame] [edit]
#include "node_json.h"
#include "crdtp/json.h"
namespace node {
namespace inspector {
using crdtp::ParserHandler;
using crdtp::span;
using crdtp::Status;
using protocol::Binary;
using protocol::BinaryValue;
using protocol::DictionaryValue;
using protocol::FundamentalValue;
using protocol::ListValue;
using protocol::String;
using protocol::StringUtil;
using protocol::StringValue;
using protocol::Value;
namespace {
// Uses the parsing events received from driver of `ParserHandler`
// (e.g. crdtp::json::ParseJSON) 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::fromUTF16(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 {
explicit ContainerState(DictionaryValue* dict)
: is_dict(true), dict(dict) {}
explicit 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
std::unique_ptr<Value> JsonUtil::ParseJSON(const uint8_t* chars, size_t size) {
ValueParserHandler handler;
crdtp::json::ParseJSON(span<uint8_t>(chars, size), &handler);
if (handler.status().ok()) return handler.ReleaseRoot();
return nullptr;
}
std::unique_ptr<Value> JsonUtil::ParseJSON(const uint16_t* chars, size_t size) {
ValueParserHandler handler;
crdtp::json::ParseJSON(span<uint16_t>(chars, size), &handler);
if (handler.status().ok()) return handler.ReleaseRoot();
return nullptr;
}
std::unique_ptr<Value> JsonUtil::parseJSON(const std::string_view string) {
if (string.empty()) return nullptr;
return ParseJSON(reinterpret_cast<const uint8_t*>(string.data()),
string.size());
}
std::unique_ptr<Value> JsonUtil::parseJSON(v8_inspector::StringView string) {
if (string.length() == 0) return nullptr;
if (string.is8Bit()) return ParseJSON(string.characters8(), string.length());
return ParseJSON(string.characters16(), string.length());
}
} // namespace inspector
} // namespace node