blob: 19ebfd000f5170a0512e5502d3c27fb93ba77025 [file] [log] [blame]
Todd Fiala75930012016-08-19 04:21:48 +00001//===--------------------- 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 "JSON.h"
11
12// C includes
13#include <assert.h>
14#include <limits.h>
15
16// C++ includes
Kate Stoneb9c1b512016-09-06 20:57:50 +000017#include "lldb/Host/StringConvert.h"
Todd Fiala75930012016-08-19 04:21:48 +000018#include <iomanip>
19#include <sstream>
Todd Fiala75930012016-08-19 04:21:48 +000020
21using namespace lldb_private;
22
Kate Stoneb9c1b512016-09-06 20:57:50 +000023std::string JSONString::json_string_quote_metachars(const std::string &s) {
24 if (s.find('"') == 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 == '"') {
33 output.push_back('\\');
Todd Fiala75930012016-08-19 04:21:48 +000034 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000035 output.push_back(ch);
36 }
37 return output;
Todd Fiala75930012016-08-19 04:21:48 +000038}
39
Kate Stoneb9c1b512016-09-06 20:57:50 +000040JSONString::JSONString() : JSONValue(JSONValue::Kind::String), m_data() {}
41
42JSONString::JSONString(const char *s)
43 : JSONValue(JSONValue::Kind::String), m_data(s ? s : "") {}
44
45JSONString::JSONString(const std::string &s)
46 : JSONValue(JSONValue::Kind::String), m_data(s) {}
47
48void JSONString::Write(std::ostream &s) {
49 s << "\"" << json_string_quote_metachars(m_data).c_str() << "\"";
Todd Fiala75930012016-08-19 04:21:48 +000050}
51
Kate Stoneb9c1b512016-09-06 20:57:50 +000052uint64_t JSONNumber::GetAsUnsigned() const {
53 switch (m_data_type) {
54 case DataType::Unsigned:
55 return m_data.m_unsigned;
56 case DataType::Signed:
57 return (uint64_t)m_data.m_signed;
58 case DataType::Double:
59 return (uint64_t)m_data.m_double;
60 }
61 assert("Unhandled data type");
Todd Fiala75930012016-08-19 04:21:48 +000062}
63
Kate Stoneb9c1b512016-09-06 20:57:50 +000064int64_t JSONNumber::GetAsSigned() const {
65 switch (m_data_type) {
66 case DataType::Unsigned:
67 return (int64_t)m_data.m_unsigned;
68 case DataType::Signed:
69 return m_data.m_signed;
70 case DataType::Double:
71 return (int64_t)m_data.m_double;
72 }
73 assert("Unhandled data type");
Todd Fiala75930012016-08-19 04:21:48 +000074}
75
Kate Stoneb9c1b512016-09-06 20:57:50 +000076double JSONNumber::GetAsDouble() const {
77 switch (m_data_type) {
78 case DataType::Unsigned:
79 return (double)m_data.m_unsigned;
80 case DataType::Signed:
81 return (double)m_data.m_signed;
82 case DataType::Double:
83 return m_data.m_double;
84 }
85 assert("Unhandled data type");
Todd Fiala75930012016-08-19 04:21:48 +000086}
87
Kate Stoneb9c1b512016-09-06 20:57:50 +000088void JSONNumber::Write(std::ostream &s) {
89 switch (m_data_type) {
90 case DataType::Unsigned:
91 s << m_data.m_unsigned;
92 break;
93 case DataType::Signed:
94 s << m_data.m_signed;
95 break;
96 case DataType::Double:
97 // Set max precision to emulate %g.
98 s << std::setprecision(std::numeric_limits<double>::digits10 + 1);
99 s << m_data.m_double;
100 break;
101 }
Todd Fiala75930012016-08-19 04:21:48 +0000102}
103
Kate Stoneb9c1b512016-09-06 20:57:50 +0000104JSONTrue::JSONTrue() : JSONValue(JSONValue::Kind::True) {}
Todd Fiala75930012016-08-19 04:21:48 +0000105
Kate Stoneb9c1b512016-09-06 20:57:50 +0000106void JSONTrue::Write(std::ostream &s) { s << "true"; }
Todd Fiala75930012016-08-19 04:21:48 +0000107
Kate Stoneb9c1b512016-09-06 20:57:50 +0000108JSONFalse::JSONFalse() : JSONValue(JSONValue::Kind::False) {}
Todd Fiala75930012016-08-19 04:21:48 +0000109
Kate Stoneb9c1b512016-09-06 20:57:50 +0000110void JSONFalse::Write(std::ostream &s) { s << "false"; }
Todd Fiala75930012016-08-19 04:21:48 +0000111
Kate Stoneb9c1b512016-09-06 20:57:50 +0000112JSONNull::JSONNull() : JSONValue(JSONValue::Kind::Null) {}
Todd Fiala75930012016-08-19 04:21:48 +0000113
Kate Stoneb9c1b512016-09-06 20:57:50 +0000114void JSONNull::Write(std::ostream &s) { s << "null"; }
Todd Fiala75930012016-08-19 04:21:48 +0000115
Kate Stoneb9c1b512016-09-06 20:57:50 +0000116JSONObject::JSONObject() : JSONValue(JSONValue::Kind::Object) {}
Todd Fiala75930012016-08-19 04:21:48 +0000117
Kate Stoneb9c1b512016-09-06 20:57:50 +0000118void JSONObject::Write(std::ostream &s) {
119 bool first = true;
120 s << '{';
121 auto iter = m_elements.begin(), end = m_elements.end();
122 for (; iter != end; iter++) {
123 if (first)
124 first = false;
Todd Fiala75930012016-08-19 04:21:48 +0000125 else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000126 s << ',';
127 JSONString key(iter->first);
128 JSONValue::SP value(iter->second);
129 key.Write(s);
130 s << ':';
131 value->Write(s);
132 }
133 s << '}';
Todd Fiala75930012016-08-19 04:21:48 +0000134}
135
Kate Stoneb9c1b512016-09-06 20:57:50 +0000136bool JSONObject::SetObject(const std::string &key, JSONValue::SP value) {
137 if (key.empty() || nullptr == value.get())
Todd Fiala75930012016-08-19 04:21:48 +0000138 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000139 m_elements[key] = value;
140 return true;
Todd Fiala75930012016-08-19 04:21:48 +0000141}
142
Kate Stoneb9c1b512016-09-06 20:57:50 +0000143JSONValue::SP JSONObject::GetObject(const std::string &key) const {
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
150bool JSONObject::GetObjectAsBool(const std::string &key, bool &value) const {
151 auto value_sp = GetObject(key);
152 if (!value_sp) {
153 // The given key doesn't exist, so we have no value.
154 return false;
155 }
156
157 if (JSONTrue::classof(value_sp.get())) {
158 // We have the value, and it is true.
159 value = true;
160 return true;
161 } else if (JSONFalse::classof(value_sp.get())) {
162 // We have the value, and it is false.
163 value = false;
164 return true;
165 } else {
166 // We don't have a valid bool value for the given key.
167 return false;
168 }
169}
170
171bool JSONObject::GetObjectAsString(const std::string &key,
172 std::string &value) const {
173 auto value_sp = GetObject(key);
174 if (!value_sp) {
175 // The given key doesn't exist, so we have no value.
176 return false;
177 }
178
179 if (!JSONString::classof(value_sp.get()))
180 return false;
181
182 value = static_cast<JSONString *>(value_sp.get())->GetData();
183 return true;
184}
185
186JSONArray::JSONArray() : JSONValue(JSONValue::Kind::Array) {}
187
188void JSONArray::Write(std::ostream &s) {
189 bool first = true;
190 s << '[';
191 auto iter = m_elements.begin(), end = m_elements.end();
192 for (; iter != end; iter++) {
193 if (first)
194 first = false;
195 else
196 s << ',';
197 (*iter)->Write(s);
198 }
199 s << ']';
200}
201
202bool JSONArray::SetObject(Index i, JSONValue::SP value) {
203 if (value.get() == nullptr)
204 return false;
205 if (i < m_elements.size()) {
206 m_elements[i] = value;
207 return true;
208 }
209 if (i == m_elements.size()) {
Todd Fiala75930012016-08-19 04:21:48 +0000210 m_elements.push_back(value);
211 return true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000212 }
213 return false;
Todd Fiala75930012016-08-19 04:21:48 +0000214}
215
Kate Stoneb9c1b512016-09-06 20:57:50 +0000216bool JSONArray::AppendObject(JSONValue::SP value) {
217 if (value.get() == nullptr)
218 return false;
219 m_elements.push_back(value);
220 return true;
Todd Fiala75930012016-08-19 04:21:48 +0000221}
222
Kate Stoneb9c1b512016-09-06 20:57:50 +0000223JSONValue::SP JSONArray::GetObject(Index i) {
224 if (i < m_elements.size())
225 return m_elements[i];
226 return JSONValue::SP();
Todd Fiala75930012016-08-19 04:21:48 +0000227}
228
Kate Stoneb9c1b512016-09-06 20:57:50 +0000229JSONArray::Size JSONArray::GetNumElements() { return m_elements.size(); }
Todd Fiala75930012016-08-19 04:21:48 +0000230
Kate Stoneb9c1b512016-09-06 20:57:50 +0000231JSONParser::JSONParser(const char *cstr) : StdStringExtractor(cstr) {}
Todd Fiala75930012016-08-19 04:21:48 +0000232
Kate Stoneb9c1b512016-09-06 20:57:50 +0000233JSONParser::Token JSONParser::GetToken(std::string &value) {
234 std::ostringstream error;
Todd Fiala75930012016-08-19 04:21:48 +0000235
Kate Stoneb9c1b512016-09-06 20:57:50 +0000236 value.clear();
237 SkipSpaces();
238 const uint64_t start_index = m_index;
239 const char ch = GetChar();
240 switch (ch) {
241 case '{':
242 return Token::ObjectStart;
243 case '}':
244 return Token::ObjectEnd;
245 case '[':
246 return Token::ArrayStart;
247 case ']':
248 return Token::ArrayEnd;
249 case ',':
250 return Token::Comma;
251 case ':':
252 return Token::Colon;
253 case '\0':
254 return Token::EndOfFile;
255 case 't':
256 if (GetChar() == 'r')
257 if (GetChar() == 'u')
258 if (GetChar() == 'e')
259 return Token::True;
260 break;
Todd Fiala75930012016-08-19 04:21:48 +0000261
Kate Stoneb9c1b512016-09-06 20:57:50 +0000262 case 'f':
263 if (GetChar() == 'a')
264 if (GetChar() == 'l')
265 if (GetChar() == 's')
266 if (GetChar() == 'e')
267 return Token::False;
268 break;
Todd Fiala75930012016-08-19 04:21:48 +0000269
Kate Stoneb9c1b512016-09-06 20:57:50 +0000270 case 'n':
271 if (GetChar() == 'u')
272 if (GetChar() == 'l')
273 if (GetChar() == 'l')
274 return Token::Null;
275 break;
Todd Fiala75930012016-08-19 04:21:48 +0000276
Kate Stoneb9c1b512016-09-06 20:57:50 +0000277 case '"': {
278 while (1) {
279 bool was_escaped = false;
280 int escaped_ch = GetEscapedChar(was_escaped);
281 if (escaped_ch == -1) {
282 error << "error: an error occurred getting a character from offset "
283 << start_index;
284 value = error.str();
285 return Token::Error;
Todd Fiala75930012016-08-19 04:21:48 +0000286
Kate Stoneb9c1b512016-09-06 20:57:50 +0000287 } else {
288 const bool is_end_quote = escaped_ch == '"';
289 const bool is_null = escaped_ch == 0;
290 if (was_escaped || (!is_end_quote && !is_null)) {
291 if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX) {
292 value.append(1, (char)escaped_ch);
293 } else {
294 error << "error: wide character support is needed for unicode "
295 "character 0x"
296 << std::setprecision(4) << std::hex << escaped_ch;
297 error << " at offset " << start_index;
298 value = error.str();
299 return Token::Error;
300 }
301 } else if (is_end_quote) {
302 return Token::String;
303 } else if (is_null) {
304 value = "error: missing end quote for string";
305 return Token::Error;
306 }
307 }
Todd Fiala75930012016-08-19 04:21:48 +0000308 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000309 } break;
Todd Fiala75930012016-08-19 04:21:48 +0000310
Kate Stoneb9c1b512016-09-06 20:57:50 +0000311 case '-':
312 case '0':
313 case '1':
314 case '2':
315 case '3':
316 case '4':
317 case '5':
318 case '6':
319 case '7':
320 case '8':
321 case '9': {
322 bool done = false;
323 bool got_decimal_point = false;
324 uint64_t exp_index = 0;
325 bool got_int_digits = (ch >= '0') && (ch <= '9');
326 bool got_frac_digits = false;
327 bool got_exp_digits = false;
328 while (!done) {
329 const char next_ch = PeekChar();
330 switch (next_ch) {
331 case '0':
332 case '1':
333 case '2':
334 case '3':
335 case '4':
336 case '5':
337 case '6':
338 case '7':
339 case '8':
340 case '9':
341 if (exp_index != 0) {
342 got_exp_digits = true;
343 } else if (got_decimal_point) {
344 got_frac_digits = true;
345 } else {
346 got_int_digits = true;
Todd Fiala75930012016-08-19 04:21:48 +0000347 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000348 ++m_index; // Skip this character
349 break;
350
351 case '.':
352 if (got_decimal_point) {
353 error << "error: extra decimal point found at offset " << start_index;
354 value = error.str();
355 return Token::Error;
356 } else {
357 got_decimal_point = true;
358 ++m_index; // Skip this character
359 }
360 break;
361
362 case 'e':
363 case 'E':
364 if (exp_index != 0) {
365 error << "error: extra exponent character found at offset "
366 << start_index;
367 value = error.str();
368 return Token::Error;
369 } else {
370 exp_index = m_index;
371 ++m_index; // Skip this character
372 }
373 break;
374
375 case '+':
376 case '-':
377 // The '+' and '-' can only come after an exponent character...
378 if (exp_index == m_index - 1) {
379 ++m_index; // Skip the exponent sign character
380 } else {
381 error << "error: unexpected " << next_ch << " character at offset "
382 << start_index;
383 value = error.str();
384 return Token::Error;
385 }
386 break;
387
388 default:
389 done = true;
390 break;
391 }
Todd Fiala75930012016-08-19 04:21:48 +0000392 }
Todd Fiala75930012016-08-19 04:21:48 +0000393
Kate Stoneb9c1b512016-09-06 20:57:50 +0000394 if (m_index > start_index) {
395 value = m_packet.substr(start_index, m_index - start_index);
396 if (got_decimal_point) {
397 if (exp_index != 0) {
398 // We have an exponent, make sure we got exponent digits
399 if (got_exp_digits) {
400 return Token::Float;
401 } else {
402 error << "error: got exponent character but no exponent digits at "
403 "offset in float value \""
404 << value.c_str() << "\"";
405 value = error.str();
406 return Token::Error;
407 }
408 } else {
409 // No exponent, but we need at least one decimal after the decimal
410 // point
411 if (got_frac_digits) {
412 return Token::Float;
413 } else {
414 error << "error: no digits after decimal point \"" << value.c_str()
415 << "\"";
416 value = error.str();
417 return Token::Error;
418 }
Todd Fiala75930012016-08-19 04:21:48 +0000419 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000420 } else {
421 // No decimal point
422 if (got_int_digits) {
423 // We need at least some integer digits to make an integer
424 return Token::Integer;
425 } else {
426 error << "error: no digits negate sign \"" << value.c_str() << "\"";
427 value = error.str();
428 return Token::Error;
Todd Fiala75930012016-08-19 04:21:48 +0000429 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000430 }
431 } else {
432 error << "error: invalid number found at offset " << start_index;
433 value = error.str();
434 return Token::Error;
Todd Fiala75930012016-08-19 04:21:48 +0000435 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000436 } break;
437 default:
438 break;
439 }
440 error << "error: failed to parse token at offset " << start_index
441 << " (around character '" << ch << "')";
442 value = error.str();
443 return Token::Error;
Todd Fiala75930012016-08-19 04:21:48 +0000444}
445
Kate Stoneb9c1b512016-09-06 20:57:50 +0000446int JSONParser::GetEscapedChar(bool &was_escaped) {
447 was_escaped = false;
448 const char ch = GetChar();
449 if (ch == '\\') {
450 was_escaped = true;
451 const char ch2 = GetChar();
452 switch (ch2) {
453 case '"':
454 case '\\':
455 case '/':
456 default:
457 break;
Todd Fiala75930012016-08-19 04:21:48 +0000458
Kate Stoneb9c1b512016-09-06 20:57:50 +0000459 case 'b':
460 return '\b';
461 case 'f':
462 return '\f';
463 case 'n':
464 return '\n';
465 case 'r':
466 return '\r';
467 case 't':
468 return '\t';
469 case 'u': {
470 const int hi_byte = DecodeHexU8();
471 const int lo_byte = DecodeHexU8();
472 if (hi_byte >= 0 && lo_byte >= 0)
473 return hi_byte << 8 | lo_byte;
474 return -1;
475 } break;
476 }
477 return ch2;
478 }
479 return ch;
480}
481
482JSONValue::SP JSONParser::ParseJSONObject() {
483 // The "JSONParser::Token::ObjectStart" token should have already been
484 // consumed
485 // by the time this function is called
486 std::unique_ptr<JSONObject> dict_up(new JSONObject());
487
488 std::string value;
489 std::string key;
490 while (1) {
491 JSONParser::Token token = GetToken(value);
492
493 if (token == JSONParser::Token::String) {
494 key.swap(value);
495 token = GetToken(value);
496 if (token == JSONParser::Token::Colon) {
Todd Fiala75930012016-08-19 04:21:48 +0000497 JSONValue::SP value_sp = ParseJSONValue();
498 if (value_sp)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000499 dict_up->SetObject(key, value_sp);
Todd Fiala75930012016-08-19 04:21:48 +0000500 else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000501 break;
502 }
503 } else if (token == JSONParser::Token::ObjectEnd) {
504 return JSONValue::SP(dict_up.release());
505 } else if (token == JSONParser::Token::Comma) {
506 continue;
507 } else {
508 break;
Todd Fiala75930012016-08-19 04:21:48 +0000509 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000510 }
511 return JSONValue::SP();
Todd Fiala75930012016-08-19 04:21:48 +0000512}
513
Kate Stoneb9c1b512016-09-06 20:57:50 +0000514JSONValue::SP JSONParser::ParseJSONArray() {
515 // The "JSONParser::Token::ObjectStart" token should have already been
516 // consumed
517 // by the time this function is called
518 std::unique_ptr<JSONArray> array_up(new JSONArray());
Todd Fiala75930012016-08-19 04:21:48 +0000519
Kate Stoneb9c1b512016-09-06 20:57:50 +0000520 std::string value;
521 std::string key;
522 while (1) {
523 JSONValue::SP value_sp = ParseJSONValue();
524 if (value_sp)
525 array_up->AppendObject(value_sp);
526 else
527 break;
Todd Fiala75930012016-08-19 04:21:48 +0000528
Kate Stoneb9c1b512016-09-06 20:57:50 +0000529 JSONParser::Token token = GetToken(value);
530 if (token == JSONParser::Token::Comma) {
531 continue;
532 } else if (token == JSONParser::Token::ArrayEnd) {
533 return JSONValue::SP(array_up.release());
534 } else {
535 break;
Todd Fiala75930012016-08-19 04:21:48 +0000536 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000537 }
538 return JSONValue::SP();
539}
540
541JSONValue::SP JSONParser::ParseJSONValue() {
542 std::string value;
543 const JSONParser::Token token = GetToken(value);
544 switch (token) {
545 case JSONParser::Token::ObjectStart:
546 return ParseJSONObject();
547
548 case JSONParser::Token::ArrayStart:
549 return ParseJSONArray();
550
551 case JSONParser::Token::Integer: {
552 if (value.front() == '-') {
553 bool success = false;
554 int64_t sval = StringConvert::ToSInt64(value.c_str(), 0, 0, &success);
555 if (success)
556 return JSONValue::SP(new JSONNumber(sval));
557 } else {
558 bool success = false;
559 uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success);
560 if (success)
561 return JSONValue::SP(new JSONNumber(uval));
562 }
563 } break;
564
565 case JSONParser::Token::Float: {
566 bool success = false;
567 double val = StringConvert::ToDouble(value.c_str(), 0.0, &success);
568 if (success)
569 return JSONValue::SP(new JSONNumber(val));
570 } break;
571
572 case JSONParser::Token::String:
573 return JSONValue::SP(new JSONString(value));
574
575 case JSONParser::Token::True:
576 return JSONValue::SP(new JSONTrue());
577
578 case JSONParser::Token::False:
579 return JSONValue::SP(new JSONFalse());
580
581 case JSONParser::Token::Null:
582 return JSONValue::SP(new JSONNull());
583
584 default:
585 break;
586 }
587 return JSONValue::SP();
Todd Fiala75930012016-08-19 04:21:48 +0000588}