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"
13 #include "lldb/Core/StreamString.h"
14 #include "lldb/Host/StringConvert.h"
15 #include "llvm/Support/ErrorHandling.h"
17 using namespace lldb_private;
20 JSONString::json_string_quote_metachars (const std::string &s)
22 if (s.find('"') == std::string::npos)
26 const size_t s_size = s.size();
27 const char *s_chars = s.c_str();
28 for (size_t i = 0; i < s_size; i++)
30 unsigned char ch = *(s_chars + i);
33 output.push_back ('\\');
35 output.push_back (ch);
40 JSONString::JSONString () :
41 JSONValue(JSONValue::Kind::String),
46 JSONString::JSONString (const char* s) :
47 JSONValue(JSONValue::Kind::String),
52 JSONString::JSONString (const std::string& s) :
53 JSONValue(JSONValue::Kind::String),
59 JSONString::Write (Stream& s)
61 s.Printf("\"%s\"", json_string_quote_metachars(m_data).c_str());
65 JSONNumber::GetAsUnsigned() const
69 case DataType::Unsigned:
70 return m_data.m_unsigned;
71 case DataType::Signed:
72 return (uint64_t)m_data.m_signed;
73 case DataType::Double:
74 return (uint64_t)m_data.m_double;
76 llvm_unreachable("Unhandled data type");
80 JSONNumber::GetAsSigned() const
84 case DataType::Unsigned:
85 return (int64_t)m_data.m_unsigned;
86 case DataType::Signed:
87 return m_data.m_signed;
88 case DataType::Double:
89 return (int64_t)m_data.m_double;
91 llvm_unreachable("Unhandled data type");
95 JSONNumber::GetAsDouble() const
99 case DataType::Unsigned:
100 return (double)m_data.m_unsigned;
101 case DataType::Signed:
102 return (double)m_data.m_signed;
103 case DataType::Double:
104 return m_data.m_double;
106 llvm_unreachable("Unhandled data type");
110 JSONNumber::Write (Stream& s)
114 case DataType::Unsigned:
115 s.Printf("%" PRIu64, m_data.m_unsigned);
117 case DataType::Signed:
118 s.Printf("%" PRId64, m_data.m_signed);
120 case DataType::Double:
121 s.Printf("%g", m_data.m_double);
126 JSONTrue::JSONTrue () :
127 JSONValue(JSONValue::Kind::True)
132 JSONTrue::Write(Stream& s)
137 JSONFalse::JSONFalse () :
138 JSONValue(JSONValue::Kind::False)
143 JSONFalse::Write(Stream& s)
148 JSONNull::JSONNull () :
149 JSONValue(JSONValue::Kind::Null)
154 JSONNull::Write(Stream& s)
159 JSONObject::JSONObject () :
160 JSONValue(JSONValue::Kind::Object)
165 JSONObject::Write (Stream& s)
169 auto iter = m_elements.begin(), end = m_elements.end();
170 for (;iter != end; iter++)
176 JSONString key(iter->first);
177 JSONValue::SP value(iter->second);
186 JSONObject::SetObject (const std::string& key,
189 if (key.empty() || nullptr == value.get())
191 m_elements[key] = value;
196 JSONObject::GetObject (const std::string& key)
198 auto iter = m_elements.find(key), end = m_elements.end();
200 return JSONValue::SP();
204 JSONArray::JSONArray () :
205 JSONValue(JSONValue::Kind::Array)
210 JSONArray::Write (Stream& s)
214 auto iter = m_elements.begin(), end = m_elements.end();
215 for (;iter != end; iter++)
227 JSONArray::SetObject (Index i,
230 if (value.get() == nullptr)
232 if (i < m_elements.size())
234 m_elements[i] = value;
237 if (i == m_elements.size())
239 m_elements.push_back(value);
246 JSONArray::AppendObject (JSONValue::SP value)
248 if (value.get() == nullptr)
250 m_elements.push_back(value);
255 JSONArray::GetObject (Index i)
257 if (i < m_elements.size())
258 return m_elements[i];
259 return JSONValue::SP();
263 JSONArray::GetNumElements ()
265 return m_elements.size();
269 JSONParser::JSONParser (const char *cstr) :
270 StringExtractor(cstr)
275 JSONParser::GetToken (std::string &value)
281 const uint64_t start_index = m_index;
282 const char ch = GetChar();
285 case '{': return Token::ObjectStart;
286 case '}': return Token::ObjectEnd;
287 case '[': return Token::ArrayStart;
288 case ']': return Token::ArrayEnd;
289 case ',': return Token::Comma;
290 case ':': return Token::Colon;
291 case '\0': return Token::EndOfFile;
293 if (GetChar() == 'r')
294 if (GetChar() == 'u')
295 if (GetChar() == 'e')
300 if (GetChar() == 'a')
301 if (GetChar() == 'l')
302 if (GetChar() == 's')
303 if (GetChar() == 'e')
308 if (GetChar() == 'u')
309 if (GetChar() == 'l')
310 if (GetChar() == 'l')
318 bool was_escaped = false;
319 int escaped_ch = GetEscapedChar(was_escaped);
320 if (escaped_ch == -1)
322 error.Printf("error: an error occurred getting a character from offset %" PRIu64, start_index);
323 value = std::move(error.GetString());
329 const bool is_end_quote = escaped_ch == '"';
330 const bool is_null = escaped_ch == 0;
331 if (was_escaped || (!is_end_quote && !is_null))
333 if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX)
335 value.append(1, (char)escaped_ch);
339 error.Printf("error: wide character support is needed for unicode character 0x%4.4x at offset %" PRIu64, escaped_ch, start_index);
340 value = std::move(error.GetString());
344 else if (is_end_quote)
346 return Token::String;
350 value = "error: missing end quote for string";
371 bool got_decimal_point = false;
372 uint64_t exp_index = 0;
373 bool got_int_digits = (ch >= '0') && (ch <= '9');
374 bool got_frac_digits = false;
375 bool got_exp_digits = false;
378 const char next_ch = PeekChar();
393 got_exp_digits = true;
395 else if (got_decimal_point)
397 got_frac_digits = true;
401 got_int_digits = true;
403 ++m_index; // Skip this character
407 if (got_decimal_point)
409 error.Printf("error: extra decimal point found at offset %" PRIu64, start_index);
410 value = std::move(error.GetString());
415 got_decimal_point = true;
416 ++m_index; // Skip this character
424 error.Printf("error: extra exponent character found at offset %" PRIu64, start_index);
425 value = std::move(error.GetString());
431 ++m_index; // Skip this character
437 // The '+' and '-' can only come after an exponent character...
438 if (exp_index == m_index - 1)
440 ++m_index; // Skip the exponent sign character
444 error.Printf("error: unexpected %c character at offset %" PRIu64, next_ch, start_index);
445 value = std::move(error.GetString());
456 if (m_index > start_index)
458 value = m_packet.substr(start_index, m_index - start_index);
459 if (got_decimal_point)
463 // We have an exponent, make sure we got exponent digits
470 error.Printf("error: got exponent character but no exponent digits at offset in float value \"%s\"", value.c_str());
471 value = std::move(error.GetString());
477 // No exponent, but we need at least one decimal after the decimal point
484 error.Printf("error: no digits after decimal point \"%s\"", value.c_str());
485 value = std::move(error.GetString());
495 // We need at least some integer digits to make an integer
496 return Token::Integer;
500 error.Printf("error: no digits negate sign \"%s\"", value.c_str());
501 value = std::move(error.GetString());
508 error.Printf("error: invalid number found at offset %" PRIu64, start_index);
509 value = std::move(error.GetString());
517 error.Printf("error: failed to parse token at offset %" PRIu64 " (around character '%c')", start_index, ch);
518 value = std::move(error.GetString());
523 JSONParser::GetEscapedChar(bool &was_escaped)
526 const char ch = GetChar();
530 const char ch2 = GetChar();
539 case 'b': return '\b';
540 case 'f': return '\f';
541 case 'n': return '\n';
542 case 'r': return '\r';
543 case 't': return '\t';
546 const int hi_byte = DecodeHexU8();
547 const int lo_byte = DecodeHexU8();
548 if (hi_byte >=0 && lo_byte >= 0)
549 return hi_byte << 8 | lo_byte;
560 JSONParser::ParseJSONObject ()
562 // The "JSONParser::Token::ObjectStart" token should have already been consumed
563 // by the time this function is called
564 std::unique_ptr<JSONObject> dict_up(new JSONObject());
570 JSONParser::Token token = GetToken(value);
572 if (token == JSONParser::Token::String)
575 token = GetToken(value);
576 if (token == JSONParser::Token::Colon)
578 JSONValue::SP value_sp = ParseJSONValue();
580 dict_up->SetObject(key, value_sp);
585 else if (token == JSONParser::Token::ObjectEnd)
587 return JSONValue::SP(dict_up.release());
589 else if (token == JSONParser::Token::Comma)
598 return JSONValue::SP();
602 JSONParser::ParseJSONArray ()
604 // The "JSONParser::Token::ObjectStart" token should have already been consumed
605 // by the time this function is called
606 std::unique_ptr<JSONArray> array_up(new JSONArray());
612 JSONValue::SP value_sp = ParseJSONValue();
614 array_up->AppendObject(value_sp);
618 JSONParser::Token token = GetToken(value);
619 if (token == JSONParser::Token::Comma)
623 else if (token == JSONParser::Token::ArrayEnd)
625 return JSONValue::SP(array_up.release());
632 return JSONValue::SP();
636 JSONParser::ParseJSONValue ()
639 const JSONParser::Token token = GetToken(value);
642 case JSONParser::Token::ObjectStart:
643 return ParseJSONObject();
645 case JSONParser::Token::ArrayStart:
646 return ParseJSONArray();
648 case JSONParser::Token::Integer:
650 if (value.front() == '-')
652 bool success = false;
653 int64_t sval = StringConvert::ToSInt64(value.c_str(), 0, 0, &success);
655 return JSONValue::SP(new JSONNumber(sval));
659 bool success = false;
660 uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success);
662 return JSONValue::SP(new JSONNumber(uval));
667 case JSONParser::Token::Float:
669 bool success = false;
670 double val = StringConvert::ToDouble(value.c_str(), 0.0, &success);
672 return JSONValue::SP(new JSONNumber(val));
676 case JSONParser::Token::String:
677 return JSONValue::SP(new JSONString(value));
679 case JSONParser::Token::True:
680 return JSONValue::SP(new JSONTrue());
682 case JSONParser::Token::False:
683 return JSONValue::SP(new JSONFalse());
685 case JSONParser::Token::Null:
686 return JSONValue::SP(new JSONNull());
691 return JSONValue::SP();