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 1775930019STodd Fiala #include <iomanip> 1875930019STodd Fiala #include <sstream> 1975930019STodd Fiala #include "lldb/Host/StringConvert.h" 2075930019STodd Fiala 2175930019STodd Fiala using namespace lldb_private; 2275930019STodd Fiala 2375930019STodd Fiala std::string 2475930019STodd Fiala JSONString::json_string_quote_metachars (const std::string &s) 2575930019STodd Fiala { 2675930019STodd Fiala if (s.find('"') == std::string::npos) 2775930019STodd Fiala return s; 2875930019STodd Fiala 2975930019STodd Fiala std::string output; 3075930019STodd Fiala const size_t s_size = s.size(); 3175930019STodd Fiala const char *s_chars = s.c_str(); 3275930019STodd Fiala for (size_t i = 0; i < s_size; i++) 3375930019STodd Fiala { 3475930019STodd Fiala unsigned char ch = *(s_chars + i); 3575930019STodd Fiala if (ch == '"') 3675930019STodd Fiala { 3775930019STodd Fiala output.push_back ('\\'); 3875930019STodd Fiala } 3975930019STodd Fiala output.push_back (ch); 4075930019STodd Fiala } 4175930019STodd Fiala return output; 4275930019STodd Fiala } 4375930019STodd Fiala 4475930019STodd Fiala JSONString::JSONString () : 4575930019STodd Fiala JSONValue(JSONValue::Kind::String), 4675930019STodd Fiala m_data() 4775930019STodd Fiala { 4875930019STodd Fiala } 4975930019STodd Fiala 5075930019STodd Fiala JSONString::JSONString (const char* s) : 5175930019STodd Fiala JSONValue(JSONValue::Kind::String), 5275930019STodd Fiala m_data(s ? s : "") 5375930019STodd Fiala { 5475930019STodd Fiala } 5575930019STodd Fiala 5675930019STodd Fiala JSONString::JSONString (const std::string& s) : 5775930019STodd Fiala JSONValue(JSONValue::Kind::String), 5875930019STodd Fiala m_data(s) 5975930019STodd Fiala { 6075930019STodd Fiala } 6175930019STodd Fiala 6275930019STodd Fiala void 6375930019STodd Fiala JSONString::Write (std::ostream& s) 6475930019STodd Fiala { 6575930019STodd Fiala s << "\"" << json_string_quote_metachars(m_data).c_str() <<"\""; 6675930019STodd Fiala } 6775930019STodd Fiala 6875930019STodd Fiala uint64_t 6975930019STodd Fiala JSONNumber::GetAsUnsigned() const 7075930019STodd Fiala { 7175930019STodd Fiala switch (m_data_type) 7275930019STodd Fiala { 7375930019STodd Fiala case DataType::Unsigned: 7475930019STodd Fiala return m_data.m_unsigned; 7575930019STodd Fiala case DataType::Signed: 7675930019STodd Fiala return (uint64_t)m_data.m_signed; 7775930019STodd Fiala case DataType::Double: 7875930019STodd Fiala return (uint64_t)m_data.m_double; 7975930019STodd Fiala } 8075930019STodd Fiala assert("Unhandled data type"); 8175930019STodd Fiala } 8275930019STodd Fiala 8375930019STodd Fiala int64_t 8475930019STodd Fiala JSONNumber::GetAsSigned() const 8575930019STodd Fiala { 8675930019STodd Fiala switch (m_data_type) 8775930019STodd Fiala { 8875930019STodd Fiala case DataType::Unsigned: 8975930019STodd Fiala return (int64_t)m_data.m_unsigned; 9075930019STodd Fiala case DataType::Signed: 9175930019STodd Fiala return m_data.m_signed; 9275930019STodd Fiala case DataType::Double: 9375930019STodd Fiala return (int64_t)m_data.m_double; 9475930019STodd Fiala } 9575930019STodd Fiala assert("Unhandled data type"); 9675930019STodd Fiala } 9775930019STodd Fiala 9875930019STodd Fiala double 9975930019STodd Fiala JSONNumber::GetAsDouble() const 10075930019STodd Fiala { 10175930019STodd Fiala switch (m_data_type) 10275930019STodd Fiala { 10375930019STodd Fiala case DataType::Unsigned: 10475930019STodd Fiala return (double)m_data.m_unsigned; 10575930019STodd Fiala case DataType::Signed: 10675930019STodd Fiala return (double)m_data.m_signed; 10775930019STodd Fiala case DataType::Double: 10875930019STodd Fiala return m_data.m_double; 10975930019STodd Fiala } 11075930019STodd Fiala assert("Unhandled data type"); 11175930019STodd Fiala } 11275930019STodd Fiala 11375930019STodd Fiala void 11475930019STodd Fiala JSONNumber::Write (std::ostream& s) 11575930019STodd Fiala { 11675930019STodd Fiala switch (m_data_type) 11775930019STodd Fiala { 11875930019STodd Fiala case DataType::Unsigned: 11975930019STodd Fiala s << m_data.m_unsigned; 12075930019STodd Fiala break; 12175930019STodd Fiala case DataType::Signed: 12275930019STodd Fiala s << m_data.m_signed; 12375930019STodd Fiala break; 12475930019STodd Fiala case DataType::Double: 12575930019STodd Fiala // Set max precision to emulate %g. 12675930019STodd Fiala s << std::setprecision(std::numeric_limits<double>::digits10 + 1); 12775930019STodd Fiala s << m_data.m_double; 12875930019STodd Fiala break; 12975930019STodd Fiala } 13075930019STodd Fiala } 13175930019STodd Fiala 13275930019STodd Fiala JSONTrue::JSONTrue () : 13375930019STodd Fiala JSONValue(JSONValue::Kind::True) 13475930019STodd Fiala { 13575930019STodd Fiala } 13675930019STodd Fiala 13775930019STodd Fiala void 13875930019STodd Fiala JSONTrue::Write(std::ostream& s) 13975930019STodd Fiala { 14075930019STodd Fiala s << "true"; 14175930019STodd Fiala } 14275930019STodd Fiala 14375930019STodd Fiala JSONFalse::JSONFalse () : 14475930019STodd Fiala JSONValue(JSONValue::Kind::False) 14575930019STodd Fiala { 14675930019STodd Fiala } 14775930019STodd Fiala 14875930019STodd Fiala void 14975930019STodd Fiala JSONFalse::Write(std::ostream& s) 15075930019STodd Fiala { 15175930019STodd Fiala s << "false"; 15275930019STodd Fiala } 15375930019STodd Fiala 15475930019STodd Fiala JSONNull::JSONNull () : 15575930019STodd Fiala JSONValue(JSONValue::Kind::Null) 15675930019STodd Fiala { 15775930019STodd Fiala } 15875930019STodd Fiala 15975930019STodd Fiala void 16075930019STodd Fiala JSONNull::Write(std::ostream& s) 16175930019STodd Fiala { 16275930019STodd Fiala s << "null"; 16375930019STodd Fiala } 16475930019STodd Fiala 16575930019STodd Fiala JSONObject::JSONObject () : 16675930019STodd Fiala JSONValue(JSONValue::Kind::Object) 16775930019STodd Fiala { 16875930019STodd Fiala } 16975930019STodd Fiala 17075930019STodd Fiala void 17175930019STodd Fiala JSONObject::Write (std::ostream& s) 17275930019STodd Fiala { 17375930019STodd Fiala bool first = true; 17475930019STodd Fiala s << '{'; 17575930019STodd Fiala auto iter = m_elements.begin(), end = m_elements.end(); 17675930019STodd Fiala for (;iter != end; iter++) 17775930019STodd Fiala { 17875930019STodd Fiala if (first) 17975930019STodd Fiala first = false; 18075930019STodd Fiala else 18175930019STodd Fiala s << ','; 18275930019STodd Fiala JSONString key(iter->first); 18375930019STodd Fiala JSONValue::SP value(iter->second); 18475930019STodd Fiala key.Write(s); 18575930019STodd Fiala s << ':'; 18675930019STodd Fiala value->Write(s); 18775930019STodd Fiala } 18875930019STodd Fiala s << '}'; 18975930019STodd Fiala } 19075930019STodd Fiala 19175930019STodd Fiala bool 19275930019STodd Fiala JSONObject::SetObject (const std::string& key, 19375930019STodd Fiala JSONValue::SP value) 19475930019STodd Fiala { 19575930019STodd Fiala if (key.empty() || nullptr == value.get()) 19675930019STodd Fiala return false; 19775930019STodd Fiala m_elements[key] = value; 19875930019STodd Fiala return true; 19975930019STodd Fiala } 20075930019STodd Fiala 20175930019STodd Fiala JSONValue::SP 20275930019STodd Fiala JSONObject::GetObject (const std::string& key) const 20375930019STodd Fiala { 20475930019STodd Fiala auto iter = m_elements.find(key), end = m_elements.end(); 20575930019STodd Fiala if (iter == end) 20675930019STodd Fiala return JSONValue::SP(); 20775930019STodd Fiala return iter->second; 20875930019STodd Fiala } 20975930019STodd Fiala 21075930019STodd Fiala bool 21175930019STodd Fiala JSONObject::GetObjectAsBool (const std::string& key, bool& value) const 21275930019STodd Fiala { 21375930019STodd Fiala auto value_sp = GetObject(key); 21475930019STodd Fiala if (!value_sp) 21575930019STodd Fiala { 21675930019STodd Fiala // The given key doesn't exist, so we have no value. 21775930019STodd Fiala return false; 21875930019STodd Fiala } 21975930019STodd Fiala 22075930019STodd Fiala if (JSONTrue::classof(value_sp.get())) 22175930019STodd Fiala { 22275930019STodd Fiala // We have the value, and it is true. 22375930019STodd Fiala value = true; 22475930019STodd Fiala return true; 22575930019STodd Fiala } 22675930019STodd Fiala else if (JSONFalse::classof(value_sp.get())) 22775930019STodd Fiala { 22875930019STodd Fiala // We have the value, and it is false. 22975930019STodd Fiala value = false; 23075930019STodd Fiala return true; 23175930019STodd Fiala } 23275930019STodd Fiala else 23375930019STodd Fiala { 23475930019STodd Fiala // We don't have a valid bool value for the given key. 23575930019STodd Fiala return false; 23675930019STodd Fiala } 23775930019STodd Fiala } 23875930019STodd Fiala 23975930019STodd Fiala bool 24075930019STodd Fiala JSONObject::GetObjectAsString (const std::string& key, std::string& value) const 24175930019STodd Fiala { 24275930019STodd Fiala auto value_sp = GetObject(key); 24375930019STodd Fiala if (!value_sp) 24475930019STodd Fiala { 24575930019STodd Fiala // The given key doesn't exist, so we have no value. 24675930019STodd Fiala return false; 24775930019STodd Fiala } 24875930019STodd Fiala 24975930019STodd Fiala if (!JSONString::classof(value_sp.get())) 25075930019STodd Fiala return false; 25175930019STodd Fiala 25275930019STodd Fiala value = static_cast<JSONString*>(value_sp.get())->GetData(); 25375930019STodd Fiala return true; 25475930019STodd Fiala } 25575930019STodd Fiala 25675930019STodd Fiala JSONArray::JSONArray () : 25775930019STodd Fiala JSONValue(JSONValue::Kind::Array) 25875930019STodd Fiala { 25975930019STodd Fiala } 26075930019STodd Fiala 26175930019STodd Fiala void 26275930019STodd Fiala JSONArray::Write (std::ostream& s) 26375930019STodd Fiala { 26475930019STodd Fiala bool first = true; 26575930019STodd Fiala s << '['; 26675930019STodd Fiala auto iter = m_elements.begin(), end = m_elements.end(); 26775930019STodd Fiala for (;iter != end; iter++) 26875930019STodd Fiala { 26975930019STodd Fiala if (first) 27075930019STodd Fiala first = false; 27175930019STodd Fiala else 27275930019STodd Fiala s << ','; 27375930019STodd Fiala (*iter)->Write(s); 27475930019STodd Fiala } 27575930019STodd Fiala s << ']'; 27675930019STodd Fiala } 27775930019STodd Fiala 27875930019STodd Fiala bool 27975930019STodd Fiala JSONArray::SetObject (Index i, 28075930019STodd Fiala JSONValue::SP value) 28175930019STodd Fiala { 28275930019STodd Fiala if (value.get() == nullptr) 28375930019STodd Fiala return false; 28475930019STodd Fiala if (i < m_elements.size()) 28575930019STodd Fiala { 28675930019STodd Fiala m_elements[i] = value; 28775930019STodd Fiala return true; 28875930019STodd Fiala } 28975930019STodd Fiala if (i == m_elements.size()) 29075930019STodd Fiala { 29175930019STodd Fiala m_elements.push_back(value); 29275930019STodd Fiala return true; 29375930019STodd Fiala } 29475930019STodd Fiala return false; 29575930019STodd Fiala } 29675930019STodd Fiala 29775930019STodd Fiala bool 29875930019STodd Fiala JSONArray::AppendObject (JSONValue::SP value) 29975930019STodd Fiala { 30075930019STodd Fiala if (value.get() == nullptr) 30175930019STodd Fiala return false; 30275930019STodd Fiala m_elements.push_back(value); 30375930019STodd Fiala return true; 30475930019STodd Fiala } 30575930019STodd Fiala 30675930019STodd Fiala JSONValue::SP 30775930019STodd Fiala JSONArray::GetObject (Index i) 30875930019STodd Fiala { 30975930019STodd Fiala if (i < m_elements.size()) 31075930019STodd Fiala return m_elements[i]; 31175930019STodd Fiala return JSONValue::SP(); 31275930019STodd Fiala } 31375930019STodd Fiala 31475930019STodd Fiala JSONArray::Size 31575930019STodd Fiala JSONArray::GetNumElements () 31675930019STodd Fiala { 31775930019STodd Fiala return m_elements.size(); 31875930019STodd Fiala } 31975930019STodd Fiala 32075930019STodd Fiala 32175930019STodd Fiala JSONParser::JSONParser (const char *cstr) : 32275930019STodd Fiala StringExtractor(cstr) 32375930019STodd Fiala { 32475930019STodd Fiala } 32575930019STodd Fiala 32675930019STodd Fiala JSONParser::Token 32775930019STodd Fiala JSONParser::GetToken (std::string &value) 32875930019STodd Fiala { 32975930019STodd Fiala std::ostringstream error; 33075930019STodd Fiala 33175930019STodd Fiala value.clear(); 33275930019STodd Fiala SkipSpaces (); 33375930019STodd Fiala const uint64_t start_index = m_index; 33475930019STodd Fiala const char ch = GetChar(); 33575930019STodd Fiala switch (ch) 33675930019STodd Fiala { 33775930019STodd Fiala case '{': return Token::ObjectStart; 33875930019STodd Fiala case '}': return Token::ObjectEnd; 33975930019STodd Fiala case '[': return Token::ArrayStart; 34075930019STodd Fiala case ']': return Token::ArrayEnd; 34175930019STodd Fiala case ',': return Token::Comma; 34275930019STodd Fiala case ':': return Token::Colon; 34375930019STodd Fiala case '\0': return Token::EndOfFile; 34475930019STodd Fiala case 't': 34575930019STodd Fiala if (GetChar() == 'r') 34675930019STodd Fiala if (GetChar() == 'u') 34775930019STodd Fiala if (GetChar() == 'e') 34875930019STodd Fiala return Token::True; 34975930019STodd Fiala break; 35075930019STodd Fiala 35175930019STodd Fiala case 'f': 35275930019STodd Fiala if (GetChar() == 'a') 35375930019STodd Fiala if (GetChar() == 'l') 35475930019STodd Fiala if (GetChar() == 's') 35575930019STodd Fiala if (GetChar() == 'e') 35675930019STodd Fiala return Token::False; 35775930019STodd Fiala break; 35875930019STodd Fiala 35975930019STodd Fiala case 'n': 36075930019STodd Fiala if (GetChar() == 'u') 36175930019STodd Fiala if (GetChar() == 'l') 36275930019STodd Fiala if (GetChar() == 'l') 36375930019STodd Fiala return Token::Null; 36475930019STodd Fiala break; 36575930019STodd Fiala 36675930019STodd Fiala case '"': 36775930019STodd Fiala { 36875930019STodd Fiala while (1) 36975930019STodd Fiala { 37075930019STodd Fiala bool was_escaped = false; 37175930019STodd Fiala int escaped_ch = GetEscapedChar(was_escaped); 37275930019STodd Fiala if (escaped_ch == -1) 37375930019STodd Fiala { 37475930019STodd Fiala error << "error: an error occurred getting a character from offset " <<start_index; 375*c1566308SPavel Labath value = error.str(); 37675930019STodd Fiala return Token::Error; 37775930019STodd Fiala 37875930019STodd Fiala } 37975930019STodd Fiala else 38075930019STodd Fiala { 38175930019STodd Fiala const bool is_end_quote = escaped_ch == '"'; 38275930019STodd Fiala const bool is_null = escaped_ch == 0; 38375930019STodd Fiala if (was_escaped || (!is_end_quote && !is_null)) 38475930019STodd Fiala { 38575930019STodd Fiala if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX) 38675930019STodd Fiala { 38775930019STodd Fiala value.append(1, (char)escaped_ch); 38875930019STodd Fiala } 38975930019STodd Fiala else 39075930019STodd Fiala { 39175930019STodd Fiala error << "error: wide character support is needed for unicode character 0x" << std::setprecision(4) << std::hex << escaped_ch; 39275930019STodd Fiala error << " at offset " << start_index; 393*c1566308SPavel Labath value = error.str(); 39475930019STodd Fiala return Token::Error; 39575930019STodd Fiala } 39675930019STodd Fiala } 39775930019STodd Fiala else if (is_end_quote) 39875930019STodd Fiala { 39975930019STodd Fiala return Token::String; 40075930019STodd Fiala } 40175930019STodd Fiala else if (is_null) 40275930019STodd Fiala { 40375930019STodd Fiala value = "error: missing end quote for string"; 40475930019STodd Fiala return Token::Error; 40575930019STodd Fiala } 40675930019STodd Fiala } 40775930019STodd Fiala } 40875930019STodd Fiala } 40975930019STodd Fiala break; 41075930019STodd Fiala 41175930019STodd Fiala case '-': 41275930019STodd Fiala case '0': 41375930019STodd Fiala case '1': 41475930019STodd Fiala case '2': 41575930019STodd Fiala case '3': 41675930019STodd Fiala case '4': 41775930019STodd Fiala case '5': 41875930019STodd Fiala case '6': 41975930019STodd Fiala case '7': 42075930019STodd Fiala case '8': 42175930019STodd Fiala case '9': 42275930019STodd Fiala { 42375930019STodd Fiala bool done = false; 42475930019STodd Fiala bool got_decimal_point = false; 42575930019STodd Fiala uint64_t exp_index = 0; 42675930019STodd Fiala bool got_int_digits = (ch >= '0') && (ch <= '9'); 42775930019STodd Fiala bool got_frac_digits = false; 42875930019STodd Fiala bool got_exp_digits = false; 42975930019STodd Fiala while (!done) 43075930019STodd Fiala { 43175930019STodd Fiala const char next_ch = PeekChar(); 43275930019STodd Fiala switch (next_ch) 43375930019STodd Fiala { 43475930019STodd Fiala case '0': 43575930019STodd Fiala case '1': 43675930019STodd Fiala case '2': 43775930019STodd Fiala case '3': 43875930019STodd Fiala case '4': 43975930019STodd Fiala case '5': 44075930019STodd Fiala case '6': 44175930019STodd Fiala case '7': 44275930019STodd Fiala case '8': 44375930019STodd Fiala case '9': 44475930019STodd Fiala if (exp_index != 0) 44575930019STodd Fiala { 44675930019STodd Fiala got_exp_digits = true; 44775930019STodd Fiala } 44875930019STodd Fiala else if (got_decimal_point) 44975930019STodd Fiala { 45075930019STodd Fiala got_frac_digits = true; 45175930019STodd Fiala } 45275930019STodd Fiala else 45375930019STodd Fiala { 45475930019STodd Fiala got_int_digits = true; 45575930019STodd Fiala } 45675930019STodd Fiala ++m_index; // Skip this character 45775930019STodd Fiala break; 45875930019STodd Fiala 45975930019STodd Fiala case '.': 46075930019STodd Fiala if (got_decimal_point) 46175930019STodd Fiala { 46275930019STodd Fiala error << "error: extra decimal point found at offset " << start_index; 463*c1566308SPavel Labath value = error.str(); 46475930019STodd Fiala return Token::Error; 46575930019STodd Fiala } 46675930019STodd Fiala else 46775930019STodd Fiala { 46875930019STodd Fiala got_decimal_point = true; 46975930019STodd Fiala ++m_index; // Skip this character 47075930019STodd Fiala } 47175930019STodd Fiala break; 47275930019STodd Fiala 47375930019STodd Fiala case 'e': 47475930019STodd Fiala case 'E': 47575930019STodd Fiala if (exp_index != 0) 47675930019STodd Fiala { 47775930019STodd Fiala error << "error: extra exponent character found at offset " << start_index; 478*c1566308SPavel Labath value = error.str(); 47975930019STodd Fiala return Token::Error; 48075930019STodd Fiala } 48175930019STodd Fiala else 48275930019STodd Fiala { 48375930019STodd Fiala exp_index = m_index; 48475930019STodd Fiala ++m_index; // Skip this character 48575930019STodd Fiala } 48675930019STodd Fiala break; 48775930019STodd Fiala 48875930019STodd Fiala case '+': 48975930019STodd Fiala case '-': 49075930019STodd Fiala // The '+' and '-' can only come after an exponent character... 49175930019STodd Fiala if (exp_index == m_index - 1) 49275930019STodd Fiala { 49375930019STodd Fiala ++m_index; // Skip the exponent sign character 49475930019STodd Fiala } 49575930019STodd Fiala else 49675930019STodd Fiala { 49775930019STodd Fiala error << "error: unexpected " << next_ch << " character at offset " << start_index; 498*c1566308SPavel Labath value = error.str(); 49975930019STodd Fiala return Token::Error; 50075930019STodd Fiala } 50175930019STodd Fiala break; 50275930019STodd Fiala 50375930019STodd Fiala default: 50475930019STodd Fiala done = true; 50575930019STodd Fiala break; 50675930019STodd Fiala } 50775930019STodd Fiala } 50875930019STodd Fiala 50975930019STodd Fiala if (m_index > start_index) 51075930019STodd Fiala { 51175930019STodd Fiala value = m_packet.substr(start_index, m_index - start_index); 51275930019STodd Fiala if (got_decimal_point) 51375930019STodd Fiala { 51475930019STodd Fiala if (exp_index != 0) 51575930019STodd Fiala { 51675930019STodd Fiala // We have an exponent, make sure we got exponent digits 51775930019STodd Fiala if (got_exp_digits) 51875930019STodd Fiala { 51975930019STodd Fiala return Token::Float; 52075930019STodd Fiala } 52175930019STodd Fiala else 52275930019STodd Fiala { 52375930019STodd Fiala error << "error: got exponent character but no exponent digits at offset in float value \"" << value.c_str() << "\""; 524*c1566308SPavel Labath value = error.str(); 52575930019STodd Fiala return Token::Error; 52675930019STodd Fiala } 52775930019STodd Fiala } 52875930019STodd Fiala else 52975930019STodd Fiala { 53075930019STodd Fiala // No exponent, but we need at least one decimal after the decimal point 53175930019STodd Fiala if (got_frac_digits) 53275930019STodd Fiala { 53375930019STodd Fiala return Token::Float; 53475930019STodd Fiala } 53575930019STodd Fiala else 53675930019STodd Fiala { 53775930019STodd Fiala error << "error: no digits after decimal point \"" << value.c_str() << "\""; 538*c1566308SPavel Labath value = error.str(); 53975930019STodd Fiala return Token::Error; 54075930019STodd Fiala } 54175930019STodd Fiala } 54275930019STodd Fiala } 54375930019STodd Fiala else 54475930019STodd Fiala { 54575930019STodd Fiala // No decimal point 54675930019STodd Fiala if (got_int_digits) 54775930019STodd Fiala { 54875930019STodd Fiala // We need at least some integer digits to make an integer 54975930019STodd Fiala return Token::Integer; 55075930019STodd Fiala } 55175930019STodd Fiala else 55275930019STodd Fiala { 55375930019STodd Fiala error << "error: no digits negate sign \"" << value.c_str() << "\""; 554*c1566308SPavel Labath value = error.str(); 55575930019STodd Fiala return Token::Error; 55675930019STodd Fiala } 55775930019STodd Fiala } 55875930019STodd Fiala } 55975930019STodd Fiala else 56075930019STodd Fiala { 56175930019STodd Fiala error << "error: invalid number found at offset " << start_index; 562*c1566308SPavel Labath value = error.str(); 56375930019STodd Fiala return Token::Error; 56475930019STodd Fiala } 56575930019STodd Fiala } 56675930019STodd Fiala break; 56775930019STodd Fiala default: 56875930019STodd Fiala break; 56975930019STodd Fiala } 57075930019STodd Fiala error << "error: failed to parse token at offset " << start_index << " (around character '" << ch << "')"; 571*c1566308SPavel Labath value = error.str(); 57275930019STodd Fiala return Token::Error; 57375930019STodd Fiala } 57475930019STodd Fiala 57575930019STodd Fiala int 57675930019STodd Fiala JSONParser::GetEscapedChar(bool &was_escaped) 57775930019STodd Fiala { 57875930019STodd Fiala was_escaped = false; 57975930019STodd Fiala const char ch = GetChar(); 58075930019STodd Fiala if (ch == '\\') 58175930019STodd Fiala { 58275930019STodd Fiala was_escaped = true; 58375930019STodd Fiala const char ch2 = GetChar(); 58475930019STodd Fiala switch (ch2) 58575930019STodd Fiala { 58675930019STodd Fiala case '"': 58775930019STodd Fiala case '\\': 58875930019STodd Fiala case '/': 58975930019STodd Fiala default: 59075930019STodd Fiala break; 59175930019STodd Fiala 59275930019STodd Fiala case 'b': return '\b'; 59375930019STodd Fiala case 'f': return '\f'; 59475930019STodd Fiala case 'n': return '\n'; 59575930019STodd Fiala case 'r': return '\r'; 59675930019STodd Fiala case 't': return '\t'; 59775930019STodd Fiala case 'u': 59875930019STodd Fiala { 59975930019STodd Fiala const int hi_byte = DecodeHexU8(); 60075930019STodd Fiala const int lo_byte = DecodeHexU8(); 60175930019STodd Fiala if (hi_byte >=0 && lo_byte >= 0) 60275930019STodd Fiala return hi_byte << 8 | lo_byte; 60375930019STodd Fiala return -1; 60475930019STodd Fiala } 60575930019STodd Fiala break; 60675930019STodd Fiala } 60775930019STodd Fiala return ch2; 60875930019STodd Fiala } 60975930019STodd Fiala return ch; 61075930019STodd Fiala } 61175930019STodd Fiala 61275930019STodd Fiala JSONValue::SP 61375930019STodd Fiala JSONParser::ParseJSONObject () 61475930019STodd Fiala { 61575930019STodd Fiala // The "JSONParser::Token::ObjectStart" token should have already been consumed 61675930019STodd Fiala // by the time this function is called 61775930019STodd Fiala std::unique_ptr<JSONObject> dict_up(new JSONObject()); 61875930019STodd Fiala 61975930019STodd Fiala std::string value; 62075930019STodd Fiala std::string key; 62175930019STodd Fiala while (1) 62275930019STodd Fiala { 62375930019STodd Fiala JSONParser::Token token = GetToken(value); 62475930019STodd Fiala 62575930019STodd Fiala if (token == JSONParser::Token::String) 62675930019STodd Fiala { 62775930019STodd Fiala key.swap(value); 62875930019STodd Fiala token = GetToken(value); 62975930019STodd Fiala if (token == JSONParser::Token::Colon) 63075930019STodd Fiala { 63175930019STodd Fiala JSONValue::SP value_sp = ParseJSONValue(); 63275930019STodd Fiala if (value_sp) 63375930019STodd Fiala dict_up->SetObject(key, value_sp); 63475930019STodd Fiala else 63575930019STodd Fiala break; 63675930019STodd Fiala } 63775930019STodd Fiala } 63875930019STodd Fiala else if (token == JSONParser::Token::ObjectEnd) 63975930019STodd Fiala { 64075930019STodd Fiala return JSONValue::SP(dict_up.release()); 64175930019STodd Fiala } 64275930019STodd Fiala else if (token == JSONParser::Token::Comma) 64375930019STodd Fiala { 64475930019STodd Fiala continue; 64575930019STodd Fiala } 64675930019STodd Fiala else 64775930019STodd Fiala { 64875930019STodd Fiala break; 64975930019STodd Fiala } 65075930019STodd Fiala } 65175930019STodd Fiala return JSONValue::SP(); 65275930019STodd Fiala } 65375930019STodd Fiala 65475930019STodd Fiala JSONValue::SP 65575930019STodd Fiala JSONParser::ParseJSONArray () 65675930019STodd Fiala { 65775930019STodd Fiala // The "JSONParser::Token::ObjectStart" token should have already been consumed 65875930019STodd Fiala // by the time this function is called 65975930019STodd Fiala std::unique_ptr<JSONArray> array_up(new JSONArray()); 66075930019STodd Fiala 66175930019STodd Fiala std::string value; 66275930019STodd Fiala std::string key; 66375930019STodd Fiala while (1) 66475930019STodd Fiala { 66575930019STodd Fiala JSONValue::SP value_sp = ParseJSONValue(); 66675930019STodd Fiala if (value_sp) 66775930019STodd Fiala array_up->AppendObject(value_sp); 66875930019STodd Fiala else 66975930019STodd Fiala break; 67075930019STodd Fiala 67175930019STodd Fiala JSONParser::Token token = GetToken(value); 67275930019STodd Fiala if (token == JSONParser::Token::Comma) 67375930019STodd Fiala { 67475930019STodd Fiala continue; 67575930019STodd Fiala } 67675930019STodd Fiala else if (token == JSONParser::Token::ArrayEnd) 67775930019STodd Fiala { 67875930019STodd Fiala return JSONValue::SP(array_up.release()); 67975930019STodd Fiala } 68075930019STodd Fiala else 68175930019STodd Fiala { 68275930019STodd Fiala break; 68375930019STodd Fiala } 68475930019STodd Fiala } 68575930019STodd Fiala return JSONValue::SP(); 68675930019STodd Fiala } 68775930019STodd Fiala 68875930019STodd Fiala JSONValue::SP 68975930019STodd Fiala JSONParser::ParseJSONValue () 69075930019STodd Fiala { 69175930019STodd Fiala std::string value; 69275930019STodd Fiala const JSONParser::Token token = GetToken(value); 69375930019STodd Fiala switch (token) 69475930019STodd Fiala { 69575930019STodd Fiala case JSONParser::Token::ObjectStart: 69675930019STodd Fiala return ParseJSONObject(); 69775930019STodd Fiala 69875930019STodd Fiala case JSONParser::Token::ArrayStart: 69975930019STodd Fiala return ParseJSONArray(); 70075930019STodd Fiala 70175930019STodd Fiala case JSONParser::Token::Integer: 70275930019STodd Fiala { 70375930019STodd Fiala if (value.front() == '-') 70475930019STodd Fiala { 70575930019STodd Fiala bool success = false; 70675930019STodd Fiala int64_t sval = StringConvert::ToSInt64(value.c_str(), 0, 0, &success); 70775930019STodd Fiala if (success) 70875930019STodd Fiala return JSONValue::SP(new JSONNumber(sval)); 70975930019STodd Fiala } 71075930019STodd Fiala else 71175930019STodd Fiala { 71275930019STodd Fiala bool success = false; 71375930019STodd Fiala uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success); 71475930019STodd Fiala if (success) 71575930019STodd Fiala return JSONValue::SP(new JSONNumber(uval)); 71675930019STodd Fiala } 71775930019STodd Fiala } 71875930019STodd Fiala break; 71975930019STodd Fiala 72075930019STodd Fiala case JSONParser::Token::Float: 72175930019STodd Fiala { 72275930019STodd Fiala bool success = false; 72375930019STodd Fiala double val = StringConvert::ToDouble(value.c_str(), 0.0, &success); 72475930019STodd Fiala if (success) 72575930019STodd Fiala return JSONValue::SP(new JSONNumber(val)); 72675930019STodd Fiala } 72775930019STodd Fiala break; 72875930019STodd Fiala 72975930019STodd Fiala case JSONParser::Token::String: 73075930019STodd Fiala return JSONValue::SP(new JSONString(value)); 73175930019STodd Fiala 73275930019STodd Fiala case JSONParser::Token::True: 73375930019STodd Fiala return JSONValue::SP(new JSONTrue()); 73475930019STodd Fiala 73575930019STodd Fiala case JSONParser::Token::False: 73675930019STodd Fiala return JSONValue::SP(new JSONFalse()); 73775930019STodd Fiala 73875930019STodd Fiala case JSONParser::Token::Null: 73975930019STodd Fiala return JSONValue::SP(new JSONNull()); 74075930019STodd Fiala 74175930019STodd Fiala default: 74275930019STodd Fiala break; 74375930019STodd Fiala } 74475930019STodd Fiala return JSONValue::SP(); 74575930019STodd Fiala 74675930019STodd Fiala } 747