LLDB  mainline
JSON.cpp
Go to the documentation of this file.
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"
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 
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 
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 (uint64_t)m_data.m_signed;
59  case DataType::Double:
60  return (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 (int64_t)m_data.m_unsigned;
69  case DataType::Signed:
70  return m_data.m_signed;
71  case DataType::Double:
72  return (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 (double)m_data.m_unsigned;
81  case DataType::Signed:
82  return (double)m_data.m_signed;
83  case DataType::Double:
84  return m_data.m_double;
85  }
86  llvm_unreachable("Unhandled data type");
87 }
88 
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 
104 
105 void JSONTrue::Write(Stream &s) { s.Printf("true"); }
106 
108 
109 void JSONFalse::Write(Stream &s) { s.Printf("false"); }
110 
112 
113 void JSONNull::Write(Stream &s) { s.Printf("null"); }
114 
116 
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 
150 
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 
180  if (value.get() == nullptr)
181  return false;
182  m_elements.push_back(value);
183  return true;
184 }
185 
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 
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 (1) {
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, (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 
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 (1) {
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 
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 (1) {
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 
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 }
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
JSONValue::SP ParseJSONValue()
Definition: JSON.cpp:506
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
std::shared_ptr< JSONValue > SP
Definition: JSON.h:31
std::string m_packet
JSONValue::SP GetObject(const std::string &key)
Definition: JSON.cpp:142
char PeekChar(char fail_value='\0')
double GetAsDouble() const
Definition: JSON.cpp:77
JSONValue::SP GetObject(Index i)
Definition: JSON.cpp:186
JSONValue::SP ParseJSONArray()
Definition: JSON.cpp:480
void Write(Stream &s) override
Definition: JSON.cpp:89
int GetEscapedChar(bool &was_escaped)
Definition: JSON.cpp:413
Token GetToken(std::string &value)
Definition: JSON.cpp:196
bool SetObject(const std::string &key, JSONValue::SP value)
Definition: JSON.cpp:135
llvm::StringRef GetString() const
int64_t GetAsSigned() const
Definition: JSON.cpp:65
void Write(Stream &s) override
Definition: JSON.cpp:151
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:106
void Write(Stream &s) override
Definition: JSON.cpp:113
uint64_t GetAsUnsigned() const
Definition: JSON.cpp:53
size_t PutChar(char ch)
Definition: Stream.cpp:103
void Write(Stream &s) override
Definition: JSON.cpp:117
bool AppendObject(JSONValue::SP value)
Definition: JSON.cpp:179
JSONValue::SP ParseJSONObject()
Definition: JSON.cpp:449
JSONParser(llvm::StringRef data)
Definition: JSON.cpp:194
bool SetObject(Index i, JSONValue::SP value)
Definition: JSON.cpp:165
void Write(Stream &s) override
Definition: JSON.cpp:109
void Write(Stream &s) override
Definition: JSON.cpp:49
char GetChar(char fail_value='\0')
void Write(Stream &s) override
Definition: JSON.cpp:105