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