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 "lldb/Host/StringConvert.h" 18 #include <iomanip> 19 #include <sstream> 20 21 using namespace lldb_private; 22 23 std::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('\\'); 34 } 35 output.push_back(ch); 36 } 37 return output; 38 } 39 40 JSONString::JSONString() : JSONValue(JSONValue::Kind::String), m_data() {} 41 42 JSONString::JSONString(const char *s) 43 : JSONValue(JSONValue::Kind::String), m_data(s ? s : "") {} 44 45 JSONString::JSONString(const std::string &s) 46 : JSONValue(JSONValue::Kind::String), m_data(s) {} 47 48 void JSONString::Write(std::ostream &s) { 49 s << "\"" << json_string_quote_metachars(m_data).c_str() << "\""; 50 } 51 52 uint64_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"); 62 } 63 64 int64_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"); 74 } 75 76 double 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"); 86 } 87 88 void 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 } 102 } 103 104 JSONTrue::JSONTrue() : JSONValue(JSONValue::Kind::True) {} 105 106 void JSONTrue::Write(std::ostream &s) { s << "true"; } 107 108 JSONFalse::JSONFalse() : JSONValue(JSONValue::Kind::False) {} 109 110 void JSONFalse::Write(std::ostream &s) { s << "false"; } 111 112 JSONNull::JSONNull() : JSONValue(JSONValue::Kind::Null) {} 113 114 void JSONNull::Write(std::ostream &s) { s << "null"; } 115 116 JSONObject::JSONObject() : JSONValue(JSONValue::Kind::Object) {} 117 118 void 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; 125 else 126 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 << '}'; 134 } 135 136 bool JSONObject::SetObject(const std::string &key, JSONValue::SP value) { 137 if (key.empty() || nullptr == value.get()) 138 return false; 139 m_elements[key] = value; 140 return true; 141 } 142 143 JSONValue::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 150 bool 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 171 bool 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 186 JSONArray::JSONArray() : JSONValue(JSONValue::Kind::Array) {} 187 188 void 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 202 bool 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()) { 210 m_elements.push_back(value); 211 return true; 212 } 213 return false; 214 } 215 216 bool JSONArray::AppendObject(JSONValue::SP value) { 217 if (value.get() == nullptr) 218 return false; 219 m_elements.push_back(value); 220 return true; 221 } 222 223 JSONValue::SP JSONArray::GetObject(Index i) { 224 if (i < m_elements.size()) 225 return m_elements[i]; 226 return JSONValue::SP(); 227 } 228 229 JSONArray::Size JSONArray::GetNumElements() { return m_elements.size(); } 230 231 JSONParser::JSONParser(const char *cstr) : StdStringExtractor(cstr) {} 232 233 JSONParser::Token JSONParser::GetToken(std::string &value) { 234 std::ostringstream error; 235 236 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; 261 262 case 'f': 263 if (GetChar() == 'a') 264 if (GetChar() == 'l') 265 if (GetChar() == 's') 266 if (GetChar() == 'e') 267 return Token::False; 268 break; 269 270 case 'n': 271 if (GetChar() == 'u') 272 if (GetChar() == 'l') 273 if (GetChar() == 'l') 274 return Token::Null; 275 break; 276 277 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; 286 287 } 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 } 308 } 309 } break; 310 311 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; 347 } 348 ++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 } 392 } 393 394 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 } 419 } 420 } 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; 429 } 430 } 431 } else { 432 error << "error: invalid number found at offset " << start_index; 433 value = error.str(); 434 return Token::Error; 435 } 436 } 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; 444 } 445 446 int 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; 458 459 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 482 JSONValue::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) { 497 JSONValue::SP value_sp = ParseJSONValue(); 498 if (value_sp) 499 dict_up->SetObject(key, value_sp); 500 else 501 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; 509 } 510 } 511 return JSONValue::SP(); 512 } 513 514 JSONValue::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()); 519 520 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; 528 529 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; 536 } 537 } 538 return JSONValue::SP(); 539 } 540 541 JSONValue::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(); 588 } 589