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