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 "JSON.h" 11 12 // C includes 13 #include <assert.h> 14 #include <limits.h> 15 16 // C++ includes 17 #include <iomanip> 18 #include <sstream> 19 #include "lldb/Host/StringConvert.h" 20 21 using namespace lldb_private; 22 23 std::string 24 JSONString::json_string_quote_metachars (const std::string &s) 25 { 26 if (s.find('"') == std::string::npos) 27 return s; 28 29 std::string output; 30 const size_t s_size = s.size(); 31 const char *s_chars = s.c_str(); 32 for (size_t i = 0; i < s_size; i++) 33 { 34 unsigned char ch = *(s_chars + i); 35 if (ch == '"') 36 { 37 output.push_back ('\\'); 38 } 39 output.push_back (ch); 40 } 41 return output; 42 } 43 44 JSONString::JSONString () : 45 JSONValue(JSONValue::Kind::String), 46 m_data() 47 { 48 } 49 50 JSONString::JSONString (const char* s) : 51 JSONValue(JSONValue::Kind::String), 52 m_data(s ? s : "") 53 { 54 } 55 56 JSONString::JSONString (const std::string& s) : 57 JSONValue(JSONValue::Kind::String), 58 m_data(s) 59 { 60 } 61 62 void 63 JSONString::Write (std::ostream& s) 64 { 65 s << "\"" << json_string_quote_metachars(m_data).c_str() <<"\""; 66 } 67 68 uint64_t 69 JSONNumber::GetAsUnsigned() const 70 { 71 switch (m_data_type) 72 { 73 case DataType::Unsigned: 74 return m_data.m_unsigned; 75 case DataType::Signed: 76 return (uint64_t)m_data.m_signed; 77 case DataType::Double: 78 return (uint64_t)m_data.m_double; 79 } 80 assert("Unhandled data type"); 81 } 82 83 int64_t 84 JSONNumber::GetAsSigned() const 85 { 86 switch (m_data_type) 87 { 88 case DataType::Unsigned: 89 return (int64_t)m_data.m_unsigned; 90 case DataType::Signed: 91 return m_data.m_signed; 92 case DataType::Double: 93 return (int64_t)m_data.m_double; 94 } 95 assert("Unhandled data type"); 96 } 97 98 double 99 JSONNumber::GetAsDouble() const 100 { 101 switch (m_data_type) 102 { 103 case DataType::Unsigned: 104 return (double)m_data.m_unsigned; 105 case DataType::Signed: 106 return (double)m_data.m_signed; 107 case DataType::Double: 108 return m_data.m_double; 109 } 110 assert("Unhandled data type"); 111 } 112 113 void 114 JSONNumber::Write (std::ostream& s) 115 { 116 switch (m_data_type) 117 { 118 case DataType::Unsigned: 119 s << m_data.m_unsigned; 120 break; 121 case DataType::Signed: 122 s << m_data.m_signed; 123 break; 124 case DataType::Double: 125 // Set max precision to emulate %g. 126 s << std::setprecision(std::numeric_limits<double>::digits10 + 1); 127 s << m_data.m_double; 128 break; 129 } 130 } 131 132 JSONTrue::JSONTrue () : 133 JSONValue(JSONValue::Kind::True) 134 { 135 } 136 137 void 138 JSONTrue::Write(std::ostream& s) 139 { 140 s << "true"; 141 } 142 143 JSONFalse::JSONFalse () : 144 JSONValue(JSONValue::Kind::False) 145 { 146 } 147 148 void 149 JSONFalse::Write(std::ostream& s) 150 { 151 s << "false"; 152 } 153 154 JSONNull::JSONNull () : 155 JSONValue(JSONValue::Kind::Null) 156 { 157 } 158 159 void 160 JSONNull::Write(std::ostream& s) 161 { 162 s << "null"; 163 } 164 165 JSONObject::JSONObject () : 166 JSONValue(JSONValue::Kind::Object) 167 { 168 } 169 170 void 171 JSONObject::Write (std::ostream& s) 172 { 173 bool first = true; 174 s << '{'; 175 auto iter = m_elements.begin(), end = m_elements.end(); 176 for (;iter != end; iter++) 177 { 178 if (first) 179 first = false; 180 else 181 s << ','; 182 JSONString key(iter->first); 183 JSONValue::SP value(iter->second); 184 key.Write(s); 185 s << ':'; 186 value->Write(s); 187 } 188 s << '}'; 189 } 190 191 bool 192 JSONObject::SetObject (const std::string& key, 193 JSONValue::SP value) 194 { 195 if (key.empty() || nullptr == value.get()) 196 return false; 197 m_elements[key] = value; 198 return true; 199 } 200 201 JSONValue::SP 202 JSONObject::GetObject (const std::string& key) const 203 { 204 auto iter = m_elements.find(key), end = m_elements.end(); 205 if (iter == end) 206 return JSONValue::SP(); 207 return iter->second; 208 } 209 210 bool 211 JSONObject::GetObjectAsBool (const std::string& key, bool& value) const 212 { 213 auto value_sp = GetObject(key); 214 if (!value_sp) 215 { 216 // The given key doesn't exist, so we have no value. 217 return false; 218 } 219 220 if (JSONTrue::classof(value_sp.get())) 221 { 222 // We have the value, and it is true. 223 value = true; 224 return true; 225 } 226 else if (JSONFalse::classof(value_sp.get())) 227 { 228 // We have the value, and it is false. 229 value = false; 230 return true; 231 } 232 else 233 { 234 // We don't have a valid bool value for the given key. 235 return false; 236 } 237 } 238 239 bool 240 JSONObject::GetObjectAsString (const std::string& key, std::string& value) const 241 { 242 auto value_sp = GetObject(key); 243 if (!value_sp) 244 { 245 // The given key doesn't exist, so we have no value. 246 return false; 247 } 248 249 if (!JSONString::classof(value_sp.get())) 250 return false; 251 252 value = static_cast<JSONString*>(value_sp.get())->GetData(); 253 return true; 254 } 255 256 JSONArray::JSONArray () : 257 JSONValue(JSONValue::Kind::Array) 258 { 259 } 260 261 void 262 JSONArray::Write (std::ostream& s) 263 { 264 bool first = true; 265 s << '['; 266 auto iter = m_elements.begin(), end = m_elements.end(); 267 for (;iter != end; iter++) 268 { 269 if (first) 270 first = false; 271 else 272 s << ','; 273 (*iter)->Write(s); 274 } 275 s << ']'; 276 } 277 278 bool 279 JSONArray::SetObject (Index i, 280 JSONValue::SP value) 281 { 282 if (value.get() == nullptr) 283 return false; 284 if (i < m_elements.size()) 285 { 286 m_elements[i] = value; 287 return true; 288 } 289 if (i == m_elements.size()) 290 { 291 m_elements.push_back(value); 292 return true; 293 } 294 return false; 295 } 296 297 bool 298 JSONArray::AppendObject (JSONValue::SP value) 299 { 300 if (value.get() == nullptr) 301 return false; 302 m_elements.push_back(value); 303 return true; 304 } 305 306 JSONValue::SP 307 JSONArray::GetObject (Index i) 308 { 309 if (i < m_elements.size()) 310 return m_elements[i]; 311 return JSONValue::SP(); 312 } 313 314 JSONArray::Size 315 JSONArray::GetNumElements () 316 { 317 return m_elements.size(); 318 } 319 320 321 JSONParser::JSONParser (const char *cstr) : 322 StringExtractor(cstr) 323 { 324 } 325 326 JSONParser::Token 327 JSONParser::GetToken (std::string &value) 328 { 329 std::ostringstream error; 330 331 value.clear(); 332 SkipSpaces (); 333 const uint64_t start_index = m_index; 334 const char ch = GetChar(); 335 switch (ch) 336 { 337 case '{': return Token::ObjectStart; 338 case '}': return Token::ObjectEnd; 339 case '[': return Token::ArrayStart; 340 case ']': return Token::ArrayEnd; 341 case ',': return Token::Comma; 342 case ':': return Token::Colon; 343 case '\0': return Token::EndOfFile; 344 case 't': 345 if (GetChar() == 'r') 346 if (GetChar() == 'u') 347 if (GetChar() == 'e') 348 return Token::True; 349 break; 350 351 case 'f': 352 if (GetChar() == 'a') 353 if (GetChar() == 'l') 354 if (GetChar() == 's') 355 if (GetChar() == 'e') 356 return Token::False; 357 break; 358 359 case 'n': 360 if (GetChar() == 'u') 361 if (GetChar() == 'l') 362 if (GetChar() == 'l') 363 return Token::Null; 364 break; 365 366 case '"': 367 { 368 while (1) 369 { 370 bool was_escaped = false; 371 int escaped_ch = GetEscapedChar(was_escaped); 372 if (escaped_ch == -1) 373 { 374 error << "error: an error occurred getting a character from offset " <<start_index; 375 value = std::move(error.str()); 376 return Token::Error; 377 378 } 379 else 380 { 381 const bool is_end_quote = escaped_ch == '"'; 382 const bool is_null = escaped_ch == 0; 383 if (was_escaped || (!is_end_quote && !is_null)) 384 { 385 if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX) 386 { 387 value.append(1, (char)escaped_ch); 388 } 389 else 390 { 391 error << "error: wide character support is needed for unicode character 0x" << std::setprecision(4) << std::hex << escaped_ch; 392 error << " at offset " << start_index; 393 value = std::move(error.str()); 394 return Token::Error; 395 } 396 } 397 else if (is_end_quote) 398 { 399 return Token::String; 400 } 401 else if (is_null) 402 { 403 value = "error: missing end quote for string"; 404 return Token::Error; 405 } 406 } 407 } 408 } 409 break; 410 411 case '-': 412 case '0': 413 case '1': 414 case '2': 415 case '3': 416 case '4': 417 case '5': 418 case '6': 419 case '7': 420 case '8': 421 case '9': 422 { 423 bool done = false; 424 bool got_decimal_point = false; 425 uint64_t exp_index = 0; 426 bool got_int_digits = (ch >= '0') && (ch <= '9'); 427 bool got_frac_digits = false; 428 bool got_exp_digits = false; 429 while (!done) 430 { 431 const char next_ch = PeekChar(); 432 switch (next_ch) 433 { 434 case '0': 435 case '1': 436 case '2': 437 case '3': 438 case '4': 439 case '5': 440 case '6': 441 case '7': 442 case '8': 443 case '9': 444 if (exp_index != 0) 445 { 446 got_exp_digits = true; 447 } 448 else if (got_decimal_point) 449 { 450 got_frac_digits = true; 451 } 452 else 453 { 454 got_int_digits = true; 455 } 456 ++m_index; // Skip this character 457 break; 458 459 case '.': 460 if (got_decimal_point) 461 { 462 error << "error: extra decimal point found at offset " << start_index; 463 value = std::move(error.str()); 464 return Token::Error; 465 } 466 else 467 { 468 got_decimal_point = true; 469 ++m_index; // Skip this character 470 } 471 break; 472 473 case 'e': 474 case 'E': 475 if (exp_index != 0) 476 { 477 error << "error: extra exponent character found at offset " << start_index; 478 value = std::move(error.str()); 479 return Token::Error; 480 } 481 else 482 { 483 exp_index = m_index; 484 ++m_index; // Skip this character 485 } 486 break; 487 488 case '+': 489 case '-': 490 // The '+' and '-' can only come after an exponent character... 491 if (exp_index == m_index - 1) 492 { 493 ++m_index; // Skip the exponent sign character 494 } 495 else 496 { 497 error << "error: unexpected " << next_ch << " character at offset " << start_index; 498 value = std::move(error.str()); 499 return Token::Error; 500 } 501 break; 502 503 default: 504 done = true; 505 break; 506 } 507 } 508 509 if (m_index > start_index) 510 { 511 value = m_packet.substr(start_index, m_index - start_index); 512 if (got_decimal_point) 513 { 514 if (exp_index != 0) 515 { 516 // We have an exponent, make sure we got exponent digits 517 if (got_exp_digits) 518 { 519 return Token::Float; 520 } 521 else 522 { 523 error << "error: got exponent character but no exponent digits at offset in float value \"" << value.c_str() << "\""; 524 value = std::move(error.str()); 525 return Token::Error; 526 } 527 } 528 else 529 { 530 // No exponent, but we need at least one decimal after the decimal point 531 if (got_frac_digits) 532 { 533 return Token::Float; 534 } 535 else 536 { 537 error << "error: no digits after decimal point \"" << value.c_str() << "\""; 538 value = std::move(error.str()); 539 return Token::Error; 540 } 541 } 542 } 543 else 544 { 545 // No decimal point 546 if (got_int_digits) 547 { 548 // We need at least some integer digits to make an integer 549 return Token::Integer; 550 } 551 else 552 { 553 error << "error: no digits negate sign \"" << value.c_str() << "\""; 554 value = std::move(error.str()); 555 return Token::Error; 556 } 557 } 558 } 559 else 560 { 561 error << "error: invalid number found at offset " << start_index; 562 value = std::move(error.str()); 563 return Token::Error; 564 } 565 } 566 break; 567 default: 568 break; 569 } 570 error << "error: failed to parse token at offset " << start_index << " (around character '" << ch << "')"; 571 value = std::move(error.str()); 572 return Token::Error; 573 } 574 575 int 576 JSONParser::GetEscapedChar(bool &was_escaped) 577 { 578 was_escaped = false; 579 const char ch = GetChar(); 580 if (ch == '\\') 581 { 582 was_escaped = true; 583 const char ch2 = GetChar(); 584 switch (ch2) 585 { 586 case '"': 587 case '\\': 588 case '/': 589 default: 590 break; 591 592 case 'b': return '\b'; 593 case 'f': return '\f'; 594 case 'n': return '\n'; 595 case 'r': return '\r'; 596 case 't': return '\t'; 597 case 'u': 598 { 599 const int hi_byte = DecodeHexU8(); 600 const int lo_byte = DecodeHexU8(); 601 if (hi_byte >=0 && lo_byte >= 0) 602 return hi_byte << 8 | lo_byte; 603 return -1; 604 } 605 break; 606 } 607 return ch2; 608 } 609 return ch; 610 } 611 612 JSONValue::SP 613 JSONParser::ParseJSONObject () 614 { 615 // The "JSONParser::Token::ObjectStart" token should have already been consumed 616 // by the time this function is called 617 std::unique_ptr<JSONObject> dict_up(new JSONObject()); 618 619 std::string value; 620 std::string key; 621 while (1) 622 { 623 JSONParser::Token token = GetToken(value); 624 625 if (token == JSONParser::Token::String) 626 { 627 key.swap(value); 628 token = GetToken(value); 629 if (token == JSONParser::Token::Colon) 630 { 631 JSONValue::SP value_sp = ParseJSONValue(); 632 if (value_sp) 633 dict_up->SetObject(key, value_sp); 634 else 635 break; 636 } 637 } 638 else if (token == JSONParser::Token::ObjectEnd) 639 { 640 return JSONValue::SP(dict_up.release()); 641 } 642 else if (token == JSONParser::Token::Comma) 643 { 644 continue; 645 } 646 else 647 { 648 break; 649 } 650 } 651 return JSONValue::SP(); 652 } 653 654 JSONValue::SP 655 JSONParser::ParseJSONArray () 656 { 657 // The "JSONParser::Token::ObjectStart" token should have already been consumed 658 // by the time this function is called 659 std::unique_ptr<JSONArray> array_up(new JSONArray()); 660 661 std::string value; 662 std::string key; 663 while (1) 664 { 665 JSONValue::SP value_sp = ParseJSONValue(); 666 if (value_sp) 667 array_up->AppendObject(value_sp); 668 else 669 break; 670 671 JSONParser::Token token = GetToken(value); 672 if (token == JSONParser::Token::Comma) 673 { 674 continue; 675 } 676 else if (token == JSONParser::Token::ArrayEnd) 677 { 678 return JSONValue::SP(array_up.release()); 679 } 680 else 681 { 682 break; 683 } 684 } 685 return JSONValue::SP(); 686 } 687 688 JSONValue::SP 689 JSONParser::ParseJSONValue () 690 { 691 std::string value; 692 const JSONParser::Token token = GetToken(value); 693 switch (token) 694 { 695 case JSONParser::Token::ObjectStart: 696 return ParseJSONObject(); 697 698 case JSONParser::Token::ArrayStart: 699 return ParseJSONArray(); 700 701 case JSONParser::Token::Integer: 702 { 703 if (value.front() == '-') 704 { 705 bool success = false; 706 int64_t sval = StringConvert::ToSInt64(value.c_str(), 0, 0, &success); 707 if (success) 708 return JSONValue::SP(new JSONNumber(sval)); 709 } 710 else 711 { 712 bool success = false; 713 uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success); 714 if (success) 715 return JSONValue::SP(new JSONNumber(uval)); 716 } 717 } 718 break; 719 720 case JSONParser::Token::Float: 721 { 722 bool success = false; 723 double val = StringConvert::ToDouble(value.c_str(), 0.0, &success); 724 if (success) 725 return JSONValue::SP(new JSONNumber(val)); 726 } 727 break; 728 729 case JSONParser::Token::String: 730 return JSONValue::SP(new JSONString(value)); 731 732 case JSONParser::Token::True: 733 return JSONValue::SP(new JSONTrue()); 734 735 case JSONParser::Token::False: 736 return JSONValue::SP(new JSONFalse()); 737 738 case JSONParser::Token::Null: 739 return JSONValue::SP(new JSONNull()); 740 741 default: 742 break; 743 } 744 return JSONValue::SP(); 745 746 } 747