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/Core/StreamString.h"
13 #include "lldb/Host/StringConvert.h"
14 #include "llvm/Support/ErrorHandling.h"
17 using namespace lldb_private;
19 std::string JSONString::json_string_quote_metachars(const std::string &s) {
20 if (s.find('"') == std::string::npos)
24 const size_t s_size = s.size();
25 const char *s_chars = s.c_str();
26 for (size_t i = 0; i < s_size; i++) {
27 unsigned char ch = *(s_chars + i);
29 output.push_back('\\');
36 JSONString::JSONString() : JSONValue(JSONValue::Kind::String), m_data() {}
38 JSONString::JSONString(const char *s)
39 : JSONValue(JSONValue::Kind::String), m_data(s ? s : "") {}
41 JSONString::JSONString(const std::string &s)
42 : JSONValue(JSONValue::Kind::String), m_data(s) {}
44 void JSONString::Write(Stream &s) {
45 s.Printf("\"%s\"", json_string_quote_metachars(m_data).c_str());
48 uint64_t JSONNumber::GetAsUnsigned() const {
49 switch (m_data_type) {
50 case DataType::Unsigned:
51 return m_data.m_unsigned;
52 case DataType::Signed:
53 return (uint64_t)m_data.m_signed;
54 case DataType::Double:
55 return (uint64_t)m_data.m_double;
57 llvm_unreachable("Unhandled data type");
60 int64_t JSONNumber::GetAsSigned() const {
61 switch (m_data_type) {
62 case DataType::Unsigned:
63 return (int64_t)m_data.m_unsigned;
64 case DataType::Signed:
65 return m_data.m_signed;
66 case DataType::Double:
67 return (int64_t)m_data.m_double;
69 llvm_unreachable("Unhandled data type");
72 double JSONNumber::GetAsDouble() const {
73 switch (m_data_type) {
74 case DataType::Unsigned:
75 return (double)m_data.m_unsigned;
76 case DataType::Signed:
77 return (double)m_data.m_signed;
78 case DataType::Double:
79 return m_data.m_double;
81 llvm_unreachable("Unhandled data type");
84 void JSONNumber::Write(Stream &s) {
85 switch (m_data_type) {
86 case DataType::Unsigned:
87 s.Printf("%" PRIu64, m_data.m_unsigned);
89 case DataType::Signed:
90 s.Printf("%" PRId64, m_data.m_signed);
92 case DataType::Double:
93 s.Printf("%g", m_data.m_double);
98 JSONTrue::JSONTrue() : JSONValue(JSONValue::Kind::True) {}
100 void JSONTrue::Write(Stream &s) { s.Printf("true"); }
102 JSONFalse::JSONFalse() : JSONValue(JSONValue::Kind::False) {}
104 void JSONFalse::Write(Stream &s) { s.Printf("false"); }
106 JSONNull::JSONNull() : JSONValue(JSONValue::Kind::Null) {}
108 void JSONNull::Write(Stream &s) { s.Printf("null"); }
110 JSONObject::JSONObject() : JSONValue(JSONValue::Kind::Object) {}
112 void JSONObject::Write(Stream &s) {
115 auto iter = m_elements.begin(), end = m_elements.end();
116 for (; iter != end; iter++) {
121 JSONString key(iter->first);
122 JSONValue::SP value(iter->second);
130 bool JSONObject::SetObject(const std::string &key, JSONValue::SP value) {
131 if (key.empty() || nullptr == value.get())
133 m_elements[key] = value;
137 JSONValue::SP JSONObject::GetObject(const std::string &key) {
138 auto iter = m_elements.find(key), end = m_elements.end();
140 return JSONValue::SP();
144 JSONArray::JSONArray() : JSONValue(JSONValue::Kind::Array) {}
146 void JSONArray::Write(Stream &s) {
149 auto iter = m_elements.begin(), end = m_elements.end();
150 for (; iter != end; iter++) {
160 bool JSONArray::SetObject(Index i, JSONValue::SP value) {
161 if (value.get() == nullptr)
163 if (i < m_elements.size()) {
164 m_elements[i] = value;
167 if (i == m_elements.size()) {
168 m_elements.push_back(value);
174 bool JSONArray::AppendObject(JSONValue::SP value) {
175 if (value.get() == nullptr)
177 m_elements.push_back(value);
181 JSONValue::SP JSONArray::GetObject(Index i) {
182 if (i < m_elements.size())
183 return m_elements[i];
184 return JSONValue::SP();
187 JSONArray::Size JSONArray::GetNumElements() { return m_elements.size(); }
189 JSONParser::JSONParser(const char *cstr) : StringExtractor(cstr) {}
191 JSONParser::Token JSONParser::GetToken(std::string &value) {
196 const uint64_t start_index = m_index;
197 const char ch = GetChar();
200 return Token::ObjectStart;
202 return Token::ObjectEnd;
204 return Token::ArrayStart;
206 return Token::ArrayEnd;
212 return Token::EndOfFile;
214 if (GetChar() == 'r')
215 if (GetChar() == 'u')
216 if (GetChar() == 'e')
221 if (GetChar() == 'a')
222 if (GetChar() == 'l')
223 if (GetChar() == 's')
224 if (GetChar() == 'e')
229 if (GetChar() == 'u')
230 if (GetChar() == 'l')
231 if (GetChar() == 'l')
237 bool was_escaped = false;
238 int escaped_ch = GetEscapedChar(was_escaped);
239 if (escaped_ch == -1) {
241 "error: an error occurred getting a character from offset %" PRIu64,
243 value = std::move(error.GetString());
247 const bool is_end_quote = escaped_ch == '"';
248 const bool is_null = escaped_ch == 0;
249 if (was_escaped || (!is_end_quote && !is_null)) {
250 if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX) {
251 value.append(1, (char)escaped_ch);
253 error.Printf("error: wide character support is needed for unicode "
254 "character 0x%4.4x at offset %" PRIu64,
255 escaped_ch, start_index);
256 value = std::move(error.GetString());
259 } else if (is_end_quote) {
260 return Token::String;
261 } else if (is_null) {
262 value = "error: missing end quote for string";
281 bool got_decimal_point = false;
282 uint64_t exp_index = 0;
283 bool got_int_digits = (ch >= '0') && (ch <= '9');
284 bool got_frac_digits = false;
285 bool got_exp_digits = false;
287 const char next_ch = PeekChar();
299 if (exp_index != 0) {
300 got_exp_digits = true;
301 } else if (got_decimal_point) {
302 got_frac_digits = true;
304 got_int_digits = true;
306 ++m_index; // Skip this character
310 if (got_decimal_point) {
311 error.Printf("error: extra decimal point found at offset %" PRIu64,
313 value = std::move(error.GetString());
316 got_decimal_point = true;
317 ++m_index; // Skip this character
323 if (exp_index != 0) {
325 "error: extra exponent character found at offset %" PRIu64,
327 value = std::move(error.GetString());
331 ++m_index; // Skip this character
337 // The '+' and '-' can only come after an exponent character...
338 if (exp_index == m_index - 1) {
339 ++m_index; // Skip the exponent sign character
341 error.Printf("error: unexpected %c character at offset %" PRIu64,
342 next_ch, start_index);
343 value = std::move(error.GetString());
354 if (m_index > start_index) {
355 value = m_packet.substr(start_index, m_index - start_index);
356 if (got_decimal_point) {
357 if (exp_index != 0) {
358 // We have an exponent, make sure we got exponent digits
359 if (got_exp_digits) {
362 error.Printf("error: got exponent character but no exponent digits "
363 "at offset in float value \"%s\"",
365 value = std::move(error.GetString());
369 // No exponent, but we need at least one decimal after the decimal
371 if (got_frac_digits) {
374 error.Printf("error: no digits after decimal point \"%s\"",
376 value = std::move(error.GetString());
382 if (got_int_digits) {
383 // We need at least some integer digits to make an integer
384 return Token::Integer;
386 error.Printf("error: no digits negate sign \"%s\"", value.c_str());
387 value = std::move(error.GetString());
392 error.Printf("error: invalid number found at offset %" PRIu64,
394 value = std::move(error.GetString());
401 error.Printf("error: failed to parse token at offset %" PRIu64
402 " (around character '%c')",
404 value = std::move(error.GetString());
408 int JSONParser::GetEscapedChar(bool &was_escaped) {
410 const char ch = GetChar();
413 const char ch2 = GetChar();
432 const int hi_byte = DecodeHexU8();
433 const int lo_byte = DecodeHexU8();
434 if (hi_byte >= 0 && lo_byte >= 0)
435 return hi_byte << 8 | lo_byte;
444 JSONValue::SP JSONParser::ParseJSONObject() {
445 // The "JSONParser::Token::ObjectStart" token should have already been
447 // by the time this function is called
448 std::unique_ptr<JSONObject> dict_up(new JSONObject());
453 JSONParser::Token token = GetToken(value);
455 if (token == JSONParser::Token::String) {
457 token = GetToken(value);
458 if (token == JSONParser::Token::Colon) {
459 JSONValue::SP value_sp = ParseJSONValue();
461 dict_up->SetObject(key, value_sp);
465 } else if (token == JSONParser::Token::ObjectEnd) {
466 return JSONValue::SP(dict_up.release());
467 } else if (token == JSONParser::Token::Comma) {
473 return JSONValue::SP();
476 JSONValue::SP JSONParser::ParseJSONArray() {
477 // The "JSONParser::Token::ObjectStart" token should have already been
479 // by the time this function is called
480 std::unique_ptr<JSONArray> array_up(new JSONArray());
485 JSONValue::SP value_sp = ParseJSONValue();
487 array_up->AppendObject(value_sp);
491 JSONParser::Token token = GetToken(value);
492 if (token == JSONParser::Token::Comma) {
494 } else if (token == JSONParser::Token::ArrayEnd) {
495 return JSONValue::SP(array_up.release());
500 return JSONValue::SP();
503 JSONValue::SP JSONParser::ParseJSONValue() {
505 const JSONParser::Token token = GetToken(value);
507 case JSONParser::Token::ObjectStart:
508 return ParseJSONObject();
510 case JSONParser::Token::ArrayStart:
511 return ParseJSONArray();
513 case JSONParser::Token::Integer: {
514 if (value.front() == '-') {
515 bool success = false;
516 int64_t sval = StringConvert::ToSInt64(value.c_str(), 0, 0, &success);
518 return JSONValue::SP(new JSONNumber(sval));
520 bool success = false;
521 uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success);
523 return JSONValue::SP(new JSONNumber(uval));
527 case JSONParser::Token::Float: {
528 bool success = false;
529 double val = StringConvert::ToDouble(value.c_str(), 0.0, &success);
531 return JSONValue::SP(new JSONNumber(val));
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();