1 //===--------------------- JSON.cpp -----------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Utility/JSON.h"
11 #include "lldb/Utility/Stream.h"
12 #include "lldb/Utility/StreamString.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/Support/ErrorHandling.h"
21 using namespace lldb_private;
23 std::string JSONString::json_string_quote_metachars(const std::string &s) {
24 if (s.find_first_of("\\\n\"") == std::string::npos)
28 const size_t s_size = s.size();
29 const char *s_chars = s.c_str();
30 for (size_t i = 0; i < s_size; i++) {
31 unsigned char ch = *(s_chars + i);
32 if (ch == '"' || ch == '\\' || ch == '\n') {
33 output.push_back('\\');
34 if (ch == '\n') ch = 'n';
41 JSONString::JSONString() : JSONValue(JSONValue::Kind::String), m_data() {}
43 JSONString::JSONString(const char *s)
44 : JSONValue(JSONValue::Kind::String), m_data(s ? s : "") {}
46 JSONString::JSONString(const std::string &s)
47 : JSONValue(JSONValue::Kind::String), m_data(s) {}
49 void JSONString::Write(Stream &s) {
50 s.Printf("\"%s\"", json_string_quote_metachars(m_data).c_str());
53 uint64_t JSONNumber::GetAsUnsigned() const {
54 switch (m_data_type) {
55 case DataType::Unsigned:
56 return m_data.m_unsigned;
57 case DataType::Signed:
58 return static_cast<uint64_t>(m_data.m_signed);
59 case DataType::Double:
60 return static_cast<uint64_t>(m_data.m_double);
62 llvm_unreachable("Unhandled data type");
65 int64_t JSONNumber::GetAsSigned() const {
66 switch (m_data_type) {
67 case DataType::Unsigned:
68 return static_cast<int64_t>(m_data.m_unsigned);
69 case DataType::Signed:
70 return m_data.m_signed;
71 case DataType::Double:
72 return static_cast<int64_t>(m_data.m_double);
74 llvm_unreachable("Unhandled data type");
77 double JSONNumber::GetAsDouble() const {
78 switch (m_data_type) {
79 case DataType::Unsigned:
80 return static_cast<double>(m_data.m_unsigned);
81 case DataType::Signed:
82 return static_cast<double>(m_data.m_signed);
83 case DataType::Double:
84 return m_data.m_double;
86 llvm_unreachable("Unhandled data type");
89 void JSONNumber::Write(Stream &s) {
90 switch (m_data_type) {
91 case DataType::Unsigned:
92 s.Printf("%" PRIu64, m_data.m_unsigned);
94 case DataType::Signed:
95 s.Printf("%" PRId64, m_data.m_signed);
97 case DataType::Double:
98 s.Printf("%g", m_data.m_double);
103 JSONTrue::JSONTrue() : JSONValue(JSONValue::Kind::True) {}
105 void JSONTrue::Write(Stream &s) { s.Printf("true"); }
107 JSONFalse::JSONFalse() : JSONValue(JSONValue::Kind::False) {}
109 void JSONFalse::Write(Stream &s) { s.Printf("false"); }
111 JSONNull::JSONNull() : JSONValue(JSONValue::Kind::Null) {}
113 void JSONNull::Write(Stream &s) { s.Printf("null"); }
115 JSONObject::JSONObject() : JSONValue(JSONValue::Kind::Object) {}
117 void JSONObject::Write(Stream &s) {
120 auto iter = m_elements.begin(), end = m_elements.end();
121 for (; iter != end; iter++) {
126 JSONString key(iter->first);
127 JSONValue::SP value(iter->second);
135 bool JSONObject::SetObject(const std::string &key, JSONValue::SP value) {
136 if (key.empty() || nullptr == value.get())
138 m_elements[key] = value;
142 JSONValue::SP JSONObject::GetObject(const std::string &key) {
143 auto iter = m_elements.find(key), end = m_elements.end();
145 return JSONValue::SP();
149 JSONArray::JSONArray() : JSONValue(JSONValue::Kind::Array) {}
151 void JSONArray::Write(Stream &s) {
154 auto iter = m_elements.begin(), end = m_elements.end();
155 for (; iter != end; iter++) {
165 bool JSONArray::SetObject(Index i, JSONValue::SP value) {
166 if (value.get() == nullptr)
168 if (i < m_elements.size()) {
169 m_elements[i] = value;
172 if (i == m_elements.size()) {
173 m_elements.push_back(value);
179 bool JSONArray::AppendObject(JSONValue::SP value) {
180 if (value.get() == nullptr)
182 m_elements.push_back(value);
186 JSONValue::SP JSONArray::GetObject(Index i) {
187 if (i < m_elements.size())
188 return m_elements[i];
189 return JSONValue::SP();
192 JSONArray::Size JSONArray::GetNumElements() { return m_elements.size(); }
194 JSONParser::JSONParser(llvm::StringRef data) : StringExtractor(data) {}
196 JSONParser::Token JSONParser::GetToken(std::string &value) {
201 const uint64_t start_index = m_index;
202 const char ch = GetChar();
205 return Token::ObjectStart;
207 return Token::ObjectEnd;
209 return Token::ArrayStart;
211 return Token::ArrayEnd;
217 return Token::EndOfFile;
219 if (GetChar() == 'r')
220 if (GetChar() == 'u')
221 if (GetChar() == 'e')
226 if (GetChar() == 'a')
227 if (GetChar() == 'l')
228 if (GetChar() == 's')
229 if (GetChar() == 'e')
234 if (GetChar() == 'u')
235 if (GetChar() == 'l')
236 if (GetChar() == 'l')
242 bool was_escaped = false;
243 int escaped_ch = GetEscapedChar(was_escaped);
244 if (escaped_ch == -1) {
246 "error: an error occurred getting a character from offset %" PRIu64,
248 value = std::move(error.GetString());
249 return Token::Status;
252 const bool is_end_quote = escaped_ch == '"';
253 const bool is_null = escaped_ch == 0;
254 if (was_escaped || (!is_end_quote && !is_null)) {
255 if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX) {
256 value.append(1, static_cast<char>(escaped_ch));
258 error.Printf("error: wide character support is needed for unicode "
259 "character 0x%4.4x at offset %" PRIu64,
260 escaped_ch, start_index);
261 value = std::move(error.GetString());
262 return Token::Status;
264 } else if (is_end_quote) {
265 return Token::String;
266 } else if (is_null) {
267 value = "error: missing end quote for string";
268 return Token::Status;
286 bool got_decimal_point = false;
287 uint64_t exp_index = 0;
288 bool got_int_digits = (ch >= '0') && (ch <= '9');
289 bool got_frac_digits = false;
290 bool got_exp_digits = false;
292 const char next_ch = PeekChar();
304 if (exp_index != 0) {
305 got_exp_digits = true;
306 } else if (got_decimal_point) {
307 got_frac_digits = true;
309 got_int_digits = true;
311 ++m_index; // Skip this character
315 if (got_decimal_point) {
316 error.Printf("error: extra decimal point found at offset %" PRIu64,
318 value = std::move(error.GetString());
319 return Token::Status;
321 got_decimal_point = true;
322 ++m_index; // Skip this character
328 if (exp_index != 0) {
330 "error: extra exponent character found at offset %" PRIu64,
332 value = std::move(error.GetString());
333 return Token::Status;
336 ++m_index; // Skip this character
342 // The '+' and '-' can only come after an exponent character...
343 if (exp_index == m_index - 1) {
344 ++m_index; // Skip the exponent sign character
346 error.Printf("error: unexpected %c character at offset %" PRIu64,
347 next_ch, start_index);
348 value = std::move(error.GetString());
349 return Token::Status;
359 if (m_index > start_index) {
360 value = m_packet.substr(start_index, m_index - start_index);
361 if (got_decimal_point) {
362 if (exp_index != 0) {
363 // We have an exponent, make sure we got exponent digits
364 if (got_exp_digits) {
367 error.Printf("error: got exponent character but no exponent digits "
368 "at offset in float value \"%s\"",
370 value = std::move(error.GetString());
371 return Token::Status;
374 // No exponent, but we need at least one decimal after the decimal
376 if (got_frac_digits) {
379 error.Printf("error: no digits after decimal point \"%s\"",
381 value = std::move(error.GetString());
382 return Token::Status;
387 if (got_int_digits) {
388 // We need at least some integer digits to make an integer
389 return Token::Integer;
391 error.Printf("error: no digits negate sign \"%s\"", value.c_str());
392 value = std::move(error.GetString());
393 return Token::Status;
397 error.Printf("error: invalid number found at offset %" PRIu64,
399 value = std::move(error.GetString());
400 return Token::Status;
406 error.Printf("error: failed to parse token at offset %" PRIu64
407 " (around character '%c')",
409 value = std::move(error.GetString());
410 return Token::Status;
413 int JSONParser::GetEscapedChar(bool &was_escaped) {
415 const char ch = GetChar();
418 const char ch2 = GetChar();
437 const int hi_byte = DecodeHexU8();
438 const int lo_byte = DecodeHexU8();
439 if (hi_byte >= 0 && lo_byte >= 0)
440 return hi_byte << 8 | lo_byte;
449 JSONValue::SP JSONParser::ParseJSONObject() {
450 // The "JSONParser::Token::ObjectStart" token should have already been
451 // consumed by the time this function is called
452 std::unique_ptr<JSONObject> dict_up(new JSONObject());
457 JSONParser::Token token = GetToken(value);
459 if (token == JSONParser::Token::String) {
461 token = GetToken(value);
462 if (token == JSONParser::Token::Colon) {
463 JSONValue::SP value_sp = ParseJSONValue();
465 dict_up->SetObject(key, value_sp);
469 } else if (token == JSONParser::Token::ObjectEnd) {
470 return JSONValue::SP(dict_up.release());
471 } else if (token == JSONParser::Token::Comma) {
477 return JSONValue::SP();
480 JSONValue::SP JSONParser::ParseJSONArray() {
481 // The "JSONParser::Token::ObjectStart" token should have already been
482 // consumed by the time this function is called
483 std::unique_ptr<JSONArray> array_up(new JSONArray());
488 JSONValue::SP value_sp = ParseJSONValue();
490 array_up->AppendObject(value_sp);
494 JSONParser::Token token = GetToken(value);
495 if (token == JSONParser::Token::Comma) {
497 } else if (token == JSONParser::Token::ArrayEnd) {
498 return JSONValue::SP(array_up.release());
503 return JSONValue::SP();
506 JSONValue::SP JSONParser::ParseJSONValue() {
508 const JSONParser::Token token = GetToken(value);
510 case JSONParser::Token::ObjectStart:
511 return ParseJSONObject();
513 case JSONParser::Token::ArrayStart:
514 return ParseJSONArray();
516 case JSONParser::Token::Integer: {
517 if (value.front() == '-') {
519 if (!llvm::StringRef(value).getAsInteger(0, sval))
520 return JSONValue::SP(new JSONNumber(sval));
523 if (!llvm::StringRef(value).getAsInteger(0, uval))
524 return JSONValue::SP(new JSONNumber(uval));
528 case JSONParser::Token::Float: {
530 if (!llvm::StringRef(value).getAsDouble(D))
531 return JSONValue::SP(new JSONNumber(D));
534 case JSONParser::Token::String:
535 return JSONValue::SP(new JSONString(value));
537 case JSONParser::Token::True:
538 return JSONValue::SP(new JSONTrue());
540 case JSONParser::Token::False:
541 return JSONValue::SP(new JSONFalse());
543 case JSONParser::Token::Null:
544 return JSONValue::SP(new JSONNull());
549 return JSONValue::SP();