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