#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 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 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 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 chars) override { AddStringToParent(StringUtil::fromUTF8(chars.data(), chars.size())); } void HandleString16(span chars) override { AddStringToParent(StringUtil::fromUTF16(chars.data(), chars.size())); } void HandleBinary(span 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) { 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 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 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 JsonUtil::ParseJSON(const uint8_t* chars, size_t size) { ValueParserHandler handler; crdtp::json::ParseJSON(span(chars, size), &handler); if (handler.status().ok()) return handler.ReleaseRoot(); return nullptr; } std::unique_ptr JsonUtil::ParseJSON(const uint16_t* chars, size_t size) { ValueParserHandler handler; crdtp::json::ParseJSON(span(chars, size), &handler); if (handler.status().ok()) return handler.ReleaseRoot(); return nullptr; } std::unique_ptr JsonUtil::parseJSON(const std::string_view string) { if (string.empty()) return nullptr; return ParseJSON(reinterpret_cast(string.data()), string.size()); } std::unique_ptr 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