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