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