1 //===--------------------- JSON.cpp -----------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "JSON.h"
10
11 // C includes
12 #include <assert.h>
13 #include <limits.h>
14
15 // C++ includes
16 #include "lldb/Host/StringConvert.h"
17 #include <iomanip>
18 #include <sstream>
19
20 using namespace lldb_private;
21
json_string_quote_metachars(const std::string & s)22 std::string JSONString::json_string_quote_metachars(const std::string &s) {
23 if (s.find('"') == std::string::npos)
24 return s;
25
26 std::string output;
27 const size_t s_size = s.size();
28 const char *s_chars = s.c_str();
29 for (size_t i = 0; i < s_size; i++) {
30 unsigned char ch = *(s_chars + i);
31 if (ch == '"') {
32 output.push_back('\\');
33 }
34 output.push_back(ch);
35 }
36 return output;
37 }
38
JSONString()39 JSONString::JSONString() : JSONValue(JSONValue::Kind::String), m_data() {}
40
JSONString(const char * s)41 JSONString::JSONString(const char *s)
42 : JSONValue(JSONValue::Kind::String), m_data(s ? s : "") {}
43
JSONString(const std::string & s)44 JSONString::JSONString(const std::string &s)
45 : JSONValue(JSONValue::Kind::String), m_data(s) {}
46
Write(std::ostream & s)47 void JSONString::Write(std::ostream &s) {
48 s << "\"" << json_string_quote_metachars(m_data).c_str() << "\"";
49 }
50
GetAsUnsigned() const51 uint64_t JSONNumber::GetAsUnsigned() const {
52 switch (m_data_type) {
53 case DataType::Unsigned:
54 return m_data.m_unsigned;
55 case DataType::Signed:
56 return (uint64_t)m_data.m_signed;
57 case DataType::Double:
58 return (uint64_t)m_data.m_double;
59 }
60 }
61
GetAsSigned() const62 int64_t JSONNumber::GetAsSigned() const {
63 switch (m_data_type) {
64 case DataType::Unsigned:
65 return (int64_t)m_data.m_unsigned;
66 case DataType::Signed:
67 return m_data.m_signed;
68 case DataType::Double:
69 return (int64_t)m_data.m_double;
70 }
71 }
72
GetAsDouble() const73 double JSONNumber::GetAsDouble() const {
74 switch (m_data_type) {
75 case DataType::Unsigned:
76 return (double)m_data.m_unsigned;
77 case DataType::Signed:
78 return (double)m_data.m_signed;
79 case DataType::Double:
80 return m_data.m_double;
81 }
82 }
83
Write(std::ostream & s)84 void JSONNumber::Write(std::ostream &s) {
85 switch (m_data_type) {
86 case DataType::Unsigned:
87 s << m_data.m_unsigned;
88 break;
89 case DataType::Signed:
90 s << m_data.m_signed;
91 break;
92 case DataType::Double:
93 // Set max precision to emulate %g.
94 s << std::setprecision(std::numeric_limits<double>::digits10 + 1);
95 s << m_data.m_double;
96 break;
97 }
98 }
99
JSONTrue()100 JSONTrue::JSONTrue() : JSONValue(JSONValue::Kind::True) {}
101
Write(std::ostream & s)102 void JSONTrue::Write(std::ostream &s) { s << "true"; }
103
JSONFalse()104 JSONFalse::JSONFalse() : JSONValue(JSONValue::Kind::False) {}
105
Write(std::ostream & s)106 void JSONFalse::Write(std::ostream &s) { s << "false"; }
107
JSONNull()108 JSONNull::JSONNull() : JSONValue(JSONValue::Kind::Null) {}
109
Write(std::ostream & s)110 void JSONNull::Write(std::ostream &s) { s << "null"; }
111
JSONObject()112 JSONObject::JSONObject() : JSONValue(JSONValue::Kind::Object) {}
113
Write(std::ostream & s)114 void JSONObject::Write(std::ostream &s) {
115 bool first = true;
116 s << '{';
117 auto iter = m_elements.begin(), end = m_elements.end();
118 for (; iter != end; iter++) {
119 if (first)
120 first = false;
121 else
122 s << ',';
123 JSONString key(iter->first);
124 JSONValue::SP value(iter->second);
125 key.Write(s);
126 s << ':';
127 value->Write(s);
128 }
129 s << '}';
130 }
131
SetObject(const std::string & key,JSONValue::SP value)132 bool JSONObject::SetObject(const std::string &key, JSONValue::SP value) {
133 if (key.empty() || nullptr == value.get())
134 return false;
135 m_elements[key] = value;
136 return true;
137 }
138
GetObject(const std::string & key) const139 JSONValue::SP JSONObject::GetObject(const std::string &key) const {
140 auto iter = m_elements.find(key), end = m_elements.end();
141 if (iter == end)
142 return JSONValue::SP();
143 return iter->second;
144 }
145
GetObjectAsBool(const std::string & key,bool & value) const146 bool JSONObject::GetObjectAsBool(const std::string &key, bool &value) const {
147 auto value_sp = GetObject(key);
148 if (!value_sp) {
149 // The given key doesn't exist, so we have no value.
150 return false;
151 }
152
153 if (JSONTrue::classof(value_sp.get())) {
154 // We have the value, and it is true.
155 value = true;
156 return true;
157 } else if (JSONFalse::classof(value_sp.get())) {
158 // We have the value, and it is false.
159 value = false;
160 return true;
161 } else {
162 // We don't have a valid bool value for the given key.
163 return false;
164 }
165 }
166
GetObjectAsString(const std::string & key,std::string & value) const167 bool JSONObject::GetObjectAsString(const std::string &key,
168 std::string &value) const {
169 auto value_sp = GetObject(key);
170 if (!value_sp) {
171 // The given key doesn't exist, so we have no value.
172 return false;
173 }
174
175 if (!JSONString::classof(value_sp.get()))
176 return false;
177
178 value = static_cast<JSONString *>(value_sp.get())->GetData();
179 return true;
180 }
181
JSONArray()182 JSONArray::JSONArray() : JSONValue(JSONValue::Kind::Array) {}
183
Write(std::ostream & s)184 void JSONArray::Write(std::ostream &s) {
185 bool first = true;
186 s << '[';
187 auto iter = m_elements.begin(), end = m_elements.end();
188 for (; iter != end; iter++) {
189 if (first)
190 first = false;
191 else
192 s << ',';
193 (*iter)->Write(s);
194 }
195 s << ']';
196 }
197
SetObject(Index i,JSONValue::SP value)198 bool JSONArray::SetObject(Index i, JSONValue::SP value) {
199 if (value.get() == nullptr)
200 return false;
201 if (i < m_elements.size()) {
202 m_elements[i] = value;
203 return true;
204 }
205 if (i == m_elements.size()) {
206 m_elements.push_back(value);
207 return true;
208 }
209 return false;
210 }
211
AppendObject(JSONValue::SP value)212 bool JSONArray::AppendObject(JSONValue::SP value) {
213 if (value.get() == nullptr)
214 return false;
215 m_elements.push_back(value);
216 return true;
217 }
218
GetObject(Index i)219 JSONValue::SP JSONArray::GetObject(Index i) {
220 if (i < m_elements.size())
221 return m_elements[i];
222 return JSONValue::SP();
223 }
224
GetNumElements()225 JSONArray::Size JSONArray::GetNumElements() { return m_elements.size(); }
226
JSONParser(const char * cstr)227 JSONParser::JSONParser(const char *cstr) : StdStringExtractor(cstr) {}
228
GetToken(std::string & value)229 JSONParser::Token JSONParser::GetToken(std::string &value) {
230 std::ostringstream error;
231
232 value.clear();
233 SkipSpaces();
234 const uint64_t start_index = m_index;
235 const char ch = GetChar();
236 switch (ch) {
237 case '{':
238 return Token::ObjectStart;
239 case '}':
240 return Token::ObjectEnd;
241 case '[':
242 return Token::ArrayStart;
243 case ']':
244 return Token::ArrayEnd;
245 case ',':
246 return Token::Comma;
247 case ':':
248 return Token::Colon;
249 case '\0':
250 return Token::EndOfFile;
251 case 't':
252 if (GetChar() == 'r')
253 if (GetChar() == 'u')
254 if (GetChar() == 'e')
255 return Token::True;
256 break;
257
258 case 'f':
259 if (GetChar() == 'a')
260 if (GetChar() == 'l')
261 if (GetChar() == 's')
262 if (GetChar() == 'e')
263 return Token::False;
264 break;
265
266 case 'n':
267 if (GetChar() == 'u')
268 if (GetChar() == 'l')
269 if (GetChar() == 'l')
270 return Token::Null;
271 break;
272
273 case '"': {
274 while (true) {
275 bool was_escaped = false;
276 int escaped_ch = GetEscapedChar(was_escaped);
277 if (escaped_ch == -1) {
278 error << "error: an error occurred getting a character from offset "
279 << start_index;
280 value = error.str();
281 return Token::Status;
282
283 } else {
284 const bool is_end_quote = escaped_ch == '"';
285 const bool is_null = escaped_ch == 0;
286 if (was_escaped || (!is_end_quote && !is_null)) {
287 if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX) {
288 value.append(1, (char)escaped_ch);
289 } else {
290 error << "error: wide character support is needed for unicode "
291 "character 0x"
292 << std::setprecision(4) << std::hex << escaped_ch;
293 error << " at offset " << start_index;
294 value = error.str();
295 return Token::Status;
296 }
297 } else if (is_end_quote) {
298 return Token::String;
299 } else if (is_null) {
300 value = "error: missing end quote for string";
301 return Token::Status;
302 }
303 }
304 }
305 } break;
306
307 case '-':
308 case '0':
309 case '1':
310 case '2':
311 case '3':
312 case '4':
313 case '5':
314 case '6':
315 case '7':
316 case '8':
317 case '9': {
318 bool done = false;
319 bool got_decimal_point = false;
320 uint64_t exp_index = 0;
321 bool got_int_digits = (ch >= '0') && (ch <= '9');
322 bool got_frac_digits = false;
323 bool got_exp_digits = false;
324 while (!done) {
325 const char next_ch = PeekChar();
326 switch (next_ch) {
327 case '0':
328 case '1':
329 case '2':
330 case '3':
331 case '4':
332 case '5':
333 case '6':
334 case '7':
335 case '8':
336 case '9':
337 if (exp_index != 0) {
338 got_exp_digits = true;
339 } else if (got_decimal_point) {
340 got_frac_digits = true;
341 } else {
342 got_int_digits = true;
343 }
344 ++m_index; // Skip this character
345 break;
346
347 case '.':
348 if (got_decimal_point) {
349 error << "error: extra decimal point found at offset " << start_index;
350 value = error.str();
351 return Token::Status;
352 } else {
353 got_decimal_point = true;
354 ++m_index; // Skip this character
355 }
356 break;
357
358 case 'e':
359 case 'E':
360 if (exp_index != 0) {
361 error << "error: extra exponent character found at offset "
362 << start_index;
363 value = error.str();
364 return Token::Status;
365 } else {
366 exp_index = m_index;
367 ++m_index; // Skip this character
368 }
369 break;
370
371 case '+':
372 case '-':
373 // The '+' and '-' can only come after an exponent character...
374 if (exp_index == m_index - 1) {
375 ++m_index; // Skip the exponent sign character
376 } else {
377 error << "error: unexpected " << next_ch << " character at offset "
378 << start_index;
379 value = error.str();
380 return Token::Status;
381 }
382 break;
383
384 default:
385 done = true;
386 break;
387 }
388 }
389
390 if (m_index > start_index) {
391 value = m_packet.substr(start_index, m_index - start_index);
392 if (got_decimal_point) {
393 if (exp_index != 0) {
394 // We have an exponent, make sure we got exponent digits
395 if (got_exp_digits) {
396 return Token::Float;
397 } else {
398 error << "error: got exponent character but no exponent digits at "
399 "offset in float value \""
400 << value.c_str() << "\"";
401 value = error.str();
402 return Token::Status;
403 }
404 } else {
405 // No exponent, but we need at least one decimal after the decimal
406 // point
407 if (got_frac_digits) {
408 return Token::Float;
409 } else {
410 error << "error: no digits after decimal point \"" << value.c_str()
411 << "\"";
412 value = error.str();
413 return Token::Status;
414 }
415 }
416 } else {
417 // No decimal point
418 if (got_int_digits) {
419 // We need at least some integer digits to make an integer
420 return Token::Integer;
421 } else {
422 error << "error: no digits negate sign \"" << value.c_str() << "\"";
423 value = error.str();
424 return Token::Status;
425 }
426 }
427 } else {
428 error << "error: invalid number found at offset " << start_index;
429 value = error.str();
430 return Token::Status;
431 }
432 } break;
433 default:
434 break;
435 }
436 error << "error: failed to parse token at offset " << start_index
437 << " (around character '" << ch << "')";
438 value = error.str();
439 return Token::Status;
440 }
441
GetEscapedChar(bool & was_escaped)442 int JSONParser::GetEscapedChar(bool &was_escaped) {
443 was_escaped = false;
444 const char ch = GetChar();
445 if (ch == '\\') {
446 was_escaped = true;
447 const char ch2 = GetChar();
448 switch (ch2) {
449 case '"':
450 case '\\':
451 case '/':
452 default:
453 break;
454
455 case 'b':
456 return '\b';
457 case 'f':
458 return '\f';
459 case 'n':
460 return '\n';
461 case 'r':
462 return '\r';
463 case 't':
464 return '\t';
465 case 'u': {
466 const int hi_byte = DecodeHexU8();
467 const int lo_byte = DecodeHexU8();
468 if (hi_byte >= 0 && lo_byte >= 0)
469 return hi_byte << 8 | lo_byte;
470 return -1;
471 } break;
472 }
473 return ch2;
474 }
475 return ch;
476 }
477
ParseJSONObject()478 JSONValue::SP JSONParser::ParseJSONObject() {
479 // The "JSONParser::Token::ObjectStart" token should have already been
480 // consumed
481 // by the time this function is called
482 std::unique_ptr<JSONObject> dict_up(new JSONObject());
483
484 std::string value;
485 std::string key;
486 while (true) {
487 JSONParser::Token token = GetToken(value);
488
489 if (token == JSONParser::Token::String) {
490 key.swap(value);
491 token = GetToken(value);
492 if (token == JSONParser::Token::Colon) {
493 JSONValue::SP value_sp = ParseJSONValue();
494 if (value_sp)
495 dict_up->SetObject(key, value_sp);
496 else
497 break;
498 }
499 } else if (token == JSONParser::Token::ObjectEnd) {
500 return JSONValue::SP(dict_up.release());
501 } else if (token == JSONParser::Token::Comma) {
502 continue;
503 } else {
504 break;
505 }
506 }
507 return JSONValue::SP();
508 }
509
ParseJSONArray()510 JSONValue::SP JSONParser::ParseJSONArray() {
511 // The "JSONParser::Token::ObjectStart" token should have already been
512 // consumed
513 // by the time this function is called
514 std::unique_ptr<JSONArray> array_up(new JSONArray());
515
516 std::string value;
517 std::string key;
518 while (true) {
519 JSONParser::Token token = GetToken(value);
520 if (token == JSONParser::Token::ArrayEnd)
521 return JSONValue::SP(array_up.release());
522 JSONValue::SP value_sp = ParseJSONValue(value, token);
523 if (value_sp)
524 array_up->AppendObject(value_sp);
525 else
526 break;
527
528 token = GetToken(value);
529 if (token == JSONParser::Token::Comma) {
530 continue;
531 } else if (token == JSONParser::Token::ArrayEnd) {
532 return JSONValue::SP(array_up.release());
533 } else {
534 break;
535 }
536 }
537 return JSONValue::SP();
538 }
539
ParseJSONValue()540 JSONValue::SP JSONParser::ParseJSONValue() {
541 std::string value;
542 const JSONParser::Token token = GetToken(value);
543 return ParseJSONValue(value, token);
544 }
545
ParseJSONValue(const std::string & value,const Token & token)546 JSONValue::SP JSONParser::ParseJSONValue(const std::string &value,
547 const Token &token) {
548 switch (token) {
549 case JSONParser::Token::ObjectStart:
550 return ParseJSONObject();
551
552 case JSONParser::Token::ArrayStart:
553 return ParseJSONArray();
554
555 case JSONParser::Token::Integer: {
556 if (value.front() == '-') {
557 bool success = false;
558 int64_t sval = StringConvert::ToSInt64(value.c_str(), 0, 0, &success);
559 if (success)
560 return JSONValue::SP(new JSONNumber(sval));
561 } else {
562 bool success = false;
563 uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success);
564 if (success)
565 return JSONValue::SP(new JSONNumber(uval));
566 }
567 } break;
568
569 case JSONParser::Token::Float: {
570 bool success = false;
571 double val = StringConvert::ToDouble(value.c_str(), 0.0, &success);
572 if (success)
573 return JSONValue::SP(new JSONNumber(val));
574 } break;
575
576 case JSONParser::Token::String:
577 return JSONValue::SP(new JSONString(value));
578
579 case JSONParser::Token::True:
580 return JSONValue::SP(new JSONTrue());
581
582 case JSONParser::Token::False:
583 return JSONValue::SP(new JSONFalse());
584
585 case JSONParser::Token::Null:
586 return JSONValue::SP(new JSONNull());
587
588 default:
589 break;
590 }
591 return JSONValue::SP();
592 }
593