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