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_first_of("\\\n\"") == 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);
33 if (ch == '"' || ch == '\\' || ch == '\n') {
34 output.push_back('\\');
35 if (ch == '\n') ch = 'n';
42 JSONString::JSONString() : JSONValue(JSONValue::Kind::String), m_data() {}
44 JSONString::JSONString(const char *s)
45 : JSONValue(JSONValue::Kind::String), m_data(s ? s : "") {}
47 JSONString::JSONString(const std::string &s)
48 : JSONValue(JSONValue::Kind::String), m_data(s) {}
50 void JSONString::Write(Stream &s) {
51 s.Printf("\"%s\"", json_string_quote_metachars(m_data).c_str());
54 uint64_t JSONNumber::GetAsUnsigned() const {
55 switch (m_data_type) {
56 case DataType::Unsigned:
57 return m_data.m_unsigned;
58 case DataType::Signed:
59 return (uint64_t)m_data.m_signed;
60 case DataType::Double:
61 return (uint64_t)m_data.m_double;
63 llvm_unreachable("Unhandled data type");
66 int64_t JSONNumber::GetAsSigned() const {
67 switch (m_data_type) {
68 case DataType::Unsigned:
69 return (int64_t)m_data.m_unsigned;
70 case DataType::Signed:
71 return m_data.m_signed;
72 case DataType::Double:
73 return (int64_t)m_data.m_double;
75 llvm_unreachable("Unhandled data type");
78 double JSONNumber::GetAsDouble() const {
79 switch (m_data_type) {
80 case DataType::Unsigned:
81 return (double)m_data.m_unsigned;
82 case DataType::Signed:
83 return (double)m_data.m_signed;
84 case DataType::Double:
85 return m_data.m_double;
87 llvm_unreachable("Unhandled data type");
90 void JSONNumber::Write(Stream &s) {
91 switch (m_data_type) {
92 case DataType::Unsigned:
93 s.Printf("%" PRIu64, m_data.m_unsigned);
95 case DataType::Signed:
96 s.Printf("%" PRId64, m_data.m_signed);
98 case DataType::Double:
99 s.Printf("%g", m_data.m_double);
104 JSONTrue::JSONTrue() : JSONValue(JSONValue::Kind::True) {}
106 void JSONTrue::Write(Stream &s) { s.Printf("true"); }
108 JSONFalse::JSONFalse() : JSONValue(JSONValue::Kind::False) {}
110 void JSONFalse::Write(Stream &s) { s.Printf("false"); }
112 JSONNull::JSONNull() : JSONValue(JSONValue::Kind::Null) {}
114 void JSONNull::Write(Stream &s) { s.Printf("null"); }
116 JSONObject::JSONObject() : JSONValue(JSONValue::Kind::Object) {}
118 void JSONObject::Write(Stream &s) {
121 auto iter = m_elements.begin(), end = m_elements.end();
122 for (; iter != end; iter++) {
127 JSONString key(iter->first);
128 JSONValue::SP value(iter->second);
136 bool JSONObject::SetObject(const std::string &key, JSONValue::SP value) {
137 if (key.empty() || nullptr == value.get())
139 m_elements[key] = value;
143 JSONValue::SP JSONObject::GetObject(const std::string &key) {
144 auto iter = m_elements.find(key), end = m_elements.end();
146 return JSONValue::SP();
150 JSONArray::JSONArray() : JSONValue(JSONValue::Kind::Array) {}
152 void JSONArray::Write(Stream &s) {
155 auto iter = m_elements.begin(), end = m_elements.end();
156 for (; iter != end; iter++) {
166 bool JSONArray::SetObject(Index i, JSONValue::SP value) {
167 if (value.get() == nullptr)
169 if (i < m_elements.size()) {
170 m_elements[i] = value;
173 if (i == m_elements.size()) {
174 m_elements.push_back(value);
180 bool JSONArray::AppendObject(JSONValue::SP value) {
181 if (value.get() == nullptr)
183 m_elements.push_back(value);
187 JSONValue::SP JSONArray::GetObject(Index i) {
188 if (i < m_elements.size())
189 return m_elements[i];
190 return JSONValue::SP();
193 JSONArray::Size JSONArray::GetNumElements() { return m_elements.size(); }
195 JSONParser::JSONParser(llvm::StringRef data) : StringExtractor(data) {}
197 JSONParser::Token JSONParser::GetToken(std::string &value) {
202 const uint64_t start_index = m_index;
203 const char ch = GetChar();
206 return Token::ObjectStart;
208 return Token::ObjectEnd;
210 return Token::ArrayStart;
212 return Token::ArrayEnd;
218 return Token::EndOfFile;
220 if (GetChar() == 'r')
221 if (GetChar() == 'u')
222 if (GetChar() == 'e')
227 if (GetChar() == 'a')
228 if (GetChar() == 'l')
229 if (GetChar() == 's')
230 if (GetChar() == 'e')
235 if (GetChar() == 'u')
236 if (GetChar() == 'l')
237 if (GetChar() == 'l')
243 bool was_escaped = false;
244 int escaped_ch = GetEscapedChar(was_escaped);
245 if (escaped_ch == -1) {
247 "error: an error occurred getting a character from offset %" PRIu64,
249 value = std::move(error.GetString());
250 return Token::Status;
253 const bool is_end_quote = escaped_ch == '"';
254 const bool is_null = escaped_ch == 0;
255 if (was_escaped || (!is_end_quote && !is_null)) {
256 if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX) {
257 value.append(1, (char)escaped_ch);
259 error.Printf("error: wide character support is needed for unicode "
260 "character 0x%4.4x at offset %" PRIu64,
261 escaped_ch, start_index);
262 value = std::move(error.GetString());
263 return Token::Status;
265 } else if (is_end_quote) {
266 return Token::String;
267 } else if (is_null) {
268 value = "error: missing end quote for string";
269 return Token::Status;
287 bool got_decimal_point = false;
288 uint64_t exp_index = 0;
289 bool got_int_digits = (ch >= '0') && (ch <= '9');
290 bool got_frac_digits = false;
291 bool got_exp_digits = false;
293 const char next_ch = PeekChar();
305 if (exp_index != 0) {
306 got_exp_digits = true;
307 } else if (got_decimal_point) {
308 got_frac_digits = true;
310 got_int_digits = true;
312 ++m_index; // Skip this character
316 if (got_decimal_point) {
317 error.Printf("error: extra decimal point found at offset %" PRIu64,
319 value = std::move(error.GetString());
320 return Token::Status;
322 got_decimal_point = true;
323 ++m_index; // Skip this character
329 if (exp_index != 0) {
331 "error: extra exponent character found at offset %" PRIu64,
333 value = std::move(error.GetString());
334 return Token::Status;
337 ++m_index; // Skip this character
343 // The '+' and '-' can only come after an exponent character...
344 if (exp_index == m_index - 1) {
345 ++m_index; // Skip the exponent sign character
347 error.Printf("error: unexpected %c character at offset %" PRIu64,
348 next_ch, start_index);
349 value = std::move(error.GetString());
350 return Token::Status;
360 if (m_index > start_index) {
361 value = m_packet.substr(start_index, m_index - start_index);
362 if (got_decimal_point) {
363 if (exp_index != 0) {
364 // We have an exponent, make sure we got exponent digits
365 if (got_exp_digits) {
368 error.Printf("error: got exponent character but no exponent digits "
369 "at offset in float value \"%s\"",
371 value = std::move(error.GetString());
372 return Token::Status;
375 // No exponent, but we need at least one decimal after the decimal
377 if (got_frac_digits) {
380 error.Printf("error: no digits after decimal point \"%s\"",
382 value = std::move(error.GetString());
383 return Token::Status;
388 if (got_int_digits) {
389 // We need at least some integer digits to make an integer
390 return Token::Integer;
392 error.Printf("error: no digits negate sign \"%s\"", value.c_str());
393 value = std::move(error.GetString());
394 return Token::Status;
398 error.Printf("error: invalid number found at offset %" PRIu64,
400 value = std::move(error.GetString());
401 return Token::Status;
407 error.Printf("error: failed to parse token at offset %" PRIu64
408 " (around character '%c')",
410 value = std::move(error.GetString());
411 return Token::Status;
414 int JSONParser::GetEscapedChar(bool &was_escaped) {
416 const char ch = GetChar();
419 const char ch2 = GetChar();
438 const int hi_byte = DecodeHexU8();
439 const int lo_byte = DecodeHexU8();
440 if (hi_byte >= 0 && lo_byte >= 0)
441 return hi_byte << 8 | lo_byte;
450 JSONValue::SP JSONParser::ParseJSONObject() {
451 // The "JSONParser::Token::ObjectStart" token should have already been
452 // consumed 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
483 // consumed by the time this function is called
484 std::unique_ptr<JSONArray> array_up(new JSONArray());
489 JSONValue::SP value_sp = ParseJSONValue();
491 array_up->AppendObject(value_sp);
495 JSONParser::Token token = GetToken(value);
496 if (token == JSONParser::Token::Comma) {
498 } else if (token == JSONParser::Token::ArrayEnd) {
499 return JSONValue::SP(array_up.release());
504 return JSONValue::SP();
507 JSONValue::SP JSONParser::ParseJSONValue() {
509 const JSONParser::Token token = GetToken(value);
511 case JSONParser::Token::ObjectStart:
512 return ParseJSONObject();
514 case JSONParser::Token::ArrayStart:
515 return ParseJSONArray();
517 case JSONParser::Token::Integer: {
518 if (value.front() == '-') {
520 if (!llvm::StringRef(value).getAsInteger(0, sval))
521 return JSONValue::SP(new JSONNumber(sval));
524 if (!llvm::StringRef(value).getAsInteger(0, uval))
525 return JSONValue::SP(new JSONNumber(uval));
529 case JSONParser::Token::Float: {
531 if (!llvm::StringRef(value).getAsDouble(D))
532 return JSONValue::SP(new JSONNumber(D));
535 case JSONParser::Token::String:
536 return JSONValue::SP(new JSONString(value));
538 case JSONParser::Token::True:
539 return JSONValue::SP(new JSONTrue());
541 case JSONParser::Token::False:
542 return JSONValue::SP(new JSONFalse());
544 case JSONParser::Token::Null:
545 return JSONValue::SP(new JSONNull());
550 return JSONValue::SP();