-
Notifications
You must be signed in to change notification settings - Fork 31.1k
/
Copy pathnode_json.cc
190 lines (159 loc) Β· 5.71 KB
/
node_json.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#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