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