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