175930019STodd Fiala //===--------------------- JSON.cpp -----------------------------*- C++ -*-===// 275930019STodd Fiala // 375930019STodd Fiala // The LLVM Compiler Infrastructure 475930019STodd Fiala // 575930019STodd Fiala // This file is distributed under the University of Illinois Open Source 675930019STodd Fiala // License. See LICENSE.TXT for details. 775930019STodd Fiala // 875930019STodd Fiala //===----------------------------------------------------------------------===// 975930019STodd Fiala 1075930019STodd Fiala #include "JSON.h" 1175930019STodd Fiala 1275930019STodd Fiala // C includes 1375930019STodd Fiala #include <assert.h> 1475930019STodd Fiala #include <limits.h> 1575930019STodd Fiala 1675930019STodd Fiala // C++ includes 17b9c1b51eSKate Stone #include "lldb/Host/StringConvert.h" 1875930019STodd Fiala #include <iomanip> 1975930019STodd Fiala #include <sstream> 2075930019STodd Fiala 2175930019STodd Fiala using namespace lldb_private; 2275930019STodd Fiala 23b9c1b51eSKate Stone std::string JSONString::json_string_quote_metachars(const std::string &s) { 2475930019STodd Fiala if (s.find('"') == std::string::npos) 2575930019STodd Fiala return s; 2675930019STodd Fiala 2775930019STodd Fiala std::string output; 2875930019STodd Fiala const size_t s_size = s.size(); 2975930019STodd Fiala const char *s_chars = s.c_str(); 30b9c1b51eSKate Stone for (size_t i = 0; i < s_size; i++) { 3175930019STodd Fiala unsigned char ch = *(s_chars + i); 32b9c1b51eSKate Stone if (ch == '"') { 3375930019STodd Fiala output.push_back('\\'); 3475930019STodd Fiala } 3575930019STodd Fiala output.push_back(ch); 3675930019STodd Fiala } 3775930019STodd Fiala return output; 3875930019STodd Fiala } 3975930019STodd Fiala 40b9c1b51eSKate Stone JSONString::JSONString() : JSONValue(JSONValue::Kind::String), m_data() {} 4175930019STodd Fiala 42b9c1b51eSKate Stone JSONString::JSONString(const char *s) 43b9c1b51eSKate Stone : JSONValue(JSONValue::Kind::String), m_data(s ? s : "") {} 4475930019STodd Fiala 45b9c1b51eSKate Stone JSONString::JSONString(const std::string &s) 46b9c1b51eSKate Stone : JSONValue(JSONValue::Kind::String), m_data(s) {} 4775930019STodd Fiala 48b9c1b51eSKate Stone void JSONString::Write(std::ostream &s) { 4975930019STodd Fiala s << "\"" << json_string_quote_metachars(m_data).c_str() << "\""; 5075930019STodd Fiala } 5175930019STodd Fiala 52b9c1b51eSKate Stone uint64_t JSONNumber::GetAsUnsigned() const { 53b9c1b51eSKate Stone switch (m_data_type) { 5475930019STodd Fiala case DataType::Unsigned: 5575930019STodd Fiala return m_data.m_unsigned; 5675930019STodd Fiala case DataType::Signed: 5775930019STodd Fiala return (uint64_t)m_data.m_signed; 5875930019STodd Fiala case DataType::Double: 5975930019STodd Fiala return (uint64_t)m_data.m_double; 6075930019STodd Fiala } 6175930019STodd Fiala assert("Unhandled data type"); 6275930019STodd Fiala } 6375930019STodd Fiala 64b9c1b51eSKate Stone int64_t JSONNumber::GetAsSigned() const { 65b9c1b51eSKate Stone switch (m_data_type) { 6675930019STodd Fiala case DataType::Unsigned: 6775930019STodd Fiala return (int64_t)m_data.m_unsigned; 6875930019STodd Fiala case DataType::Signed: 6975930019STodd Fiala return m_data.m_signed; 7075930019STodd Fiala case DataType::Double: 7175930019STodd Fiala return (int64_t)m_data.m_double; 7275930019STodd Fiala } 7375930019STodd Fiala assert("Unhandled data type"); 7475930019STodd Fiala } 7575930019STodd Fiala 76b9c1b51eSKate Stone double JSONNumber::GetAsDouble() const { 77b9c1b51eSKate Stone switch (m_data_type) { 7875930019STodd Fiala case DataType::Unsigned: 7975930019STodd Fiala return (double)m_data.m_unsigned; 8075930019STodd Fiala case DataType::Signed: 8175930019STodd Fiala return (double)m_data.m_signed; 8275930019STodd Fiala case DataType::Double: 8375930019STodd Fiala return m_data.m_double; 8475930019STodd Fiala } 8575930019STodd Fiala assert("Unhandled data type"); 8675930019STodd Fiala } 8775930019STodd Fiala 88b9c1b51eSKate Stone void JSONNumber::Write(std::ostream &s) { 89b9c1b51eSKate Stone switch (m_data_type) { 9075930019STodd Fiala case DataType::Unsigned: 9175930019STodd Fiala s << m_data.m_unsigned; 9275930019STodd Fiala break; 9375930019STodd Fiala case DataType::Signed: 9475930019STodd Fiala s << m_data.m_signed; 9575930019STodd Fiala break; 9675930019STodd Fiala case DataType::Double: 9775930019STodd Fiala // Set max precision to emulate %g. 9875930019STodd Fiala s << std::setprecision(std::numeric_limits<double>::digits10 + 1); 9975930019STodd Fiala s << m_data.m_double; 10075930019STodd Fiala break; 10175930019STodd Fiala } 10275930019STodd Fiala } 10375930019STodd Fiala 104b9c1b51eSKate Stone JSONTrue::JSONTrue() : JSONValue(JSONValue::Kind::True) {} 10575930019STodd Fiala 106b9c1b51eSKate Stone void JSONTrue::Write(std::ostream &s) { s << "true"; } 10775930019STodd Fiala 108b9c1b51eSKate Stone JSONFalse::JSONFalse() : JSONValue(JSONValue::Kind::False) {} 10975930019STodd Fiala 110b9c1b51eSKate Stone void JSONFalse::Write(std::ostream &s) { s << "false"; } 11175930019STodd Fiala 112b9c1b51eSKate Stone JSONNull::JSONNull() : JSONValue(JSONValue::Kind::Null) {} 11375930019STodd Fiala 114b9c1b51eSKate Stone void JSONNull::Write(std::ostream &s) { s << "null"; } 11575930019STodd Fiala 116b9c1b51eSKate Stone JSONObject::JSONObject() : JSONValue(JSONValue::Kind::Object) {} 11775930019STodd Fiala 118b9c1b51eSKate Stone void JSONObject::Write(std::ostream &s) { 11975930019STodd Fiala bool first = true; 12075930019STodd Fiala s << '{'; 12175930019STodd Fiala auto iter = m_elements.begin(), end = m_elements.end(); 122b9c1b51eSKate Stone for (; iter != end; iter++) { 12375930019STodd Fiala if (first) 12475930019STodd Fiala first = false; 12575930019STodd Fiala else 12675930019STodd Fiala s << ','; 12775930019STodd Fiala JSONString key(iter->first); 12875930019STodd Fiala JSONValue::SP value(iter->second); 12975930019STodd Fiala key.Write(s); 13075930019STodd Fiala s << ':'; 13175930019STodd Fiala value->Write(s); 13275930019STodd Fiala } 13375930019STodd Fiala s << '}'; 13475930019STodd Fiala } 13575930019STodd Fiala 136b9c1b51eSKate Stone bool JSONObject::SetObject(const std::string &key, JSONValue::SP value) { 13775930019STodd Fiala if (key.empty() || nullptr == value.get()) 13875930019STodd Fiala return false; 13975930019STodd Fiala m_elements[key] = value; 14075930019STodd Fiala return true; 14175930019STodd Fiala } 14275930019STodd Fiala 143b9c1b51eSKate Stone JSONValue::SP JSONObject::GetObject(const std::string &key) const { 14475930019STodd Fiala auto iter = m_elements.find(key), end = m_elements.end(); 14575930019STodd Fiala if (iter == end) 14675930019STodd Fiala return JSONValue::SP(); 14775930019STodd Fiala return iter->second; 14875930019STodd Fiala } 14975930019STodd Fiala 150b9c1b51eSKate Stone bool JSONObject::GetObjectAsBool(const std::string &key, bool &value) const { 15175930019STodd Fiala auto value_sp = GetObject(key); 152b9c1b51eSKate Stone if (!value_sp) { 15375930019STodd Fiala // The given key doesn't exist, so we have no value. 15475930019STodd Fiala return false; 15575930019STodd Fiala } 15675930019STodd Fiala 157b9c1b51eSKate Stone if (JSONTrue::classof(value_sp.get())) { 15875930019STodd Fiala // We have the value, and it is true. 15975930019STodd Fiala value = true; 16075930019STodd Fiala return true; 161b9c1b51eSKate Stone } else if (JSONFalse::classof(value_sp.get())) { 16275930019STodd Fiala // We have the value, and it is false. 16375930019STodd Fiala value = false; 16475930019STodd Fiala return true; 165b9c1b51eSKate Stone } else { 16675930019STodd Fiala // We don't have a valid bool value for the given key. 16775930019STodd Fiala return false; 16875930019STodd Fiala } 16975930019STodd Fiala } 17075930019STodd Fiala 171b9c1b51eSKate Stone bool JSONObject::GetObjectAsString(const std::string &key, 172b9c1b51eSKate Stone std::string &value) const { 17375930019STodd Fiala auto value_sp = GetObject(key); 174b9c1b51eSKate Stone if (!value_sp) { 17575930019STodd Fiala // The given key doesn't exist, so we have no value. 17675930019STodd Fiala return false; 17775930019STodd Fiala } 17875930019STodd Fiala 17975930019STodd Fiala if (!JSONString::classof(value_sp.get())) 18075930019STodd Fiala return false; 18175930019STodd Fiala 18275930019STodd Fiala value = static_cast<JSONString *>(value_sp.get())->GetData(); 18375930019STodd Fiala return true; 18475930019STodd Fiala } 18575930019STodd Fiala 186b9c1b51eSKate Stone JSONArray::JSONArray() : JSONValue(JSONValue::Kind::Array) {} 18775930019STodd Fiala 188b9c1b51eSKate Stone void JSONArray::Write(std::ostream &s) { 18975930019STodd Fiala bool first = true; 19075930019STodd Fiala s << '['; 19175930019STodd Fiala auto iter = m_elements.begin(), end = m_elements.end(); 192b9c1b51eSKate Stone for (; iter != end; iter++) { 19375930019STodd Fiala if (first) 19475930019STodd Fiala first = false; 19575930019STodd Fiala else 19675930019STodd Fiala s << ','; 19775930019STodd Fiala (*iter)->Write(s); 19875930019STodd Fiala } 19975930019STodd Fiala s << ']'; 20075930019STodd Fiala } 20175930019STodd Fiala 202b9c1b51eSKate Stone bool JSONArray::SetObject(Index i, JSONValue::SP value) { 20375930019STodd Fiala if (value.get() == nullptr) 20475930019STodd Fiala return false; 205b9c1b51eSKate Stone if (i < m_elements.size()) { 20675930019STodd Fiala m_elements[i] = value; 20775930019STodd Fiala return true; 20875930019STodd Fiala } 209b9c1b51eSKate Stone if (i == m_elements.size()) { 21075930019STodd Fiala m_elements.push_back(value); 21175930019STodd Fiala return true; 21275930019STodd Fiala } 21375930019STodd Fiala return false; 21475930019STodd Fiala } 21575930019STodd Fiala 216b9c1b51eSKate Stone bool JSONArray::AppendObject(JSONValue::SP value) { 21775930019STodd Fiala if (value.get() == nullptr) 21875930019STodd Fiala return false; 21975930019STodd Fiala m_elements.push_back(value); 22075930019STodd Fiala return true; 22175930019STodd Fiala } 22275930019STodd Fiala 223b9c1b51eSKate Stone JSONValue::SP JSONArray::GetObject(Index i) { 22475930019STodd Fiala if (i < m_elements.size()) 22575930019STodd Fiala return m_elements[i]; 22675930019STodd Fiala return JSONValue::SP(); 22775930019STodd Fiala } 22875930019STodd Fiala 229b9c1b51eSKate Stone JSONArray::Size JSONArray::GetNumElements() { return m_elements.size(); } 23075930019STodd Fiala 231b9c1b51eSKate Stone JSONParser::JSONParser(const char *cstr) : StdStringExtractor(cstr) {} 23275930019STodd Fiala 233b9c1b51eSKate Stone JSONParser::Token JSONParser::GetToken(std::string &value) { 23475930019STodd Fiala std::ostringstream error; 23575930019STodd Fiala 23675930019STodd Fiala value.clear(); 23775930019STodd Fiala SkipSpaces(); 23875930019STodd Fiala const uint64_t start_index = m_index; 23975930019STodd Fiala const char ch = GetChar(); 240b9c1b51eSKate Stone switch (ch) { 241b9c1b51eSKate Stone case '{': 242b9c1b51eSKate Stone return Token::ObjectStart; 243b9c1b51eSKate Stone case '}': 244b9c1b51eSKate Stone return Token::ObjectEnd; 245b9c1b51eSKate Stone case '[': 246b9c1b51eSKate Stone return Token::ArrayStart; 247b9c1b51eSKate Stone case ']': 248b9c1b51eSKate Stone return Token::ArrayEnd; 249b9c1b51eSKate Stone case ',': 250b9c1b51eSKate Stone return Token::Comma; 251b9c1b51eSKate Stone case ':': 252b9c1b51eSKate Stone return Token::Colon; 253b9c1b51eSKate Stone case '\0': 254b9c1b51eSKate Stone return Token::EndOfFile; 25575930019STodd Fiala case 't': 25675930019STodd Fiala if (GetChar() == 'r') 25775930019STodd Fiala if (GetChar() == 'u') 25875930019STodd Fiala if (GetChar() == 'e') 25975930019STodd Fiala return Token::True; 26075930019STodd Fiala break; 26175930019STodd Fiala 26275930019STodd Fiala case 'f': 26375930019STodd Fiala if (GetChar() == 'a') 26475930019STodd Fiala if (GetChar() == 'l') 26575930019STodd Fiala if (GetChar() == 's') 26675930019STodd Fiala if (GetChar() == 'e') 26775930019STodd Fiala return Token::False; 26875930019STodd Fiala break; 26975930019STodd Fiala 27075930019STodd Fiala case 'n': 27175930019STodd Fiala if (GetChar() == 'u') 27275930019STodd Fiala if (GetChar() == 'l') 27375930019STodd Fiala if (GetChar() == 'l') 27475930019STodd Fiala return Token::Null; 27575930019STodd Fiala break; 27675930019STodd Fiala 277b9c1b51eSKate Stone case '"': { 278b9c1b51eSKate Stone while (1) { 27975930019STodd Fiala bool was_escaped = false; 28075930019STodd Fiala int escaped_ch = GetEscapedChar(was_escaped); 281b9c1b51eSKate Stone if (escaped_ch == -1) { 282b9c1b51eSKate Stone error << "error: an error occurred getting a character from offset " 283b9c1b51eSKate Stone << start_index; 284c1566308SPavel Labath value = error.str(); 285*97206d57SZachary Turner return Token::Status; 28675930019STodd Fiala 287b9c1b51eSKate Stone } else { 28875930019STodd Fiala const bool is_end_quote = escaped_ch == '"'; 28975930019STodd Fiala const bool is_null = escaped_ch == 0; 290b9c1b51eSKate Stone if (was_escaped || (!is_end_quote && !is_null)) { 291b9c1b51eSKate Stone if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX) { 29275930019STodd Fiala value.append(1, (char)escaped_ch); 293b9c1b51eSKate Stone } else { 294b9c1b51eSKate Stone error << "error: wide character support is needed for unicode " 295b9c1b51eSKate Stone "character 0x" 296b9c1b51eSKate Stone << std::setprecision(4) << std::hex << escaped_ch; 29775930019STodd Fiala error << " at offset " << start_index; 298c1566308SPavel Labath value = error.str(); 299*97206d57SZachary Turner return Token::Status; 30075930019STodd Fiala } 301b9c1b51eSKate Stone } else if (is_end_quote) { 30275930019STodd Fiala return Token::String; 303b9c1b51eSKate Stone } else if (is_null) { 30475930019STodd Fiala value = "error: missing end quote for string"; 305*97206d57SZachary Turner return Token::Status; 30675930019STodd Fiala } 30775930019STodd Fiala } 30875930019STodd Fiala } 309b9c1b51eSKate Stone } break; 31075930019STodd Fiala 31175930019STodd Fiala case '-': 31275930019STodd Fiala case '0': 31375930019STodd Fiala case '1': 31475930019STodd Fiala case '2': 31575930019STodd Fiala case '3': 31675930019STodd Fiala case '4': 31775930019STodd Fiala case '5': 31875930019STodd Fiala case '6': 31975930019STodd Fiala case '7': 32075930019STodd Fiala case '8': 321b9c1b51eSKate Stone case '9': { 32275930019STodd Fiala bool done = false; 32375930019STodd Fiala bool got_decimal_point = false; 32475930019STodd Fiala uint64_t exp_index = 0; 32575930019STodd Fiala bool got_int_digits = (ch >= '0') && (ch <= '9'); 32675930019STodd Fiala bool got_frac_digits = false; 32775930019STodd Fiala bool got_exp_digits = false; 328b9c1b51eSKate Stone while (!done) { 32975930019STodd Fiala const char next_ch = PeekChar(); 330b9c1b51eSKate Stone switch (next_ch) { 33175930019STodd Fiala case '0': 33275930019STodd Fiala case '1': 33375930019STodd Fiala case '2': 33475930019STodd Fiala case '3': 33575930019STodd Fiala case '4': 33675930019STodd Fiala case '5': 33775930019STodd Fiala case '6': 33875930019STodd Fiala case '7': 33975930019STodd Fiala case '8': 34075930019STodd Fiala case '9': 341b9c1b51eSKate Stone if (exp_index != 0) { 34275930019STodd Fiala got_exp_digits = true; 343b9c1b51eSKate Stone } else if (got_decimal_point) { 34475930019STodd Fiala got_frac_digits = true; 345b9c1b51eSKate Stone } else { 34675930019STodd Fiala got_int_digits = true; 34775930019STodd Fiala } 34875930019STodd Fiala ++m_index; // Skip this character 34975930019STodd Fiala break; 35075930019STodd Fiala 35175930019STodd Fiala case '.': 352b9c1b51eSKate Stone if (got_decimal_point) { 35375930019STodd Fiala error << "error: extra decimal point found at offset " << start_index; 354c1566308SPavel Labath value = error.str(); 355*97206d57SZachary Turner return Token::Status; 356b9c1b51eSKate Stone } else { 35775930019STodd Fiala got_decimal_point = true; 35875930019STodd Fiala ++m_index; // Skip this character 35975930019STodd Fiala } 36075930019STodd Fiala break; 36175930019STodd Fiala 36275930019STodd Fiala case 'e': 36375930019STodd Fiala case 'E': 364b9c1b51eSKate Stone if (exp_index != 0) { 365b9c1b51eSKate Stone error << "error: extra exponent character found at offset " 366b9c1b51eSKate Stone << start_index; 367c1566308SPavel Labath value = error.str(); 368*97206d57SZachary Turner return Token::Status; 369b9c1b51eSKate Stone } else { 37075930019STodd Fiala exp_index = m_index; 37175930019STodd Fiala ++m_index; // Skip this character 37275930019STodd Fiala } 37375930019STodd Fiala break; 37475930019STodd Fiala 37575930019STodd Fiala case '+': 37675930019STodd Fiala case '-': 37775930019STodd Fiala // The '+' and '-' can only come after an exponent character... 378b9c1b51eSKate Stone if (exp_index == m_index - 1) { 37975930019STodd Fiala ++m_index; // Skip the exponent sign character 380b9c1b51eSKate Stone } else { 381b9c1b51eSKate Stone error << "error: unexpected " << next_ch << " character at offset " 382b9c1b51eSKate Stone << start_index; 383c1566308SPavel Labath value = error.str(); 384*97206d57SZachary Turner return Token::Status; 38575930019STodd Fiala } 38675930019STodd Fiala break; 38775930019STodd Fiala 38875930019STodd Fiala default: 38975930019STodd Fiala done = true; 39075930019STodd Fiala break; 39175930019STodd Fiala } 39275930019STodd Fiala } 39375930019STodd Fiala 394b9c1b51eSKate Stone if (m_index > start_index) { 39575930019STodd Fiala value = m_packet.substr(start_index, m_index - start_index); 396b9c1b51eSKate Stone if (got_decimal_point) { 397b9c1b51eSKate Stone if (exp_index != 0) { 39875930019STodd Fiala // We have an exponent, make sure we got exponent digits 399b9c1b51eSKate Stone if (got_exp_digits) { 40075930019STodd Fiala return Token::Float; 401b9c1b51eSKate Stone } else { 402b9c1b51eSKate Stone error << "error: got exponent character but no exponent digits at " 403b9c1b51eSKate Stone "offset in float value \"" 404b9c1b51eSKate Stone << value.c_str() << "\""; 405b9c1b51eSKate Stone value = error.str(); 406*97206d57SZachary Turner return Token::Status; 40775930019STodd Fiala } 408b9c1b51eSKate Stone } else { 409b9c1b51eSKate Stone // No exponent, but we need at least one decimal after the decimal 410b9c1b51eSKate Stone // point 411b9c1b51eSKate Stone if (got_frac_digits) { 412b9c1b51eSKate Stone return Token::Float; 413b9c1b51eSKate Stone } else { 414b9c1b51eSKate Stone error << "error: no digits after decimal point \"" << value.c_str() 415b9c1b51eSKate Stone << "\""; 416c1566308SPavel Labath value = error.str(); 417*97206d57SZachary Turner return Token::Status; 41875930019STodd Fiala } 41975930019STodd Fiala } 420b9c1b51eSKate Stone } else { 42175930019STodd Fiala // No decimal point 422b9c1b51eSKate Stone if (got_int_digits) { 42375930019STodd Fiala // We need at least some integer digits to make an integer 42475930019STodd Fiala return Token::Integer; 425b9c1b51eSKate Stone } else { 42675930019STodd Fiala error << "error: no digits negate sign \"" << value.c_str() << "\""; 427c1566308SPavel Labath value = error.str(); 428*97206d57SZachary Turner return Token::Status; 42975930019STodd Fiala } 43075930019STodd Fiala } 431b9c1b51eSKate Stone } else { 43275930019STodd Fiala error << "error: invalid number found at offset " << start_index; 433c1566308SPavel Labath value = error.str(); 434*97206d57SZachary Turner return Token::Status; 43575930019STodd Fiala } 436b9c1b51eSKate Stone } break; 43775930019STodd Fiala default: 43875930019STodd Fiala break; 43975930019STodd Fiala } 440b9c1b51eSKate Stone error << "error: failed to parse token at offset " << start_index 441b9c1b51eSKate Stone << " (around character '" << ch << "')"; 442c1566308SPavel Labath value = error.str(); 443*97206d57SZachary Turner return Token::Status; 44475930019STodd Fiala } 44575930019STodd Fiala 446b9c1b51eSKate Stone int JSONParser::GetEscapedChar(bool &was_escaped) { 44775930019STodd Fiala was_escaped = false; 44875930019STodd Fiala const char ch = GetChar(); 449b9c1b51eSKate Stone if (ch == '\\') { 45075930019STodd Fiala was_escaped = true; 45175930019STodd Fiala const char ch2 = GetChar(); 452b9c1b51eSKate Stone switch (ch2) { 45375930019STodd Fiala case '"': 45475930019STodd Fiala case '\\': 45575930019STodd Fiala case '/': 45675930019STodd Fiala default: 45775930019STodd Fiala break; 45875930019STodd Fiala 459b9c1b51eSKate Stone case 'b': 460b9c1b51eSKate Stone return '\b'; 461b9c1b51eSKate Stone case 'f': 462b9c1b51eSKate Stone return '\f'; 463b9c1b51eSKate Stone case 'n': 464b9c1b51eSKate Stone return '\n'; 465b9c1b51eSKate Stone case 'r': 466b9c1b51eSKate Stone return '\r'; 467b9c1b51eSKate Stone case 't': 468b9c1b51eSKate Stone return '\t'; 469b9c1b51eSKate Stone case 'u': { 47075930019STodd Fiala const int hi_byte = DecodeHexU8(); 47175930019STodd Fiala const int lo_byte = DecodeHexU8(); 47275930019STodd Fiala if (hi_byte >= 0 && lo_byte >= 0) 47375930019STodd Fiala return hi_byte << 8 | lo_byte; 47475930019STodd Fiala return -1; 475b9c1b51eSKate Stone } break; 47675930019STodd Fiala } 47775930019STodd Fiala return ch2; 47875930019STodd Fiala } 47975930019STodd Fiala return ch; 48075930019STodd Fiala } 48175930019STodd Fiala 482b9c1b51eSKate Stone JSONValue::SP JSONParser::ParseJSONObject() { 483b9c1b51eSKate Stone // The "JSONParser::Token::ObjectStart" token should have already been 484b9c1b51eSKate Stone // consumed 48575930019STodd Fiala // by the time this function is called 48675930019STodd Fiala std::unique_ptr<JSONObject> dict_up(new JSONObject()); 48775930019STodd Fiala 48875930019STodd Fiala std::string value; 48975930019STodd Fiala std::string key; 490b9c1b51eSKate Stone while (1) { 49175930019STodd Fiala JSONParser::Token token = GetToken(value); 49275930019STodd Fiala 493b9c1b51eSKate Stone if (token == JSONParser::Token::String) { 49475930019STodd Fiala key.swap(value); 49575930019STodd Fiala token = GetToken(value); 496b9c1b51eSKate Stone if (token == JSONParser::Token::Colon) { 49775930019STodd Fiala JSONValue::SP value_sp = ParseJSONValue(); 49875930019STodd Fiala if (value_sp) 49975930019STodd Fiala dict_up->SetObject(key, value_sp); 50075930019STodd Fiala else 50175930019STodd Fiala break; 50275930019STodd Fiala } 503b9c1b51eSKate Stone } else if (token == JSONParser::Token::ObjectEnd) { 50475930019STodd Fiala return JSONValue::SP(dict_up.release()); 505b9c1b51eSKate Stone } else if (token == JSONParser::Token::Comma) { 50675930019STodd Fiala continue; 507b9c1b51eSKate Stone } else { 50875930019STodd Fiala break; 50975930019STodd Fiala } 51075930019STodd Fiala } 51175930019STodd Fiala return JSONValue::SP(); 51275930019STodd Fiala } 51375930019STodd Fiala 514b9c1b51eSKate Stone JSONValue::SP JSONParser::ParseJSONArray() { 515b9c1b51eSKate Stone // The "JSONParser::Token::ObjectStart" token should have already been 516b9c1b51eSKate Stone // consumed 51775930019STodd Fiala // by the time this function is called 51875930019STodd Fiala std::unique_ptr<JSONArray> array_up(new JSONArray()); 51975930019STodd Fiala 52075930019STodd Fiala std::string value; 52175930019STodd Fiala std::string key; 522b9c1b51eSKate Stone while (1) { 52375930019STodd Fiala JSONValue::SP value_sp = ParseJSONValue(); 52475930019STodd Fiala if (value_sp) 52575930019STodd Fiala array_up->AppendObject(value_sp); 52675930019STodd Fiala else 52775930019STodd Fiala break; 52875930019STodd Fiala 52975930019STodd Fiala JSONParser::Token token = GetToken(value); 530b9c1b51eSKate Stone if (token == JSONParser::Token::Comma) { 53175930019STodd Fiala continue; 532b9c1b51eSKate Stone } else if (token == JSONParser::Token::ArrayEnd) { 53375930019STodd Fiala return JSONValue::SP(array_up.release()); 534b9c1b51eSKate Stone } else { 53575930019STodd Fiala break; 53675930019STodd Fiala } 53775930019STodd Fiala } 53875930019STodd Fiala return JSONValue::SP(); 53975930019STodd Fiala } 54075930019STodd Fiala 541b9c1b51eSKate Stone JSONValue::SP JSONParser::ParseJSONValue() { 54275930019STodd Fiala std::string value; 54375930019STodd Fiala const JSONParser::Token token = GetToken(value); 544b9c1b51eSKate Stone switch (token) { 54575930019STodd Fiala case JSONParser::Token::ObjectStart: 54675930019STodd Fiala return ParseJSONObject(); 54775930019STodd Fiala 54875930019STodd Fiala case JSONParser::Token::ArrayStart: 54975930019STodd Fiala return ParseJSONArray(); 55075930019STodd Fiala 551b9c1b51eSKate Stone case JSONParser::Token::Integer: { 552b9c1b51eSKate Stone if (value.front() == '-') { 55375930019STodd Fiala bool success = false; 55475930019STodd Fiala int64_t sval = StringConvert::ToSInt64(value.c_str(), 0, 0, &success); 55575930019STodd Fiala if (success) 55675930019STodd Fiala return JSONValue::SP(new JSONNumber(sval)); 557b9c1b51eSKate Stone } else { 55875930019STodd Fiala bool success = false; 55975930019STodd Fiala uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success); 56075930019STodd Fiala if (success) 56175930019STodd Fiala return JSONValue::SP(new JSONNumber(uval)); 56275930019STodd Fiala } 563b9c1b51eSKate Stone } break; 56475930019STodd Fiala 565b9c1b51eSKate Stone case JSONParser::Token::Float: { 56675930019STodd Fiala bool success = false; 56775930019STodd Fiala double val = StringConvert::ToDouble(value.c_str(), 0.0, &success); 56875930019STodd Fiala if (success) 56975930019STodd Fiala return JSONValue::SP(new JSONNumber(val)); 570b9c1b51eSKate Stone } break; 57175930019STodd Fiala 57275930019STodd Fiala case JSONParser::Token::String: 57375930019STodd Fiala return JSONValue::SP(new JSONString(value)); 57475930019STodd Fiala 57575930019STodd Fiala case JSONParser::Token::True: 57675930019STodd Fiala return JSONValue::SP(new JSONTrue()); 57775930019STodd Fiala 57875930019STodd Fiala case JSONParser::Token::False: 57975930019STodd Fiala return JSONValue::SP(new JSONFalse()); 58075930019STodd Fiala 58175930019STodd Fiala case JSONParser::Token::Null: 58275930019STodd Fiala return JSONValue::SP(new JSONNull()); 58375930019STodd Fiala 58475930019STodd Fiala default: 58575930019STodd Fiala break; 58675930019STodd Fiala } 58775930019STodd Fiala return JSONValue::SP(); 58875930019STodd Fiala } 589