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