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