/src/node/src/json_parser.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include "json_parser.h" |
2 | | #include "node_errors.h" |
3 | | #include "node_v8_platform-inl.h" |
4 | | #include "util-inl.h" |
5 | | |
6 | | namespace node { |
7 | | using v8::Array; |
8 | | using v8::Context; |
9 | | using v8::Isolate; |
10 | | using v8::Local; |
11 | | using v8::Object; |
12 | | using v8::String; |
13 | | using v8::Value; |
14 | | |
15 | 0 | JSONParser::JSONParser() {} |
16 | | |
17 | 0 | bool JSONParser::Parse(const std::string& content) { |
18 | 0 | DCHECK(!parsed_); |
19 | |
|
20 | 0 | Isolate* isolate = isolate_.get(); |
21 | 0 | v8::Isolate::Scope isolate_scope(isolate); |
22 | 0 | v8::HandleScope handle_scope(isolate); |
23 | |
|
24 | 0 | Local<Context> context = Context::New(isolate); |
25 | 0 | Context::Scope context_scope(context); |
26 | | |
27 | | // It's not a real script, so don't print the source line. |
28 | 0 | errors::PrinterTryCatch bootstrapCatch( |
29 | 0 | isolate, errors::PrinterTryCatch::kDontPrintSourceLine); |
30 | 0 | Local<Value> json_string_value; |
31 | 0 | Local<Value> result_value; |
32 | 0 | if (!ToV8Value(context, content).ToLocal(&json_string_value) || |
33 | 0 | !json_string_value->IsString() || |
34 | 0 | !v8::JSON::Parse(context, json_string_value.As<String>()) |
35 | 0 | .ToLocal(&result_value) || |
36 | 0 | !result_value->IsObject()) { |
37 | 0 | return false; |
38 | 0 | } |
39 | | |
40 | 0 | context_.Reset(isolate, context); |
41 | 0 | content_.Reset(isolate, result_value.As<Object>()); |
42 | 0 | parsed_ = true; |
43 | |
|
44 | 0 | return true; |
45 | 0 | } |
46 | | |
47 | | std::optional<std::string> JSONParser::GetTopLevelStringField( |
48 | 0 | std::string_view field) { |
49 | 0 | Isolate* isolate = isolate_.get(); |
50 | 0 | v8::Isolate::Scope isolate_scope(isolate); |
51 | 0 | v8::HandleScope handle_scope(isolate); |
52 | |
|
53 | 0 | Local<Context> context = context_.Get(isolate); |
54 | 0 | Context::Scope context_scope(context); |
55 | |
|
56 | 0 | Local<Object> content_object = content_.Get(isolate); |
57 | |
|
58 | 0 | Local<Value> value; |
59 | | // It's not a real script, so don't print the source line. |
60 | 0 | errors::PrinterTryCatch bootstrapCatch( |
61 | 0 | isolate, errors::PrinterTryCatch::kDontPrintSourceLine); |
62 | 0 | Local<Value> field_local; |
63 | 0 | if (!ToV8Value(context, field, isolate).ToLocal(&field_local)) { |
64 | 0 | return {}; |
65 | 0 | } |
66 | 0 | if (!content_object->Get(context, field_local).ToLocal(&value) || |
67 | 0 | !value->IsString()) { |
68 | 0 | return {}; |
69 | 0 | } |
70 | 0 | Utf8Value utf8_value(isolate, value); |
71 | 0 | return utf8_value.ToString(); |
72 | 0 | } |
73 | | |
74 | 0 | std::optional<bool> JSONParser::GetTopLevelBoolField(std::string_view field) { |
75 | 0 | Isolate* isolate = isolate_.get(); |
76 | 0 | v8::Isolate::Scope isolate_scope(isolate); |
77 | 0 | v8::HandleScope handle_scope(isolate); |
78 | |
|
79 | 0 | Local<Context> context = context_.Get(isolate); |
80 | 0 | Context::Scope context_scope(context); |
81 | |
|
82 | 0 | Local<Object> content_object = content_.Get(isolate); |
83 | 0 | Local<Value> value; |
84 | 0 | bool has_field; |
85 | | // It's not a real script, so don't print the source line. |
86 | 0 | errors::PrinterTryCatch bootstrapCatch( |
87 | 0 | isolate, errors::PrinterTryCatch::kDontPrintSourceLine); |
88 | 0 | Local<Value> field_local; |
89 | 0 | if (!ToV8Value(context, field, isolate).ToLocal(&field_local)) { |
90 | 0 | return {}; |
91 | 0 | } |
92 | 0 | if (!content_object->Has(context, field_local).To(&has_field)) { |
93 | 0 | return {}; |
94 | 0 | } |
95 | 0 | if (!has_field) { |
96 | 0 | return false; |
97 | 0 | } |
98 | 0 | if (!content_object->Get(context, field_local).ToLocal(&value) || |
99 | 0 | !value->IsBoolean()) { |
100 | 0 | return {}; |
101 | 0 | } |
102 | 0 | return value->BooleanValue(isolate); |
103 | 0 | } |
104 | | |
105 | | std::optional<JSONParser::StringDict> JSONParser::GetTopLevelStringDict( |
106 | 0 | std::string_view field) { |
107 | 0 | Isolate* isolate = isolate_.get(); |
108 | 0 | v8::HandleScope handle_scope(isolate); |
109 | 0 | Local<Context> context = context_.Get(isolate); |
110 | 0 | Local<Object> content_object = content_.Get(isolate); |
111 | 0 | Local<Value> value; |
112 | 0 | bool has_field; |
113 | | // It's not a real script, so don't print the source line. |
114 | 0 | errors::PrinterTryCatch bootstrapCatch( |
115 | 0 | isolate, errors::PrinterTryCatch::kDontPrintSourceLine); |
116 | 0 | Local<Value> field_local; |
117 | 0 | if (!ToV8Value(context, field, isolate).ToLocal(&field_local)) { |
118 | 0 | return std::nullopt; |
119 | 0 | } |
120 | 0 | if (!content_object->Has(context, field_local).To(&has_field)) { |
121 | 0 | return std::nullopt; |
122 | 0 | } |
123 | 0 | if (!has_field) { |
124 | 0 | return StringDict(); |
125 | 0 | } |
126 | 0 | if (!content_object->Get(context, field_local).ToLocal(&value) || |
127 | 0 | !value->IsObject()) { |
128 | 0 | return std::nullopt; |
129 | 0 | } |
130 | 0 | Local<Object> dict = value.As<Object>(); |
131 | 0 | Local<Array> keys; |
132 | 0 | if (!dict->GetOwnPropertyNames(context).ToLocal(&keys)) { |
133 | 0 | return std::nullopt; |
134 | 0 | } |
135 | 0 | std::unordered_map<std::string, std::string> result; |
136 | 0 | uint32_t length = keys->Length(); |
137 | 0 | for (uint32_t i = 0; i < length; ++i) { |
138 | 0 | Local<Value> key; |
139 | 0 | Local<Value> value; |
140 | 0 | if (!keys->Get(context, i).ToLocal(&key) || !key->IsString()) |
141 | 0 | return StringDict(); |
142 | 0 | if (!dict->Get(context, key).ToLocal(&value) || !value->IsString()) |
143 | 0 | return StringDict(); |
144 | | |
145 | 0 | Utf8Value key_utf8(isolate, key); |
146 | 0 | Utf8Value value_utf8(isolate, value); |
147 | 0 | result.emplace(*key_utf8, *value_utf8); |
148 | 0 | } |
149 | 0 | return result; |
150 | 0 | } |
151 | | |
152 | | } // namespace node |