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