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