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"
13 #include "lldb/Utility/StreamString.h"
14 #include "llvm/ADT/StringRef.h"
15 #include "llvm/Support/ErrorHandling.h"
16
17 #include <inttypes.h>
18 #include <limits.h>
19 #include <stddef.h>
20 #include <utility>
21
22 using namespace lldb_private;
23
json_string_quote_metachars(const std::string & s)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
JSONString()42 JSONString::JSONString() : JSONValue(JSONValue::Kind::String), m_data() {}
43
JSONString(const char * s)44 JSONString::JSONString(const char *s)
45 : JSONValue(JSONValue::Kind::String), m_data(s ? s : "") {}
46
JSONString(const std::string & s)47 JSONString::JSONString(const std::string &s)
48 : JSONValue(JSONValue::Kind::String), m_data(s) {}
49
Write(Stream & s)50 void JSONString::Write(Stream &s) {
51 s.Printf("\"%s\"", json_string_quote_metachars(m_data).c_str());
52 }
53
GetAsUnsigned() const54 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
GetAsSigned() const66 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
GetAsDouble() const78 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
Write(Stream & s)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
JSONTrue()104 JSONTrue::JSONTrue() : JSONValue(JSONValue::Kind::True) {}
105
Write(Stream & s)106 void JSONTrue::Write(Stream &s) { s.Printf("true"); }
107
JSONFalse()108 JSONFalse::JSONFalse() : JSONValue(JSONValue::Kind::False) {}
109
Write(Stream & s)110 void JSONFalse::Write(Stream &s) { s.Printf("false"); }
111
JSONNull()112 JSONNull::JSONNull() : JSONValue(JSONValue::Kind::Null) {}
113
Write(Stream & s)114 void JSONNull::Write(Stream &s) { s.Printf("null"); }
115
JSONObject()116 JSONObject::JSONObject() : JSONValue(JSONValue::Kind::Object) {}
117
Write(Stream & s)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
SetObject(const std::string & key,JSONValue::SP value)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
GetObject(const std::string & key)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
JSONArray()150 JSONArray::JSONArray() : JSONValue(JSONValue::Kind::Array) {}
151
Write(Stream & s)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
SetObject(Index i,JSONValue::SP value)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
AppendObject(JSONValue::SP value)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
GetObject(Index i)187 JSONValue::SP JSONArray::GetObject(Index i) {
188 if (i < m_elements.size())
189 return m_elements[i];
190 return JSONValue::SP();
191 }
192
GetNumElements()193 JSONArray::Size JSONArray::GetNumElements() { return m_elements.size(); }
194
JSONParser(llvm::StringRef data)195 JSONParser::JSONParser(llvm::StringRef data) : StringExtractor(data) {}
196
GetToken(std::string & value)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
GetEscapedChar(bool & was_escaped)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
ParseJSONObject()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
ParseJSONArray()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
ParseJSONValue()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 }
552