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