1 //===--------------------- JSON.cpp -----------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/Utility/JSON.h"
12 #include "lldb/Utility/Stream.h" // for Stream
13 #include "lldb/Utility/StreamString.h"
14 #include "llvm/ADT/StringRef.h"
15 #include "llvm/Support/ErrorHandling.h"
17 #include <inttypes.h> // for PRIu64, PRId64
19 #include <stddef.h> // for size_t
20 #include <utility> // for pair
22 using namespace lldb_private;
24 std::string JSONString::json_string_quote_metachars(const std::string &s) {
25 if (s.find('"') == std::string::npos)
29 const size_t s_size = s.size();
30 const char *s_chars = s.c_str();
31 for (size_t i = 0; i < s_size; i++) {
32 unsigned char ch = *(s_chars + i);
34 output.push_back('\\');
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 (uint64_t)m_data.m_signed;
59 case DataType::Double:
60 return (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 (int64_t)m_data.m_unsigned;
69 case DataType::Signed:
70 return m_data.m_signed;
71 case DataType::Double:
72 return (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 (double)m_data.m_unsigned;
81 case DataType::Signed:
82 return (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, (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
452 // by the time this function is called
453 std::unique_ptr<JSONObject> dict_up(new JSONObject());
458 JSONParser::Token token = GetToken(value);
460 if (token == JSONParser::Token::String) {
462 token = GetToken(value);
463 if (token == JSONParser::Token::Colon) {
464 JSONValue::SP value_sp = ParseJSONValue();
466 dict_up->SetObject(key, value_sp);
470 } else if (token == JSONParser::Token::ObjectEnd) {
471 return JSONValue::SP(dict_up.release());
472 } else if (token == JSONParser::Token::Comma) {
478 return JSONValue::SP();
481 JSONValue::SP JSONParser::ParseJSONArray() {
482 // The "JSONParser::Token::ObjectStart" token should have already been
484 // by the time this function is called
485 std::unique_ptr<JSONArray> array_up(new JSONArray());
490 JSONValue::SP value_sp = ParseJSONValue();
492 array_up->AppendObject(value_sp);
496 JSONParser::Token token = GetToken(value);
497 if (token == JSONParser::Token::Comma) {
499 } else if (token == JSONParser::Token::ArrayEnd) {
500 return JSONValue::SP(array_up.release());
505 return JSONValue::SP();
508 JSONValue::SP JSONParser::ParseJSONValue() {
510 const JSONParser::Token token = GetToken(value);
512 case JSONParser::Token::ObjectStart:
513 return ParseJSONObject();
515 case JSONParser::Token::ArrayStart:
516 return ParseJSONArray();
518 case JSONParser::Token::Integer: {
519 if (value.front() == '-') {
521 if (!llvm::StringRef(value).getAsInteger(0, sval))
522 return JSONValue::SP(new JSONNumber(sval));
525 if (!llvm::StringRef(value).getAsInteger(0, uval))
526 return JSONValue::SP(new JSONNumber(uval));
530 case JSONParser::Token::Float: {
532 if (!llvm::StringRef(value).getAsDouble(D))
533 return JSONValue::SP(new JSONNumber(D));
536 case JSONParser::Token::String:
537 return JSONValue::SP(new JSONString(value));
539 case JSONParser::Token::True:
540 return JSONValue::SP(new JSONTrue());
542 case JSONParser::Token::False:
543 return JSONValue::SP(new JSONFalse());
545 case JSONParser::Token::Null:
546 return JSONValue::SP(new JSONNull());
551 return JSONValue::SP();