blob: 439918b6fcc4d1275309207b4b42df0d68065836 [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 }
Todd Fiala75930012016-08-19 04:21:48 +000061}
62
Kate Stoneb9c1b512016-09-06 20:57:50 +000063int64_t JSONNumber::GetAsSigned() const {
64 switch (m_data_type) {
65 case DataType::Unsigned:
66 return (int64_t)m_data.m_unsigned;
67 case DataType::Signed:
68 return m_data.m_signed;
69 case DataType::Double:
70 return (int64_t)m_data.m_double;
71 }
Todd Fiala75930012016-08-19 04:21:48 +000072}
73
Kate Stoneb9c1b512016-09-06 20:57:50 +000074double JSONNumber::GetAsDouble() const {
75 switch (m_data_type) {
76 case DataType::Unsigned:
77 return (double)m_data.m_unsigned;
78 case DataType::Signed:
79 return (double)m_data.m_signed;
80 case DataType::Double:
81 return m_data.m_double;
82 }
Todd Fiala75930012016-08-19 04:21:48 +000083}
84
Kate Stoneb9c1b512016-09-06 20:57:50 +000085void JSONNumber::Write(std::ostream &s) {
86 switch (m_data_type) {
87 case DataType::Unsigned:
88 s << m_data.m_unsigned;
89 break;
90 case DataType::Signed:
91 s << m_data.m_signed;
92 break;
93 case DataType::Double:
94 // Set max precision to emulate %g.
95 s << std::setprecision(std::numeric_limits<double>::digits10 + 1);
96 s << m_data.m_double;
97 break;
98 }
Todd Fiala75930012016-08-19 04:21:48 +000099}
100
Kate Stoneb9c1b512016-09-06 20:57:50 +0000101JSONTrue::JSONTrue() : JSONValue(JSONValue::Kind::True) {}
Todd Fiala75930012016-08-19 04:21:48 +0000102
Kate Stoneb9c1b512016-09-06 20:57:50 +0000103void JSONTrue::Write(std::ostream &s) { s << "true"; }
Todd Fiala75930012016-08-19 04:21:48 +0000104
Kate Stoneb9c1b512016-09-06 20:57:50 +0000105JSONFalse::JSONFalse() : JSONValue(JSONValue::Kind::False) {}
Todd Fiala75930012016-08-19 04:21:48 +0000106
Kate Stoneb9c1b512016-09-06 20:57:50 +0000107void JSONFalse::Write(std::ostream &s) { s << "false"; }
Todd Fiala75930012016-08-19 04:21:48 +0000108
Kate Stoneb9c1b512016-09-06 20:57:50 +0000109JSONNull::JSONNull() : JSONValue(JSONValue::Kind::Null) {}
Todd Fiala75930012016-08-19 04:21:48 +0000110
Kate Stoneb9c1b512016-09-06 20:57:50 +0000111void JSONNull::Write(std::ostream &s) { s << "null"; }
Todd Fiala75930012016-08-19 04:21:48 +0000112
Kate Stoneb9c1b512016-09-06 20:57:50 +0000113JSONObject::JSONObject() : JSONValue(JSONValue::Kind::Object) {}
Todd Fiala75930012016-08-19 04:21:48 +0000114
Kate Stoneb9c1b512016-09-06 20:57:50 +0000115void JSONObject::Write(std::ostream &s) {
116 bool first = true;
117 s << '{';
118 auto iter = m_elements.begin(), end = m_elements.end();
119 for (; iter != end; iter++) {
120 if (first)
121 first = false;
Todd Fiala75930012016-08-19 04:21:48 +0000122 else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000123 s << ',';
124 JSONString key(iter->first);
125 JSONValue::SP value(iter->second);
126 key.Write(s);
127 s << ':';
128 value->Write(s);
129 }
130 s << '}';
Todd Fiala75930012016-08-19 04:21:48 +0000131}
132
Kate Stoneb9c1b512016-09-06 20:57:50 +0000133bool JSONObject::SetObject(const std::string &key, JSONValue::SP value) {
134 if (key.empty() || nullptr == value.get())
Todd Fiala75930012016-08-19 04:21:48 +0000135 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000136 m_elements[key] = value;
137 return true;
Todd Fiala75930012016-08-19 04:21:48 +0000138}
139
Kate Stoneb9c1b512016-09-06 20:57:50 +0000140JSONValue::SP JSONObject::GetObject(const std::string &key) const {
141 auto iter = m_elements.find(key), end = m_elements.end();
142 if (iter == end)
143 return JSONValue::SP();
144 return iter->second;
145}
146
147bool JSONObject::GetObjectAsBool(const std::string &key, bool &value) const {
148 auto value_sp = GetObject(key);
149 if (!value_sp) {
150 // The given key doesn't exist, so we have no value.
151 return false;
152 }
153
154 if (JSONTrue::classof(value_sp.get())) {
155 // We have the value, and it is true.
156 value = true;
157 return true;
158 } else if (JSONFalse::classof(value_sp.get())) {
159 // We have the value, and it is false.
160 value = false;
161 return true;
162 } else {
163 // We don't have a valid bool value for the given key.
164 return false;
165 }
166}
167
168bool JSONObject::GetObjectAsString(const std::string &key,
169 std::string &value) const {
170 auto value_sp = GetObject(key);
171 if (!value_sp) {
172 // The given key doesn't exist, so we have no value.
173 return false;
174 }
175
176 if (!JSONString::classof(value_sp.get()))
177 return false;
178
179 value = static_cast<JSONString *>(value_sp.get())->GetData();
180 return true;
181}
182
183JSONArray::JSONArray() : JSONValue(JSONValue::Kind::Array) {}
184
185void JSONArray::Write(std::ostream &s) {
186 bool first = true;
187 s << '[';
188 auto iter = m_elements.begin(), end = m_elements.end();
189 for (; iter != end; iter++) {
190 if (first)
191 first = false;
192 else
193 s << ',';
194 (*iter)->Write(s);
195 }
196 s << ']';
197}
198
199bool JSONArray::SetObject(Index i, JSONValue::SP value) {
200 if (value.get() == nullptr)
201 return false;
202 if (i < m_elements.size()) {
203 m_elements[i] = value;
204 return true;
205 }
206 if (i == m_elements.size()) {
Todd Fiala75930012016-08-19 04:21:48 +0000207 m_elements.push_back(value);
208 return true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000209 }
210 return false;
Todd Fiala75930012016-08-19 04:21:48 +0000211}
212
Kate Stoneb9c1b512016-09-06 20:57:50 +0000213bool JSONArray::AppendObject(JSONValue::SP value) {
214 if (value.get() == nullptr)
215 return false;
216 m_elements.push_back(value);
217 return true;
Todd Fiala75930012016-08-19 04:21:48 +0000218}
219
Kate Stoneb9c1b512016-09-06 20:57:50 +0000220JSONValue::SP JSONArray::GetObject(Index i) {
221 if (i < m_elements.size())
222 return m_elements[i];
223 return JSONValue::SP();
Todd Fiala75930012016-08-19 04:21:48 +0000224}
225
Kate Stoneb9c1b512016-09-06 20:57:50 +0000226JSONArray::Size JSONArray::GetNumElements() { return m_elements.size(); }
Todd Fiala75930012016-08-19 04:21:48 +0000227
Kate Stoneb9c1b512016-09-06 20:57:50 +0000228JSONParser::JSONParser(const char *cstr) : StdStringExtractor(cstr) {}
Todd Fiala75930012016-08-19 04:21:48 +0000229
Kate Stoneb9c1b512016-09-06 20:57:50 +0000230JSONParser::Token JSONParser::GetToken(std::string &value) {
231 std::ostringstream error;
Todd Fiala75930012016-08-19 04:21:48 +0000232
Kate Stoneb9c1b512016-09-06 20:57:50 +0000233 value.clear();
234 SkipSpaces();
235 const uint64_t start_index = m_index;
236 const char ch = GetChar();
237 switch (ch) {
238 case '{':
239 return Token::ObjectStart;
240 case '}':
241 return Token::ObjectEnd;
242 case '[':
243 return Token::ArrayStart;
244 case ']':
245 return Token::ArrayEnd;
246 case ',':
247 return Token::Comma;
248 case ':':
249 return Token::Colon;
250 case '\0':
251 return Token::EndOfFile;
252 case 't':
253 if (GetChar() == 'r')
254 if (GetChar() == 'u')
255 if (GetChar() == 'e')
256 return Token::True;
257 break;
Todd Fiala75930012016-08-19 04:21:48 +0000258
Kate Stoneb9c1b512016-09-06 20:57:50 +0000259 case 'f':
260 if (GetChar() == 'a')
261 if (GetChar() == 'l')
262 if (GetChar() == 's')
263 if (GetChar() == 'e')
264 return Token::False;
265 break;
Todd Fiala75930012016-08-19 04:21:48 +0000266
Kate Stoneb9c1b512016-09-06 20:57:50 +0000267 case 'n':
268 if (GetChar() == 'u')
269 if (GetChar() == 'l')
270 if (GetChar() == 'l')
271 return Token::Null;
272 break;
Todd Fiala75930012016-08-19 04:21:48 +0000273
Kate Stoneb9c1b512016-09-06 20:57:50 +0000274 case '"': {
275 while (1) {
276 bool was_escaped = false;
277 int escaped_ch = GetEscapedChar(was_escaped);
278 if (escaped_ch == -1) {
279 error << "error: an error occurred getting a character from offset "
280 << start_index;
281 value = error.str();
Zachary Turner97206d52017-05-12 04:51:55 +0000282 return Token::Status;
Todd Fiala75930012016-08-19 04:21:48 +0000283
Kate Stoneb9c1b512016-09-06 20:57:50 +0000284 } else {
285 const bool is_end_quote = escaped_ch == '"';
286 const bool is_null = escaped_ch == 0;
287 if (was_escaped || (!is_end_quote && !is_null)) {
288 if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX) {
289 value.append(1, (char)escaped_ch);
290 } else {
291 error << "error: wide character support is needed for unicode "
292 "character 0x"
293 << std::setprecision(4) << std::hex << escaped_ch;
294 error << " at offset " << start_index;
295 value = error.str();
Zachary Turner97206d52017-05-12 04:51:55 +0000296 return Token::Status;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000297 }
298 } else if (is_end_quote) {
299 return Token::String;
300 } else if (is_null) {
301 value = "error: missing end quote for string";
Zachary Turner97206d52017-05-12 04:51:55 +0000302 return Token::Status;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000303 }
304 }
Todd Fiala75930012016-08-19 04:21:48 +0000305 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000306 } break;
Todd Fiala75930012016-08-19 04:21:48 +0000307
Kate Stoneb9c1b512016-09-06 20:57:50 +0000308 case '-':
309 case '0':
310 case '1':
311 case '2':
312 case '3':
313 case '4':
314 case '5':
315 case '6':
316 case '7':
317 case '8':
318 case '9': {
319 bool done = false;
320 bool got_decimal_point = false;
321 uint64_t exp_index = 0;
322 bool got_int_digits = (ch >= '0') && (ch <= '9');
323 bool got_frac_digits = false;
324 bool got_exp_digits = false;
325 while (!done) {
326 const char next_ch = PeekChar();
327 switch (next_ch) {
328 case '0':
329 case '1':
330 case '2':
331 case '3':
332 case '4':
333 case '5':
334 case '6':
335 case '7':
336 case '8':
337 case '9':
338 if (exp_index != 0) {
339 got_exp_digits = true;
340 } else if (got_decimal_point) {
341 got_frac_digits = true;
342 } else {
343 got_int_digits = true;
Todd Fiala75930012016-08-19 04:21:48 +0000344 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000345 ++m_index; // Skip this character
346 break;
347
348 case '.':
349 if (got_decimal_point) {
350 error << "error: extra decimal point found at offset " << start_index;
351 value = error.str();
Zachary Turner97206d52017-05-12 04:51:55 +0000352 return Token::Status;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000353 } else {
354 got_decimal_point = true;
355 ++m_index; // Skip this character
356 }
357 break;
358
359 case 'e':
360 case 'E':
361 if (exp_index != 0) {
362 error << "error: extra exponent character found at offset "
363 << start_index;
364 value = error.str();
Zachary Turner97206d52017-05-12 04:51:55 +0000365 return Token::Status;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000366 } else {
367 exp_index = m_index;
368 ++m_index; // Skip this character
369 }
370 break;
371
372 case '+':
373 case '-':
374 // The '+' and '-' can only come after an exponent character...
375 if (exp_index == m_index - 1) {
376 ++m_index; // Skip the exponent sign character
377 } else {
378 error << "error: unexpected " << next_ch << " character at offset "
379 << start_index;
380 value = error.str();
Zachary Turner97206d52017-05-12 04:51:55 +0000381 return Token::Status;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000382 }
383 break;
384
385 default:
386 done = true;
387 break;
388 }
Todd Fiala75930012016-08-19 04:21:48 +0000389 }
Todd Fiala75930012016-08-19 04:21:48 +0000390
Kate Stoneb9c1b512016-09-06 20:57:50 +0000391 if (m_index > start_index) {
392 value = m_packet.substr(start_index, m_index - start_index);
393 if (got_decimal_point) {
394 if (exp_index != 0) {
395 // We have an exponent, make sure we got exponent digits
396 if (got_exp_digits) {
397 return Token::Float;
398 } else {
399 error << "error: got exponent character but no exponent digits at "
400 "offset in float value \""
401 << value.c_str() << "\"";
402 value = error.str();
Zachary Turner97206d52017-05-12 04:51:55 +0000403 return Token::Status;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000404 }
405 } else {
406 // No exponent, but we need at least one decimal after the decimal
407 // point
408 if (got_frac_digits) {
409 return Token::Float;
410 } else {
411 error << "error: no digits after decimal point \"" << value.c_str()
412 << "\"";
413 value = error.str();
Zachary Turner97206d52017-05-12 04:51:55 +0000414 return Token::Status;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000415 }
Todd Fiala75930012016-08-19 04:21:48 +0000416 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000417 } else {
418 // No decimal point
419 if (got_int_digits) {
420 // We need at least some integer digits to make an integer
421 return Token::Integer;
422 } else {
423 error << "error: no digits negate sign \"" << value.c_str() << "\"";
424 value = error.str();
Zachary Turner97206d52017-05-12 04:51:55 +0000425 return Token::Status;
Todd Fiala75930012016-08-19 04:21:48 +0000426 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000427 }
428 } else {
429 error << "error: invalid number found at offset " << start_index;
430 value = error.str();
Zachary Turner97206d52017-05-12 04:51:55 +0000431 return Token::Status;
Todd Fiala75930012016-08-19 04:21:48 +0000432 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000433 } break;
434 default:
435 break;
436 }
437 error << "error: failed to parse token at offset " << start_index
438 << " (around character '" << ch << "')";
439 value = error.str();
Zachary Turner97206d52017-05-12 04:51:55 +0000440 return Token::Status;
Todd Fiala75930012016-08-19 04:21:48 +0000441}
442
Kate Stoneb9c1b512016-09-06 20:57:50 +0000443int JSONParser::GetEscapedChar(bool &was_escaped) {
444 was_escaped = false;
445 const char ch = GetChar();
446 if (ch == '\\') {
447 was_escaped = true;
448 const char ch2 = GetChar();
449 switch (ch2) {
450 case '"':
451 case '\\':
452 case '/':
453 default:
454 break;
Todd Fiala75930012016-08-19 04:21:48 +0000455
Kate Stoneb9c1b512016-09-06 20:57:50 +0000456 case 'b':
457 return '\b';
458 case 'f':
459 return '\f';
460 case 'n':
461 return '\n';
462 case 'r':
463 return '\r';
464 case 't':
465 return '\t';
466 case 'u': {
467 const int hi_byte = DecodeHexU8();
468 const int lo_byte = DecodeHexU8();
469 if (hi_byte >= 0 && lo_byte >= 0)
470 return hi_byte << 8 | lo_byte;
471 return -1;
472 } break;
473 }
474 return ch2;
475 }
476 return ch;
477}
478
479JSONValue::SP JSONParser::ParseJSONObject() {
480 // The "JSONParser::Token::ObjectStart" token should have already been
481 // consumed
482 // by the time this function is called
483 std::unique_ptr<JSONObject> dict_up(new JSONObject());
484
485 std::string value;
486 std::string key;
487 while (1) {
488 JSONParser::Token token = GetToken(value);
489
490 if (token == JSONParser::Token::String) {
491 key.swap(value);
492 token = GetToken(value);
493 if (token == JSONParser::Token::Colon) {
Todd Fiala75930012016-08-19 04:21:48 +0000494 JSONValue::SP value_sp = ParseJSONValue();
495 if (value_sp)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000496 dict_up->SetObject(key, value_sp);
Todd Fiala75930012016-08-19 04:21:48 +0000497 else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000498 break;
499 }
500 } else if (token == JSONParser::Token::ObjectEnd) {
501 return JSONValue::SP(dict_up.release());
502 } else if (token == JSONParser::Token::Comma) {
503 continue;
504 } else {
505 break;
Todd Fiala75930012016-08-19 04:21:48 +0000506 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000507 }
508 return JSONValue::SP();
Todd Fiala75930012016-08-19 04:21:48 +0000509}
510
Kate Stoneb9c1b512016-09-06 20:57:50 +0000511JSONValue::SP JSONParser::ParseJSONArray() {
512 // The "JSONParser::Token::ObjectStart" token should have already been
513 // consumed
514 // by the time this function is called
515 std::unique_ptr<JSONArray> array_up(new JSONArray());
Todd Fiala75930012016-08-19 04:21:48 +0000516
Kate Stoneb9c1b512016-09-06 20:57:50 +0000517 std::string value;
518 std::string key;
519 while (1) {
520 JSONValue::SP value_sp = ParseJSONValue();
521 if (value_sp)
522 array_up->AppendObject(value_sp);
523 else
524 break;
Todd Fiala75930012016-08-19 04:21:48 +0000525
Kate Stoneb9c1b512016-09-06 20:57:50 +0000526 JSONParser::Token token = GetToken(value);
527 if (token == JSONParser::Token::Comma) {
528 continue;
529 } else if (token == JSONParser::Token::ArrayEnd) {
530 return JSONValue::SP(array_up.release());
531 } else {
532 break;
Todd Fiala75930012016-08-19 04:21:48 +0000533 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000534 }
535 return JSONValue::SP();
536}
537
538JSONValue::SP JSONParser::ParseJSONValue() {
539 std::string value;
540 const JSONParser::Token token = GetToken(value);
541 switch (token) {
542 case JSONParser::Token::ObjectStart:
543 return ParseJSONObject();
544
545 case JSONParser::Token::ArrayStart:
546 return ParseJSONArray();
547
548 case JSONParser::Token::Integer: {
549 if (value.front() == '-') {
550 bool success = false;
551 int64_t sval = StringConvert::ToSInt64(value.c_str(), 0, 0, &success);
552 if (success)
553 return JSONValue::SP(new JSONNumber(sval));
554 } else {
555 bool success = false;
556 uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success);
557 if (success)
558 return JSONValue::SP(new JSONNumber(uval));
559 }
560 } break;
561
562 case JSONParser::Token::Float: {
563 bool success = false;
564 double val = StringConvert::ToDouble(value.c_str(), 0.0, &success);
565 if (success)
566 return JSONValue::SP(new JSONNumber(val));
567 } break;
568
569 case JSONParser::Token::String:
570 return JSONValue::SP(new JSONString(value));
571
572 case JSONParser::Token::True:
573 return JSONValue::SP(new JSONTrue());
574
575 case JSONParser::Token::False:
576 return JSONValue::SP(new JSONFalse());
577
578 case JSONParser::Token::Null:
579 return JSONValue::SP(new JSONNull());
580
581 default:
582 break;
583 }
584 return JSONValue::SP();
Todd Fiala75930012016-08-19 04:21:48 +0000585}