175930019STodd Fiala //===--------------------- JSON.cpp -----------------------------*- C++ -*-===// 275930019STodd Fiala // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 675930019STodd Fiala // 775930019STodd Fiala //===----------------------------------------------------------------------===// 875930019STodd Fiala 975930019STodd Fiala #include "JSON.h" 1075930019STodd Fiala 1175930019STodd Fiala // C includes 12*76e47d48SRaphael Isemann #include <cassert> 13*76e47d48SRaphael Isemann #include <climits> 1475930019STodd Fiala 1575930019STodd Fiala // C++ includes 16b9c1b51eSKate Stone #include "lldb/Host/StringConvert.h" 1775930019STodd Fiala #include <iomanip> 1875930019STodd Fiala #include <sstream> 1975930019STodd Fiala 2075930019STodd Fiala using namespace lldb_private; 2175930019STodd Fiala 22b9c1b51eSKate Stone std::string JSONString::json_string_quote_metachars(const std::string &s) { 2375930019STodd Fiala if (s.find('"') == std::string::npos) 2475930019STodd Fiala return s; 2575930019STodd Fiala 2675930019STodd Fiala std::string output; 2775930019STodd Fiala const size_t s_size = s.size(); 2875930019STodd Fiala const char *s_chars = s.c_str(); 29b9c1b51eSKate Stone for (size_t i = 0; i < s_size; i++) { 3075930019STodd Fiala unsigned char ch = *(s_chars + i); 31b9c1b51eSKate Stone if (ch == '"') { 3275930019STodd Fiala output.push_back('\\'); 3375930019STodd Fiala } 3475930019STodd Fiala output.push_back(ch); 3575930019STodd Fiala } 3675930019STodd Fiala return output; 3775930019STodd Fiala } 3875930019STodd Fiala 39b9c1b51eSKate Stone JSONString::JSONString() : JSONValue(JSONValue::Kind::String), m_data() {} 4075930019STodd Fiala 41b9c1b51eSKate Stone JSONString::JSONString(const char *s) 42b9c1b51eSKate Stone : JSONValue(JSONValue::Kind::String), m_data(s ? s : "") {} 4375930019STodd Fiala 44b9c1b51eSKate Stone JSONString::JSONString(const std::string &s) 45b9c1b51eSKate Stone : JSONValue(JSONValue::Kind::String), m_data(s) {} 4675930019STodd Fiala 47b9c1b51eSKate Stone void JSONString::Write(std::ostream &s) { 4875930019STodd Fiala s << "\"" << json_string_quote_metachars(m_data).c_str() << "\""; 4975930019STodd Fiala } 5075930019STodd Fiala 51b9c1b51eSKate Stone uint64_t JSONNumber::GetAsUnsigned() const { 52b9c1b51eSKate Stone switch (m_data_type) { 5375930019STodd Fiala case DataType::Unsigned: 5475930019STodd Fiala return m_data.m_unsigned; 5575930019STodd Fiala case DataType::Signed: 5675930019STodd Fiala return (uint64_t)m_data.m_signed; 5775930019STodd Fiala case DataType::Double: 5875930019STodd Fiala return (uint64_t)m_data.m_double; 5975930019STodd Fiala } 6075930019STodd Fiala } 6175930019STodd Fiala 62b9c1b51eSKate Stone int64_t JSONNumber::GetAsSigned() const { 63b9c1b51eSKate Stone switch (m_data_type) { 6475930019STodd Fiala case DataType::Unsigned: 6575930019STodd Fiala return (int64_t)m_data.m_unsigned; 6675930019STodd Fiala case DataType::Signed: 6775930019STodd Fiala return m_data.m_signed; 6875930019STodd Fiala case DataType::Double: 6975930019STodd Fiala return (int64_t)m_data.m_double; 7075930019STodd Fiala } 7175930019STodd Fiala } 7275930019STodd Fiala 73b9c1b51eSKate Stone double JSONNumber::GetAsDouble() const { 74b9c1b51eSKate Stone switch (m_data_type) { 7575930019STodd Fiala case DataType::Unsigned: 7675930019STodd Fiala return (double)m_data.m_unsigned; 7775930019STodd Fiala case DataType::Signed: 7875930019STodd Fiala return (double)m_data.m_signed; 7975930019STodd Fiala case DataType::Double: 8075930019STodd Fiala return m_data.m_double; 8175930019STodd Fiala } 8275930019STodd Fiala } 8375930019STodd Fiala 84b9c1b51eSKate Stone void JSONNumber::Write(std::ostream &s) { 85b9c1b51eSKate Stone switch (m_data_type) { 8675930019STodd Fiala case DataType::Unsigned: 8775930019STodd Fiala s << m_data.m_unsigned; 8875930019STodd Fiala break; 8975930019STodd Fiala case DataType::Signed: 9075930019STodd Fiala s << m_data.m_signed; 9175930019STodd Fiala break; 9275930019STodd Fiala case DataType::Double: 9375930019STodd Fiala // Set max precision to emulate %g. 9475930019STodd Fiala s << std::setprecision(std::numeric_limits<double>::digits10 + 1); 9575930019STodd Fiala s << m_data.m_double; 9675930019STodd Fiala break; 9775930019STodd Fiala } 9875930019STodd Fiala } 9975930019STodd Fiala 100b9c1b51eSKate Stone JSONTrue::JSONTrue() : JSONValue(JSONValue::Kind::True) {} 10175930019STodd Fiala 102b9c1b51eSKate Stone void JSONTrue::Write(std::ostream &s) { s << "true"; } 10375930019STodd Fiala 104b9c1b51eSKate Stone JSONFalse::JSONFalse() : JSONValue(JSONValue::Kind::False) {} 10575930019STodd Fiala 106b9c1b51eSKate Stone void JSONFalse::Write(std::ostream &s) { s << "false"; } 10775930019STodd Fiala 108b9c1b51eSKate Stone JSONNull::JSONNull() : JSONValue(JSONValue::Kind::Null) {} 10975930019STodd Fiala 110b9c1b51eSKate Stone void JSONNull::Write(std::ostream &s) { s << "null"; } 11175930019STodd Fiala 112b9c1b51eSKate Stone JSONObject::JSONObject() : JSONValue(JSONValue::Kind::Object) {} 11375930019STodd Fiala 114b9c1b51eSKate Stone void JSONObject::Write(std::ostream &s) { 11575930019STodd Fiala bool first = true; 11675930019STodd Fiala s << '{'; 11775930019STodd Fiala auto iter = m_elements.begin(), end = m_elements.end(); 118b9c1b51eSKate Stone for (; iter != end; iter++) { 11975930019STodd Fiala if (first) 12075930019STodd Fiala first = false; 12175930019STodd Fiala else 12275930019STodd Fiala s << ','; 12375930019STodd Fiala JSONString key(iter->first); 12475930019STodd Fiala JSONValue::SP value(iter->second); 12575930019STodd Fiala key.Write(s); 12675930019STodd Fiala s << ':'; 12775930019STodd Fiala value->Write(s); 12875930019STodd Fiala } 12975930019STodd Fiala s << '}'; 13075930019STodd Fiala } 13175930019STodd Fiala 132b9c1b51eSKate Stone bool JSONObject::SetObject(const std::string &key, JSONValue::SP value) { 13375930019STodd Fiala if (key.empty() || nullptr == value.get()) 13475930019STodd Fiala return false; 13575930019STodd Fiala m_elements[key] = value; 13675930019STodd Fiala return true; 13775930019STodd Fiala } 13875930019STodd Fiala 139b9c1b51eSKate Stone JSONValue::SP JSONObject::GetObject(const std::string &key) const { 14075930019STodd Fiala auto iter = m_elements.find(key), end = m_elements.end(); 14175930019STodd Fiala if (iter == end) 14275930019STodd Fiala return JSONValue::SP(); 14375930019STodd Fiala return iter->second; 14475930019STodd Fiala } 14575930019STodd Fiala 146b9c1b51eSKate Stone bool JSONObject::GetObjectAsBool(const std::string &key, bool &value) const { 14775930019STodd Fiala auto value_sp = GetObject(key); 148b9c1b51eSKate Stone if (!value_sp) { 14975930019STodd Fiala // The given key doesn't exist, so we have no value. 15075930019STodd Fiala return false; 15175930019STodd Fiala } 15275930019STodd Fiala 153b9c1b51eSKate Stone if (JSONTrue::classof(value_sp.get())) { 15475930019STodd Fiala // We have the value, and it is true. 15575930019STodd Fiala value = true; 15675930019STodd Fiala return true; 157b9c1b51eSKate Stone } else if (JSONFalse::classof(value_sp.get())) { 15875930019STodd Fiala // We have the value, and it is false. 15975930019STodd Fiala value = false; 16075930019STodd Fiala return true; 161b9c1b51eSKate Stone } else { 16275930019STodd Fiala // We don't have a valid bool value for the given key. 16375930019STodd Fiala return false; 16475930019STodd Fiala } 16575930019STodd Fiala } 16675930019STodd Fiala 167b9c1b51eSKate Stone bool JSONObject::GetObjectAsString(const std::string &key, 168b9c1b51eSKate Stone std::string &value) const { 16975930019STodd Fiala auto value_sp = GetObject(key); 170b9c1b51eSKate Stone if (!value_sp) { 17175930019STodd Fiala // The given key doesn't exist, so we have no value. 17275930019STodd Fiala return false; 17375930019STodd Fiala } 17475930019STodd Fiala 17575930019STodd Fiala if (!JSONString::classof(value_sp.get())) 17675930019STodd Fiala return false; 17775930019STodd Fiala 17875930019STodd Fiala value = static_cast<JSONString *>(value_sp.get())->GetData(); 17975930019STodd Fiala return true; 18075930019STodd Fiala } 18175930019STodd Fiala 182b9c1b51eSKate Stone JSONArray::JSONArray() : JSONValue(JSONValue::Kind::Array) {} 18375930019STodd Fiala 184b9c1b51eSKate Stone void JSONArray::Write(std::ostream &s) { 18575930019STodd Fiala bool first = true; 18675930019STodd Fiala s << '['; 18775930019STodd Fiala auto iter = m_elements.begin(), end = m_elements.end(); 188b9c1b51eSKate Stone for (; iter != end; iter++) { 18975930019STodd Fiala if (first) 19075930019STodd Fiala first = false; 19175930019STodd Fiala else 19275930019STodd Fiala s << ','; 19375930019STodd Fiala (*iter)->Write(s); 19475930019STodd Fiala } 19575930019STodd Fiala s << ']'; 19675930019STodd Fiala } 19775930019STodd Fiala 198b9c1b51eSKate Stone bool JSONArray::SetObject(Index i, JSONValue::SP value) { 19975930019STodd Fiala if (value.get() == nullptr) 20075930019STodd Fiala return false; 201b9c1b51eSKate Stone if (i < m_elements.size()) { 20275930019STodd Fiala m_elements[i] = value; 20375930019STodd Fiala return true; 20475930019STodd Fiala } 205b9c1b51eSKate Stone if (i == m_elements.size()) { 20675930019STodd Fiala m_elements.push_back(value); 20775930019STodd Fiala return true; 20875930019STodd Fiala } 20975930019STodd Fiala return false; 21075930019STodd Fiala } 21175930019STodd Fiala 212b9c1b51eSKate Stone bool JSONArray::AppendObject(JSONValue::SP value) { 21375930019STodd Fiala if (value.get() == nullptr) 21475930019STodd Fiala return false; 21575930019STodd Fiala m_elements.push_back(value); 21675930019STodd Fiala return true; 21775930019STodd Fiala } 21875930019STodd Fiala 219b9c1b51eSKate Stone JSONValue::SP JSONArray::GetObject(Index i) { 22075930019STodd Fiala if (i < m_elements.size()) 22175930019STodd Fiala return m_elements[i]; 22275930019STodd Fiala return JSONValue::SP(); 22375930019STodd Fiala } 22475930019STodd Fiala 225b9c1b51eSKate Stone JSONArray::Size JSONArray::GetNumElements() { return m_elements.size(); } 22675930019STodd Fiala 227b9c1b51eSKate Stone JSONParser::JSONParser(const char *cstr) : StdStringExtractor(cstr) {} 22875930019STodd Fiala 229b9c1b51eSKate Stone JSONParser::Token JSONParser::GetToken(std::string &value) { 23075930019STodd Fiala std::ostringstream error; 23175930019STodd Fiala 23275930019STodd Fiala value.clear(); 23375930019STodd Fiala SkipSpaces(); 23475930019STodd Fiala const uint64_t start_index = m_index; 23575930019STodd Fiala const char ch = GetChar(); 236b9c1b51eSKate Stone switch (ch) { 237b9c1b51eSKate Stone case '{': 238b9c1b51eSKate Stone return Token::ObjectStart; 239b9c1b51eSKate Stone case '}': 240b9c1b51eSKate Stone return Token::ObjectEnd; 241b9c1b51eSKate Stone case '[': 242b9c1b51eSKate Stone return Token::ArrayStart; 243b9c1b51eSKate Stone case ']': 244b9c1b51eSKate Stone return Token::ArrayEnd; 245b9c1b51eSKate Stone case ',': 246b9c1b51eSKate Stone return Token::Comma; 247b9c1b51eSKate Stone case ':': 248b9c1b51eSKate Stone return Token::Colon; 249b9c1b51eSKate Stone case '\0': 250b9c1b51eSKate Stone return Token::EndOfFile; 25175930019STodd Fiala case 't': 25275930019STodd Fiala if (GetChar() == 'r') 25375930019STodd Fiala if (GetChar() == 'u') 25475930019STodd Fiala if (GetChar() == 'e') 25575930019STodd Fiala return Token::True; 25675930019STodd Fiala break; 25775930019STodd Fiala 25875930019STodd Fiala case 'f': 25975930019STodd Fiala if (GetChar() == 'a') 26075930019STodd Fiala if (GetChar() == 'l') 26175930019STodd Fiala if (GetChar() == 's') 26275930019STodd Fiala if (GetChar() == 'e') 26375930019STodd Fiala return Token::False; 26475930019STodd Fiala break; 26575930019STodd Fiala 26675930019STodd Fiala case 'n': 26775930019STodd Fiala if (GetChar() == 'u') 26875930019STodd Fiala if (GetChar() == 'l') 26975930019STodd Fiala if (GetChar() == 'l') 27075930019STodd Fiala return Token::Null; 27175930019STodd Fiala break; 27275930019STodd Fiala 273b9c1b51eSKate Stone case '"': { 27409ad8c8fSJonas Devlieghere while (true) { 27575930019STodd Fiala bool was_escaped = false; 27675930019STodd Fiala int escaped_ch = GetEscapedChar(was_escaped); 277b9c1b51eSKate Stone if (escaped_ch == -1) { 278b9c1b51eSKate Stone error << "error: an error occurred getting a character from offset " 279b9c1b51eSKate Stone << start_index; 280c1566308SPavel Labath value = error.str(); 28197206d57SZachary Turner return Token::Status; 28275930019STodd Fiala 283b9c1b51eSKate Stone } else { 28475930019STodd Fiala const bool is_end_quote = escaped_ch == '"'; 28575930019STodd Fiala const bool is_null = escaped_ch == 0; 286b9c1b51eSKate Stone if (was_escaped || (!is_end_quote && !is_null)) { 287b9c1b51eSKate Stone if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX) { 28875930019STodd Fiala value.append(1, (char)escaped_ch); 289b9c1b51eSKate Stone } else { 290b9c1b51eSKate Stone error << "error: wide character support is needed for unicode " 291b9c1b51eSKate Stone "character 0x" 292b9c1b51eSKate Stone << std::setprecision(4) << std::hex << escaped_ch; 29375930019STodd Fiala error << " at offset " << start_index; 294c1566308SPavel Labath value = error.str(); 29597206d57SZachary Turner return Token::Status; 29675930019STodd Fiala } 297b9c1b51eSKate Stone } else if (is_end_quote) { 29875930019STodd Fiala return Token::String; 299b9c1b51eSKate Stone } else if (is_null) { 30075930019STodd Fiala value = "error: missing end quote for string"; 30197206d57SZachary Turner return Token::Status; 30275930019STodd Fiala } 30375930019STodd Fiala } 30475930019STodd Fiala } 305b9c1b51eSKate Stone } break; 30675930019STodd Fiala 30775930019STodd Fiala case '-': 30875930019STodd Fiala case '0': 30975930019STodd Fiala case '1': 31075930019STodd Fiala case '2': 31175930019STodd Fiala case '3': 31275930019STodd Fiala case '4': 31375930019STodd Fiala case '5': 31475930019STodd Fiala case '6': 31575930019STodd Fiala case '7': 31675930019STodd Fiala case '8': 317b9c1b51eSKate Stone case '9': { 31875930019STodd Fiala bool done = false; 31975930019STodd Fiala bool got_decimal_point = false; 32075930019STodd Fiala uint64_t exp_index = 0; 32175930019STodd Fiala bool got_int_digits = (ch >= '0') && (ch <= '9'); 32275930019STodd Fiala bool got_frac_digits = false; 32375930019STodd Fiala bool got_exp_digits = false; 324b9c1b51eSKate Stone while (!done) { 32575930019STodd Fiala const char next_ch = PeekChar(); 326b9c1b51eSKate Stone switch (next_ch) { 32775930019STodd Fiala case '0': 32875930019STodd Fiala case '1': 32975930019STodd Fiala case '2': 33075930019STodd Fiala case '3': 33175930019STodd Fiala case '4': 33275930019STodd Fiala case '5': 33375930019STodd Fiala case '6': 33475930019STodd Fiala case '7': 33575930019STodd Fiala case '8': 33675930019STodd Fiala case '9': 337b9c1b51eSKate Stone if (exp_index != 0) { 33875930019STodd Fiala got_exp_digits = true; 339b9c1b51eSKate Stone } else if (got_decimal_point) { 34075930019STodd Fiala got_frac_digits = true; 341b9c1b51eSKate Stone } else { 34275930019STodd Fiala got_int_digits = true; 34375930019STodd Fiala } 34475930019STodd Fiala ++m_index; // Skip this character 34575930019STodd Fiala break; 34675930019STodd Fiala 34775930019STodd Fiala case '.': 348b9c1b51eSKate Stone if (got_decimal_point) { 34975930019STodd Fiala error << "error: extra decimal point found at offset " << start_index; 350c1566308SPavel Labath value = error.str(); 35197206d57SZachary Turner return Token::Status; 352b9c1b51eSKate Stone } else { 35375930019STodd Fiala got_decimal_point = true; 35475930019STodd Fiala ++m_index; // Skip this character 35575930019STodd Fiala } 35675930019STodd Fiala break; 35775930019STodd Fiala 35875930019STodd Fiala case 'e': 35975930019STodd Fiala case 'E': 360b9c1b51eSKate Stone if (exp_index != 0) { 361b9c1b51eSKate Stone error << "error: extra exponent character found at offset " 362b9c1b51eSKate Stone << start_index; 363c1566308SPavel Labath value = error.str(); 36497206d57SZachary Turner return Token::Status; 365b9c1b51eSKate Stone } else { 36675930019STodd Fiala exp_index = m_index; 36775930019STodd Fiala ++m_index; // Skip this character 36875930019STodd Fiala } 36975930019STodd Fiala break; 37075930019STodd Fiala 37175930019STodd Fiala case '+': 37275930019STodd Fiala case '-': 37375930019STodd Fiala // The '+' and '-' can only come after an exponent character... 374b9c1b51eSKate Stone if (exp_index == m_index - 1) { 37575930019STodd Fiala ++m_index; // Skip the exponent sign character 376b9c1b51eSKate Stone } else { 377b9c1b51eSKate Stone error << "error: unexpected " << next_ch << " character at offset " 378b9c1b51eSKate Stone << start_index; 379c1566308SPavel Labath value = error.str(); 38097206d57SZachary Turner return Token::Status; 38175930019STodd Fiala } 38275930019STodd Fiala break; 38375930019STodd Fiala 38475930019STodd Fiala default: 38575930019STodd Fiala done = true; 38675930019STodd Fiala break; 38775930019STodd Fiala } 38875930019STodd Fiala } 38975930019STodd Fiala 390b9c1b51eSKate Stone if (m_index > start_index) { 39175930019STodd Fiala value = m_packet.substr(start_index, m_index - start_index); 392b9c1b51eSKate Stone if (got_decimal_point) { 393b9c1b51eSKate Stone if (exp_index != 0) { 39475930019STodd Fiala // We have an exponent, make sure we got exponent digits 395b9c1b51eSKate Stone if (got_exp_digits) { 39675930019STodd Fiala return Token::Float; 397b9c1b51eSKate Stone } else { 398b9c1b51eSKate Stone error << "error: got exponent character but no exponent digits at " 399b9c1b51eSKate Stone "offset in float value \"" 400b9c1b51eSKate Stone << value.c_str() << "\""; 401b9c1b51eSKate Stone value = error.str(); 40297206d57SZachary Turner return Token::Status; 40375930019STodd Fiala } 404b9c1b51eSKate Stone } else { 405b9c1b51eSKate Stone // No exponent, but we need at least one decimal after the decimal 406b9c1b51eSKate Stone // point 407b9c1b51eSKate Stone if (got_frac_digits) { 408b9c1b51eSKate Stone return Token::Float; 409b9c1b51eSKate Stone } else { 410b9c1b51eSKate Stone error << "error: no digits after decimal point \"" << value.c_str() 411b9c1b51eSKate Stone << "\""; 412c1566308SPavel Labath value = error.str(); 41397206d57SZachary Turner return Token::Status; 41475930019STodd Fiala } 41575930019STodd Fiala } 416b9c1b51eSKate Stone } else { 41775930019STodd Fiala // No decimal point 418b9c1b51eSKate Stone if (got_int_digits) { 41975930019STodd Fiala // We need at least some integer digits to make an integer 42075930019STodd Fiala return Token::Integer; 421b9c1b51eSKate Stone } else { 42275930019STodd Fiala error << "error: no digits negate sign \"" << value.c_str() << "\""; 423c1566308SPavel Labath value = error.str(); 42497206d57SZachary Turner return Token::Status; 42575930019STodd Fiala } 42675930019STodd Fiala } 427b9c1b51eSKate Stone } else { 42875930019STodd Fiala error << "error: invalid number found at offset " << start_index; 429c1566308SPavel Labath value = error.str(); 43097206d57SZachary Turner return Token::Status; 43175930019STodd Fiala } 432b9c1b51eSKate Stone } break; 43375930019STodd Fiala default: 43475930019STodd Fiala break; 43575930019STodd Fiala } 436b9c1b51eSKate Stone error << "error: failed to parse token at offset " << start_index 437b9c1b51eSKate Stone << " (around character '" << ch << "')"; 438c1566308SPavel Labath value = error.str(); 43997206d57SZachary Turner return Token::Status; 44075930019STodd Fiala } 44175930019STodd Fiala 442b9c1b51eSKate Stone int JSONParser::GetEscapedChar(bool &was_escaped) { 44375930019STodd Fiala was_escaped = false; 44475930019STodd Fiala const char ch = GetChar(); 445b9c1b51eSKate Stone if (ch == '\\') { 44675930019STodd Fiala was_escaped = true; 44775930019STodd Fiala const char ch2 = GetChar(); 448b9c1b51eSKate Stone switch (ch2) { 44975930019STodd Fiala case '"': 45075930019STodd Fiala case '\\': 45175930019STodd Fiala case '/': 45275930019STodd Fiala default: 45375930019STodd Fiala break; 45475930019STodd Fiala 455b9c1b51eSKate Stone case 'b': 456b9c1b51eSKate Stone return '\b'; 457b9c1b51eSKate Stone case 'f': 458b9c1b51eSKate Stone return '\f'; 459b9c1b51eSKate Stone case 'n': 460b9c1b51eSKate Stone return '\n'; 461b9c1b51eSKate Stone case 'r': 462b9c1b51eSKate Stone return '\r'; 463b9c1b51eSKate Stone case 't': 464b9c1b51eSKate Stone return '\t'; 465b9c1b51eSKate Stone case 'u': { 46675930019STodd Fiala const int hi_byte = DecodeHexU8(); 46775930019STodd Fiala const int lo_byte = DecodeHexU8(); 46875930019STodd Fiala if (hi_byte >= 0 && lo_byte >= 0) 46975930019STodd Fiala return hi_byte << 8 | lo_byte; 47075930019STodd Fiala return -1; 471b9c1b51eSKate Stone } break; 47275930019STodd Fiala } 47375930019STodd Fiala return ch2; 47475930019STodd Fiala } 47575930019STodd Fiala return ch; 47675930019STodd Fiala } 47775930019STodd Fiala 478b9c1b51eSKate Stone JSONValue::SP JSONParser::ParseJSONObject() { 479b9c1b51eSKate Stone // The "JSONParser::Token::ObjectStart" token should have already been 480b9c1b51eSKate Stone // consumed 48175930019STodd Fiala // by the time this function is called 48275930019STodd Fiala std::unique_ptr<JSONObject> dict_up(new JSONObject()); 48375930019STodd Fiala 48475930019STodd Fiala std::string value; 48575930019STodd Fiala std::string key; 48609ad8c8fSJonas Devlieghere while (true) { 48775930019STodd Fiala JSONParser::Token token = GetToken(value); 48875930019STodd Fiala 489b9c1b51eSKate Stone if (token == JSONParser::Token::String) { 49075930019STodd Fiala key.swap(value); 49175930019STodd Fiala token = GetToken(value); 492b9c1b51eSKate Stone if (token == JSONParser::Token::Colon) { 49375930019STodd Fiala JSONValue::SP value_sp = ParseJSONValue(); 49475930019STodd Fiala if (value_sp) 49575930019STodd Fiala dict_up->SetObject(key, value_sp); 49675930019STodd Fiala else 49775930019STodd Fiala break; 49875930019STodd Fiala } 499b9c1b51eSKate Stone } else if (token == JSONParser::Token::ObjectEnd) { 50075930019STodd Fiala return JSONValue::SP(dict_up.release()); 501b9c1b51eSKate Stone } else if (token == JSONParser::Token::Comma) { 50275930019STodd Fiala continue; 503b9c1b51eSKate Stone } else { 50475930019STodd Fiala break; 50575930019STodd Fiala } 50675930019STodd Fiala } 50775930019STodd Fiala return JSONValue::SP(); 50875930019STodd Fiala } 50975930019STodd Fiala 510b9c1b51eSKate Stone JSONValue::SP JSONParser::ParseJSONArray() { 511b9c1b51eSKate Stone // The "JSONParser::Token::ObjectStart" token should have already been 512b9c1b51eSKate Stone // consumed 51375930019STodd Fiala // by the time this function is called 51475930019STodd Fiala std::unique_ptr<JSONArray> array_up(new JSONArray()); 51575930019STodd Fiala 51675930019STodd Fiala std::string value; 51775930019STodd Fiala std::string key; 51809ad8c8fSJonas Devlieghere while (true) { 51910b85143SAlex Cameron JSONParser::Token token = GetToken(value); 52010b85143SAlex Cameron if (token == JSONParser::Token::ArrayEnd) 52110b85143SAlex Cameron return JSONValue::SP(array_up.release()); 52210b85143SAlex Cameron JSONValue::SP value_sp = ParseJSONValue(value, token); 52375930019STodd Fiala if (value_sp) 52475930019STodd Fiala array_up->AppendObject(value_sp); 52575930019STodd Fiala else 52675930019STodd Fiala break; 52775930019STodd Fiala 52810b85143SAlex Cameron token = GetToken(value); 529b9c1b51eSKate Stone if (token == JSONParser::Token::Comma) { 53075930019STodd Fiala continue; 531b9c1b51eSKate Stone } else if (token == JSONParser::Token::ArrayEnd) { 53275930019STodd Fiala return JSONValue::SP(array_up.release()); 533b9c1b51eSKate Stone } else { 53475930019STodd Fiala break; 53575930019STodd Fiala } 53675930019STodd Fiala } 53775930019STodd Fiala return JSONValue::SP(); 53875930019STodd Fiala } 53975930019STodd Fiala 540b9c1b51eSKate Stone JSONValue::SP JSONParser::ParseJSONValue() { 54175930019STodd Fiala std::string value; 54275930019STodd Fiala const JSONParser::Token token = GetToken(value); 54310b85143SAlex Cameron return ParseJSONValue(value, token); 54410b85143SAlex Cameron } 54510b85143SAlex Cameron 54610b85143SAlex Cameron JSONValue::SP JSONParser::ParseJSONValue(const std::string &value, 54710b85143SAlex Cameron const Token &token) { 548b9c1b51eSKate Stone switch (token) { 54975930019STodd Fiala case JSONParser::Token::ObjectStart: 55075930019STodd Fiala return ParseJSONObject(); 55175930019STodd Fiala 55275930019STodd Fiala case JSONParser::Token::ArrayStart: 55375930019STodd Fiala return ParseJSONArray(); 55475930019STodd Fiala 555b9c1b51eSKate Stone case JSONParser::Token::Integer: { 556b9c1b51eSKate Stone if (value.front() == '-') { 55775930019STodd Fiala bool success = false; 55875930019STodd Fiala int64_t sval = StringConvert::ToSInt64(value.c_str(), 0, 0, &success); 55975930019STodd Fiala if (success) 56075930019STodd Fiala return JSONValue::SP(new JSONNumber(sval)); 561b9c1b51eSKate Stone } else { 56275930019STodd Fiala bool success = false; 56375930019STodd Fiala uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success); 56475930019STodd Fiala if (success) 56575930019STodd Fiala return JSONValue::SP(new JSONNumber(uval)); 56675930019STodd Fiala } 567b9c1b51eSKate Stone } break; 56875930019STodd Fiala 569b9c1b51eSKate Stone case JSONParser::Token::Float: { 57075930019STodd Fiala bool success = false; 57175930019STodd Fiala double val = StringConvert::ToDouble(value.c_str(), 0.0, &success); 57275930019STodd Fiala if (success) 57375930019STodd Fiala return JSONValue::SP(new JSONNumber(val)); 574b9c1b51eSKate Stone } break; 57575930019STodd Fiala 57675930019STodd Fiala case JSONParser::Token::String: 57775930019STodd Fiala return JSONValue::SP(new JSONString(value)); 57875930019STodd Fiala 57975930019STodd Fiala case JSONParser::Token::True: 58075930019STodd Fiala return JSONValue::SP(new JSONTrue()); 58175930019STodd Fiala 58275930019STodd Fiala case JSONParser::Token::False: 58375930019STodd Fiala return JSONValue::SP(new JSONFalse()); 58475930019STodd Fiala 58575930019STodd Fiala case JSONParser::Token::Null: 58675930019STodd Fiala return JSONValue::SP(new JSONNull()); 58775930019STodd Fiala 58875930019STodd Fiala default: 58975930019STodd Fiala break; 59075930019STodd Fiala } 59175930019STodd Fiala return JSONValue::SP(); 59275930019STodd Fiala } 593