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