• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===--------------------- JSON.cpp -----------------------------*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "JSON.h"
10 
11 // C includes
12 #include <assert.h>
13 #include <limits.h>
14 
15 // C++ includes
16 #include "lldb/Host/StringConvert.h"
17 #include <iomanip>
18 #include <sstream>
19 
20 using namespace lldb_private;
21 
json_string_quote_metachars(const std::string & s)22 std::string JSONString::json_string_quote_metachars(const std::string &s) {
23   if (s.find('"') == std::string::npos)
24     return s;
25 
26   std::string output;
27   const size_t s_size = s.size();
28   const char *s_chars = s.c_str();
29   for (size_t i = 0; i < s_size; i++) {
30     unsigned char ch = *(s_chars + i);
31     if (ch == '"') {
32       output.push_back('\\');
33     }
34     output.push_back(ch);
35   }
36   return output;
37 }
38 
JSONString()39 JSONString::JSONString() : JSONValue(JSONValue::Kind::String), m_data() {}
40 
JSONString(const char * s)41 JSONString::JSONString(const char *s)
42     : JSONValue(JSONValue::Kind::String), m_data(s ? s : "") {}
43 
JSONString(const std::string & s)44 JSONString::JSONString(const std::string &s)
45     : JSONValue(JSONValue::Kind::String), m_data(s) {}
46 
Write(std::ostream & s)47 void JSONString::Write(std::ostream &s) {
48   s << "\"" << json_string_quote_metachars(m_data).c_str() << "\"";
49 }
50 
GetAsUnsigned() const51 uint64_t JSONNumber::GetAsUnsigned() const {
52   switch (m_data_type) {
53   case DataType::Unsigned:
54     return m_data.m_unsigned;
55   case DataType::Signed:
56     return (uint64_t)m_data.m_signed;
57   case DataType::Double:
58     return (uint64_t)m_data.m_double;
59   }
60 }
61 
GetAsSigned() const62 int64_t JSONNumber::GetAsSigned() const {
63   switch (m_data_type) {
64   case DataType::Unsigned:
65     return (int64_t)m_data.m_unsigned;
66   case DataType::Signed:
67     return m_data.m_signed;
68   case DataType::Double:
69     return (int64_t)m_data.m_double;
70   }
71 }
72 
GetAsDouble() const73 double JSONNumber::GetAsDouble() const {
74   switch (m_data_type) {
75   case DataType::Unsigned:
76     return (double)m_data.m_unsigned;
77   case DataType::Signed:
78     return (double)m_data.m_signed;
79   case DataType::Double:
80     return m_data.m_double;
81   }
82 }
83 
Write(std::ostream & s)84 void JSONNumber::Write(std::ostream &s) {
85   switch (m_data_type) {
86   case DataType::Unsigned:
87     s << m_data.m_unsigned;
88     break;
89   case DataType::Signed:
90     s << m_data.m_signed;
91     break;
92   case DataType::Double:
93     // Set max precision to emulate %g.
94     s << std::setprecision(std::numeric_limits<double>::digits10 + 1);
95     s << m_data.m_double;
96     break;
97   }
98 }
99 
JSONTrue()100 JSONTrue::JSONTrue() : JSONValue(JSONValue::Kind::True) {}
101 
Write(std::ostream & s)102 void JSONTrue::Write(std::ostream &s) { s << "true"; }
103 
JSONFalse()104 JSONFalse::JSONFalse() : JSONValue(JSONValue::Kind::False) {}
105 
Write(std::ostream & s)106 void JSONFalse::Write(std::ostream &s) { s << "false"; }
107 
JSONNull()108 JSONNull::JSONNull() : JSONValue(JSONValue::Kind::Null) {}
109 
Write(std::ostream & s)110 void JSONNull::Write(std::ostream &s) { s << "null"; }
111 
JSONObject()112 JSONObject::JSONObject() : JSONValue(JSONValue::Kind::Object) {}
113 
Write(std::ostream & s)114 void JSONObject::Write(std::ostream &s) {
115   bool first = true;
116   s << '{';
117   auto iter = m_elements.begin(), end = m_elements.end();
118   for (; iter != end; iter++) {
119     if (first)
120       first = false;
121     else
122       s << ',';
123     JSONString key(iter->first);
124     JSONValue::SP value(iter->second);
125     key.Write(s);
126     s << ':';
127     value->Write(s);
128   }
129   s << '}';
130 }
131 
SetObject(const std::string & key,JSONValue::SP value)132 bool JSONObject::SetObject(const std::string &key, JSONValue::SP value) {
133   if (key.empty() || nullptr == value.get())
134     return false;
135   m_elements[key] = value;
136   return true;
137 }
138 
GetObject(const std::string & key) const139 JSONValue::SP JSONObject::GetObject(const std::string &key) const {
140   auto iter = m_elements.find(key), end = m_elements.end();
141   if (iter == end)
142     return JSONValue::SP();
143   return iter->second;
144 }
145 
GetObjectAsBool(const std::string & key,bool & value) const146 bool JSONObject::GetObjectAsBool(const std::string &key, bool &value) const {
147   auto value_sp = GetObject(key);
148   if (!value_sp) {
149     // The given key doesn't exist, so we have no value.
150     return false;
151   }
152 
153   if (JSONTrue::classof(value_sp.get())) {
154     // We have the value, and it is true.
155     value = true;
156     return true;
157   } else if (JSONFalse::classof(value_sp.get())) {
158     // We have the value, and it is false.
159     value = false;
160     return true;
161   } else {
162     // We don't have a valid bool value for the given key.
163     return false;
164   }
165 }
166 
GetObjectAsString(const std::string & key,std::string & value) const167 bool JSONObject::GetObjectAsString(const std::string &key,
168                                    std::string &value) const {
169   auto value_sp = GetObject(key);
170   if (!value_sp) {
171     // The given key doesn't exist, so we have no value.
172     return false;
173   }
174 
175   if (!JSONString::classof(value_sp.get()))
176     return false;
177 
178   value = static_cast<JSONString *>(value_sp.get())->GetData();
179   return true;
180 }
181 
JSONArray()182 JSONArray::JSONArray() : JSONValue(JSONValue::Kind::Array) {}
183 
Write(std::ostream & s)184 void JSONArray::Write(std::ostream &s) {
185   bool first = true;
186   s << '[';
187   auto iter = m_elements.begin(), end = m_elements.end();
188   for (; iter != end; iter++) {
189     if (first)
190       first = false;
191     else
192       s << ',';
193     (*iter)->Write(s);
194   }
195   s << ']';
196 }
197 
SetObject(Index i,JSONValue::SP value)198 bool JSONArray::SetObject(Index i, JSONValue::SP value) {
199   if (value.get() == nullptr)
200     return false;
201   if (i < m_elements.size()) {
202     m_elements[i] = value;
203     return true;
204   }
205   if (i == m_elements.size()) {
206     m_elements.push_back(value);
207     return true;
208   }
209   return false;
210 }
211 
AppendObject(JSONValue::SP value)212 bool JSONArray::AppendObject(JSONValue::SP value) {
213   if (value.get() == nullptr)
214     return false;
215   m_elements.push_back(value);
216   return true;
217 }
218 
GetObject(Index i)219 JSONValue::SP JSONArray::GetObject(Index i) {
220   if (i < m_elements.size())
221     return m_elements[i];
222   return JSONValue::SP();
223 }
224 
GetNumElements()225 JSONArray::Size JSONArray::GetNumElements() { return m_elements.size(); }
226 
JSONParser(const char * cstr)227 JSONParser::JSONParser(const char *cstr) : StdStringExtractor(cstr) {}
228 
GetToken(std::string & value)229 JSONParser::Token JSONParser::GetToken(std::string &value) {
230   std::ostringstream error;
231 
232   value.clear();
233   SkipSpaces();
234   const uint64_t start_index = m_index;
235   const char ch = GetChar();
236   switch (ch) {
237   case '{':
238     return Token::ObjectStart;
239   case '}':
240     return Token::ObjectEnd;
241   case '[':
242     return Token::ArrayStart;
243   case ']':
244     return Token::ArrayEnd;
245   case ',':
246     return Token::Comma;
247   case ':':
248     return Token::Colon;
249   case '\0':
250     return Token::EndOfFile;
251   case 't':
252     if (GetChar() == 'r')
253       if (GetChar() == 'u')
254         if (GetChar() == 'e')
255           return Token::True;
256     break;
257 
258   case 'f':
259     if (GetChar() == 'a')
260       if (GetChar() == 'l')
261         if (GetChar() == 's')
262           if (GetChar() == 'e')
263             return Token::False;
264     break;
265 
266   case 'n':
267     if (GetChar() == 'u')
268       if (GetChar() == 'l')
269         if (GetChar() == 'l')
270           return Token::Null;
271     break;
272 
273   case '"': {
274     while (true) {
275       bool was_escaped = false;
276       int escaped_ch = GetEscapedChar(was_escaped);
277       if (escaped_ch == -1) {
278         error << "error: an error occurred getting a character from offset "
279               << start_index;
280         value = error.str();
281         return Token::Status;
282 
283       } else {
284         const bool is_end_quote = escaped_ch == '"';
285         const bool is_null = escaped_ch == 0;
286         if (was_escaped || (!is_end_quote && !is_null)) {
287           if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX) {
288             value.append(1, (char)escaped_ch);
289           } else {
290             error << "error: wide character support is needed for unicode "
291                      "character 0x"
292                   << std::setprecision(4) << std::hex << escaped_ch;
293             error << " at offset " << start_index;
294             value = error.str();
295             return Token::Status;
296           }
297         } else if (is_end_quote) {
298           return Token::String;
299         } else if (is_null) {
300           value = "error: missing end quote for string";
301           return Token::Status;
302         }
303       }
304     }
305   } break;
306 
307   case '-':
308   case '0':
309   case '1':
310   case '2':
311   case '3':
312   case '4':
313   case '5':
314   case '6':
315   case '7':
316   case '8':
317   case '9': {
318     bool done = false;
319     bool got_decimal_point = false;
320     uint64_t exp_index = 0;
321     bool got_int_digits = (ch >= '0') && (ch <= '9');
322     bool got_frac_digits = false;
323     bool got_exp_digits = false;
324     while (!done) {
325       const char next_ch = PeekChar();
326       switch (next_ch) {
327       case '0':
328       case '1':
329       case '2':
330       case '3':
331       case '4':
332       case '5':
333       case '6':
334       case '7':
335       case '8':
336       case '9':
337         if (exp_index != 0) {
338           got_exp_digits = true;
339         } else if (got_decimal_point) {
340           got_frac_digits = true;
341         } else {
342           got_int_digits = true;
343         }
344         ++m_index; // Skip this character
345         break;
346 
347       case '.':
348         if (got_decimal_point) {
349           error << "error: extra decimal point found at offset " << start_index;
350           value = error.str();
351           return Token::Status;
352         } else {
353           got_decimal_point = true;
354           ++m_index; // Skip this character
355         }
356         break;
357 
358       case 'e':
359       case 'E':
360         if (exp_index != 0) {
361           error << "error: extra exponent character found at offset "
362                 << start_index;
363           value = error.str();
364           return Token::Status;
365         } else {
366           exp_index = m_index;
367           ++m_index; // Skip this character
368         }
369         break;
370 
371       case '+':
372       case '-':
373         // The '+' and '-' can only come after an exponent character...
374         if (exp_index == m_index - 1) {
375           ++m_index; // Skip the exponent sign character
376         } else {
377           error << "error: unexpected " << next_ch << " character at offset "
378                 << start_index;
379           value = error.str();
380           return Token::Status;
381         }
382         break;
383 
384       default:
385         done = true;
386         break;
387       }
388     }
389 
390     if (m_index > start_index) {
391       value = m_packet.substr(start_index, m_index - start_index);
392       if (got_decimal_point) {
393         if (exp_index != 0) {
394           // We have an exponent, make sure we got exponent digits
395           if (got_exp_digits) {
396             return Token::Float;
397           } else {
398             error << "error: got exponent character but no exponent digits at "
399                      "offset in float value \""
400                   << value.c_str() << "\"";
401             value = error.str();
402             return Token::Status;
403           }
404         } else {
405           // No exponent, but we need at least one decimal after the decimal
406           // point
407           if (got_frac_digits) {
408             return Token::Float;
409           } else {
410             error << "error: no digits after decimal point \"" << value.c_str()
411                   << "\"";
412             value = error.str();
413             return Token::Status;
414           }
415         }
416       } else {
417         // No decimal point
418         if (got_int_digits) {
419           // We need at least some integer digits to make an integer
420           return Token::Integer;
421         } else {
422           error << "error: no digits negate sign \"" << value.c_str() << "\"";
423           value = error.str();
424           return Token::Status;
425         }
426       }
427     } else {
428       error << "error: invalid number found at offset " << start_index;
429       value = error.str();
430       return Token::Status;
431     }
432   } break;
433   default:
434     break;
435   }
436   error << "error: failed to parse token at offset " << start_index
437         << " (around character '" << ch << "')";
438   value = error.str();
439   return Token::Status;
440 }
441 
GetEscapedChar(bool & was_escaped)442 int JSONParser::GetEscapedChar(bool &was_escaped) {
443   was_escaped = false;
444   const char ch = GetChar();
445   if (ch == '\\') {
446     was_escaped = true;
447     const char ch2 = GetChar();
448     switch (ch2) {
449     case '"':
450     case '\\':
451     case '/':
452     default:
453       break;
454 
455     case 'b':
456       return '\b';
457     case 'f':
458       return '\f';
459     case 'n':
460       return '\n';
461     case 'r':
462       return '\r';
463     case 't':
464       return '\t';
465     case 'u': {
466       const int hi_byte = DecodeHexU8();
467       const int lo_byte = DecodeHexU8();
468       if (hi_byte >= 0 && lo_byte >= 0)
469         return hi_byte << 8 | lo_byte;
470       return -1;
471     } break;
472     }
473     return ch2;
474   }
475   return ch;
476 }
477 
ParseJSONObject()478 JSONValue::SP JSONParser::ParseJSONObject() {
479   // The "JSONParser::Token::ObjectStart" token should have already been
480   // consumed
481   // by the time this function is called
482   std::unique_ptr<JSONObject> dict_up(new JSONObject());
483 
484   std::string value;
485   std::string key;
486   while (true) {
487     JSONParser::Token token = GetToken(value);
488 
489     if (token == JSONParser::Token::String) {
490       key.swap(value);
491       token = GetToken(value);
492       if (token == JSONParser::Token::Colon) {
493         JSONValue::SP value_sp = ParseJSONValue();
494         if (value_sp)
495           dict_up->SetObject(key, value_sp);
496         else
497           break;
498       }
499     } else if (token == JSONParser::Token::ObjectEnd) {
500       return JSONValue::SP(dict_up.release());
501     } else if (token == JSONParser::Token::Comma) {
502       continue;
503     } else {
504       break;
505     }
506   }
507   return JSONValue::SP();
508 }
509 
ParseJSONArray()510 JSONValue::SP JSONParser::ParseJSONArray() {
511   // The "JSONParser::Token::ObjectStart" token should have already been
512   // consumed
513   // by the time this function is called
514   std::unique_ptr<JSONArray> array_up(new JSONArray());
515 
516   std::string value;
517   std::string key;
518   while (true) {
519     JSONParser::Token token = GetToken(value);
520     if (token == JSONParser::Token::ArrayEnd)
521       return JSONValue::SP(array_up.release());
522     JSONValue::SP value_sp = ParseJSONValue(value, token);
523     if (value_sp)
524       array_up->AppendObject(value_sp);
525     else
526       break;
527 
528     token = GetToken(value);
529     if (token == JSONParser::Token::Comma) {
530       continue;
531     } else if (token == JSONParser::Token::ArrayEnd) {
532       return JSONValue::SP(array_up.release());
533     } else {
534       break;
535     }
536   }
537   return JSONValue::SP();
538 }
539 
ParseJSONValue()540 JSONValue::SP JSONParser::ParseJSONValue() {
541   std::string value;
542   const JSONParser::Token token = GetToken(value);
543   return ParseJSONValue(value, token);
544 }
545 
ParseJSONValue(const std::string & value,const Token & token)546 JSONValue::SP JSONParser::ParseJSONValue(const std::string &value,
547                                          const Token &token) {
548   switch (token) {
549   case JSONParser::Token::ObjectStart:
550     return ParseJSONObject();
551 
552   case JSONParser::Token::ArrayStart:
553     return ParseJSONArray();
554 
555   case JSONParser::Token::Integer: {
556     if (value.front() == '-') {
557       bool success = false;
558       int64_t sval = StringConvert::ToSInt64(value.c_str(), 0, 0, &success);
559       if (success)
560         return JSONValue::SP(new JSONNumber(sval));
561     } else {
562       bool success = false;
563       uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success);
564       if (success)
565         return JSONValue::SP(new JSONNumber(uval));
566     }
567   } break;
568 
569   case JSONParser::Token::Float: {
570     bool success = false;
571     double val = StringConvert::ToDouble(value.c_str(), 0.0, &success);
572     if (success)
573       return JSONValue::SP(new JSONNumber(val));
574   } break;
575 
576   case JSONParser::Token::String:
577     return JSONValue::SP(new JSONString(value));
578 
579   case JSONParser::Token::True:
580     return JSONValue::SP(new JSONTrue());
581 
582   case JSONParser::Token::False:
583     return JSONValue::SP(new JSONFalse());
584 
585   case JSONParser::Token::Null:
586     return JSONValue::SP(new JSONNull());
587 
588   default:
589     break;
590   }
591   return JSONValue::SP();
592 }
593