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 } 62 63 int64_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 } 72 } 73 74 double 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 } 83 } 84 85 void 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 } 99 } 100 101 JSONTrue::JSONTrue() : JSONValue(JSONValue::Kind::True) {} 102 103 void JSONTrue::Write(std::ostream &s) { s << "true"; } 104 105 JSONFalse::JSONFalse() : JSONValue(JSONValue::Kind::False) {} 106 107 void JSONFalse::Write(std::ostream &s) { s << "false"; } 108 109 JSONNull::JSONNull() : JSONValue(JSONValue::Kind::Null) {} 110 111 void JSONNull::Write(std::ostream &s) { s << "null"; } 112 113 JSONObject::JSONObject() : JSONValue(JSONValue::Kind::Object) {} 114 115 void 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; 122 else 123 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 << '}'; 131 } 132 133 bool JSONObject::SetObject(const std::string &key, JSONValue::SP value) { 134 if (key.empty() || nullptr == value.get()) 135 return false; 136 m_elements[key] = value; 137 return true; 138 } 139 140 JSONValue::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 147 bool 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 168 bool 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 183 JSONArray::JSONArray() : JSONValue(JSONValue::Kind::Array) {} 184 185 void 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 199 bool 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()) { 207 m_elements.push_back(value); 208 return true; 209 } 210 return false; 211 } 212 213 bool JSONArray::AppendObject(JSONValue::SP value) { 214 if (value.get() == nullptr) 215 return false; 216 m_elements.push_back(value); 217 return true; 218 } 219 220 JSONValue::SP JSONArray::GetObject(Index i) { 221 if (i < m_elements.size()) 222 return m_elements[i]; 223 return JSONValue::SP(); 224 } 225 226 JSONArray::Size JSONArray::GetNumElements() { return m_elements.size(); } 227 228 JSONParser::JSONParser(const char *cstr) : StdStringExtractor(cstr) {} 229 230 JSONParser::Token JSONParser::GetToken(std::string &value) { 231 std::ostringstream error; 232 233 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; 258 259 case 'f': 260 if (GetChar() == 'a') 261 if (GetChar() == 'l') 262 if (GetChar() == 's') 263 if (GetChar() == 'e') 264 return Token::False; 265 break; 266 267 case 'n': 268 if (GetChar() == 'u') 269 if (GetChar() == 'l') 270 if (GetChar() == 'l') 271 return Token::Null; 272 break; 273 274 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(); 282 return Token::Status; 283 284 } 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(); 296 return Token::Status; 297 } 298 } else if (is_end_quote) { 299 return Token::String; 300 } else if (is_null) { 301 value = "error: missing end quote for string"; 302 return Token::Status; 303 } 304 } 305 } 306 } break; 307 308 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; 344 } 345 ++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(); 352 return Token::Status; 353 } 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(); 365 return Token::Status; 366 } 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(); 381 return Token::Status; 382 } 383 break; 384 385 default: 386 done = true; 387 break; 388 } 389 } 390 391 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(); 403 return Token::Status; 404 } 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(); 414 return Token::Status; 415 } 416 } 417 } 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(); 425 return Token::Status; 426 } 427 } 428 } else { 429 error << "error: invalid number found at offset " << start_index; 430 value = error.str(); 431 return Token::Status; 432 } 433 } 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(); 440 return Token::Status; 441 } 442 443 int 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; 455 456 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 479 JSONValue::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) { 494 JSONValue::SP value_sp = ParseJSONValue(); 495 if (value_sp) 496 dict_up->SetObject(key, value_sp); 497 else 498 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; 506 } 507 } 508 return JSONValue::SP(); 509 } 510 511 JSONValue::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()); 516 517 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; 525 526 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; 533 } 534 } 535 return JSONValue::SP(); 536 } 537 538 JSONValue::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(); 585 } 586