1*75930019STodd Fiala //===--------------------- JSON.cpp -----------------------------*- C++ -*-===// 2*75930019STodd Fiala // 3*75930019STodd Fiala // The LLVM Compiler Infrastructure 4*75930019STodd Fiala // 5*75930019STodd Fiala // This file is distributed under the University of Illinois Open Source 6*75930019STodd Fiala // License. See LICENSE.TXT for details. 7*75930019STodd Fiala // 8*75930019STodd Fiala //===----------------------------------------------------------------------===// 9*75930019STodd Fiala 10*75930019STodd Fiala #include "JSON.h" 11*75930019STodd Fiala 12*75930019STodd Fiala // C includes 13*75930019STodd Fiala #include <assert.h> 14*75930019STodd Fiala #include <limits.h> 15*75930019STodd Fiala 16*75930019STodd Fiala // C++ includes 17*75930019STodd Fiala #include <iomanip> 18*75930019STodd Fiala #include <sstream> 19*75930019STodd Fiala #include "lldb/Host/StringConvert.h" 20*75930019STodd Fiala 21*75930019STodd Fiala using namespace lldb_private; 22*75930019STodd Fiala 23*75930019STodd Fiala std::string 24*75930019STodd Fiala JSONString::json_string_quote_metachars (const std::string &s) 25*75930019STodd Fiala { 26*75930019STodd Fiala if (s.find('"') == std::string::npos) 27*75930019STodd Fiala return s; 28*75930019STodd Fiala 29*75930019STodd Fiala std::string output; 30*75930019STodd Fiala const size_t s_size = s.size(); 31*75930019STodd Fiala const char *s_chars = s.c_str(); 32*75930019STodd Fiala for (size_t i = 0; i < s_size; i++) 33*75930019STodd Fiala { 34*75930019STodd Fiala unsigned char ch = *(s_chars + i); 35*75930019STodd Fiala if (ch == '"') 36*75930019STodd Fiala { 37*75930019STodd Fiala output.push_back ('\\'); 38*75930019STodd Fiala } 39*75930019STodd Fiala output.push_back (ch); 40*75930019STodd Fiala } 41*75930019STodd Fiala return output; 42*75930019STodd Fiala } 43*75930019STodd Fiala 44*75930019STodd Fiala JSONString::JSONString () : 45*75930019STodd Fiala JSONValue(JSONValue::Kind::String), 46*75930019STodd Fiala m_data() 47*75930019STodd Fiala { 48*75930019STodd Fiala } 49*75930019STodd Fiala 50*75930019STodd Fiala JSONString::JSONString (const char* s) : 51*75930019STodd Fiala JSONValue(JSONValue::Kind::String), 52*75930019STodd Fiala m_data(s ? s : "") 53*75930019STodd Fiala { 54*75930019STodd Fiala } 55*75930019STodd Fiala 56*75930019STodd Fiala JSONString::JSONString (const std::string& s) : 57*75930019STodd Fiala JSONValue(JSONValue::Kind::String), 58*75930019STodd Fiala m_data(s) 59*75930019STodd Fiala { 60*75930019STodd Fiala } 61*75930019STodd Fiala 62*75930019STodd Fiala void 63*75930019STodd Fiala JSONString::Write (std::ostream& s) 64*75930019STodd Fiala { 65*75930019STodd Fiala s << "\"" << json_string_quote_metachars(m_data).c_str() <<"\""; 66*75930019STodd Fiala } 67*75930019STodd Fiala 68*75930019STodd Fiala uint64_t 69*75930019STodd Fiala JSONNumber::GetAsUnsigned() const 70*75930019STodd Fiala { 71*75930019STodd Fiala switch (m_data_type) 72*75930019STodd Fiala { 73*75930019STodd Fiala case DataType::Unsigned: 74*75930019STodd Fiala return m_data.m_unsigned; 75*75930019STodd Fiala case DataType::Signed: 76*75930019STodd Fiala return (uint64_t)m_data.m_signed; 77*75930019STodd Fiala case DataType::Double: 78*75930019STodd Fiala return (uint64_t)m_data.m_double; 79*75930019STodd Fiala } 80*75930019STodd Fiala assert("Unhandled data type"); 81*75930019STodd Fiala } 82*75930019STodd Fiala 83*75930019STodd Fiala int64_t 84*75930019STodd Fiala JSONNumber::GetAsSigned() const 85*75930019STodd Fiala { 86*75930019STodd Fiala switch (m_data_type) 87*75930019STodd Fiala { 88*75930019STodd Fiala case DataType::Unsigned: 89*75930019STodd Fiala return (int64_t)m_data.m_unsigned; 90*75930019STodd Fiala case DataType::Signed: 91*75930019STodd Fiala return m_data.m_signed; 92*75930019STodd Fiala case DataType::Double: 93*75930019STodd Fiala return (int64_t)m_data.m_double; 94*75930019STodd Fiala } 95*75930019STodd Fiala assert("Unhandled data type"); 96*75930019STodd Fiala } 97*75930019STodd Fiala 98*75930019STodd Fiala double 99*75930019STodd Fiala JSONNumber::GetAsDouble() const 100*75930019STodd Fiala { 101*75930019STodd Fiala switch (m_data_type) 102*75930019STodd Fiala { 103*75930019STodd Fiala case DataType::Unsigned: 104*75930019STodd Fiala return (double)m_data.m_unsigned; 105*75930019STodd Fiala case DataType::Signed: 106*75930019STodd Fiala return (double)m_data.m_signed; 107*75930019STodd Fiala case DataType::Double: 108*75930019STodd Fiala return m_data.m_double; 109*75930019STodd Fiala } 110*75930019STodd Fiala assert("Unhandled data type"); 111*75930019STodd Fiala } 112*75930019STodd Fiala 113*75930019STodd Fiala void 114*75930019STodd Fiala JSONNumber::Write (std::ostream& s) 115*75930019STodd Fiala { 116*75930019STodd Fiala switch (m_data_type) 117*75930019STodd Fiala { 118*75930019STodd Fiala case DataType::Unsigned: 119*75930019STodd Fiala s << m_data.m_unsigned; 120*75930019STodd Fiala break; 121*75930019STodd Fiala case DataType::Signed: 122*75930019STodd Fiala s << m_data.m_signed; 123*75930019STodd Fiala break; 124*75930019STodd Fiala case DataType::Double: 125*75930019STodd Fiala // Set max precision to emulate %g. 126*75930019STodd Fiala s << std::setprecision(std::numeric_limits<double>::digits10 + 1); 127*75930019STodd Fiala s << m_data.m_double; 128*75930019STodd Fiala break; 129*75930019STodd Fiala } 130*75930019STodd Fiala } 131*75930019STodd Fiala 132*75930019STodd Fiala JSONTrue::JSONTrue () : 133*75930019STodd Fiala JSONValue(JSONValue::Kind::True) 134*75930019STodd Fiala { 135*75930019STodd Fiala } 136*75930019STodd Fiala 137*75930019STodd Fiala void 138*75930019STodd Fiala JSONTrue::Write(std::ostream& s) 139*75930019STodd Fiala { 140*75930019STodd Fiala s << "true"; 141*75930019STodd Fiala } 142*75930019STodd Fiala 143*75930019STodd Fiala JSONFalse::JSONFalse () : 144*75930019STodd Fiala JSONValue(JSONValue::Kind::False) 145*75930019STodd Fiala { 146*75930019STodd Fiala } 147*75930019STodd Fiala 148*75930019STodd Fiala void 149*75930019STodd Fiala JSONFalse::Write(std::ostream& s) 150*75930019STodd Fiala { 151*75930019STodd Fiala s << "false"; 152*75930019STodd Fiala } 153*75930019STodd Fiala 154*75930019STodd Fiala JSONNull::JSONNull () : 155*75930019STodd Fiala JSONValue(JSONValue::Kind::Null) 156*75930019STodd Fiala { 157*75930019STodd Fiala } 158*75930019STodd Fiala 159*75930019STodd Fiala void 160*75930019STodd Fiala JSONNull::Write(std::ostream& s) 161*75930019STodd Fiala { 162*75930019STodd Fiala s << "null"; 163*75930019STodd Fiala } 164*75930019STodd Fiala 165*75930019STodd Fiala JSONObject::JSONObject () : 166*75930019STodd Fiala JSONValue(JSONValue::Kind::Object) 167*75930019STodd Fiala { 168*75930019STodd Fiala } 169*75930019STodd Fiala 170*75930019STodd Fiala void 171*75930019STodd Fiala JSONObject::Write (std::ostream& s) 172*75930019STodd Fiala { 173*75930019STodd Fiala bool first = true; 174*75930019STodd Fiala s << '{'; 175*75930019STodd Fiala auto iter = m_elements.begin(), end = m_elements.end(); 176*75930019STodd Fiala for (;iter != end; iter++) 177*75930019STodd Fiala { 178*75930019STodd Fiala if (first) 179*75930019STodd Fiala first = false; 180*75930019STodd Fiala else 181*75930019STodd Fiala s << ','; 182*75930019STodd Fiala JSONString key(iter->first); 183*75930019STodd Fiala JSONValue::SP value(iter->second); 184*75930019STodd Fiala key.Write(s); 185*75930019STodd Fiala s << ':'; 186*75930019STodd Fiala value->Write(s); 187*75930019STodd Fiala } 188*75930019STodd Fiala s << '}'; 189*75930019STodd Fiala } 190*75930019STodd Fiala 191*75930019STodd Fiala bool 192*75930019STodd Fiala JSONObject::SetObject (const std::string& key, 193*75930019STodd Fiala JSONValue::SP value) 194*75930019STodd Fiala { 195*75930019STodd Fiala if (key.empty() || nullptr == value.get()) 196*75930019STodd Fiala return false; 197*75930019STodd Fiala m_elements[key] = value; 198*75930019STodd Fiala return true; 199*75930019STodd Fiala } 200*75930019STodd Fiala 201*75930019STodd Fiala JSONValue::SP 202*75930019STodd Fiala JSONObject::GetObject (const std::string& key) const 203*75930019STodd Fiala { 204*75930019STodd Fiala auto iter = m_elements.find(key), end = m_elements.end(); 205*75930019STodd Fiala if (iter == end) 206*75930019STodd Fiala return JSONValue::SP(); 207*75930019STodd Fiala return iter->second; 208*75930019STodd Fiala } 209*75930019STodd Fiala 210*75930019STodd Fiala bool 211*75930019STodd Fiala JSONObject::GetObjectAsBool (const std::string& key, bool& value) const 212*75930019STodd Fiala { 213*75930019STodd Fiala auto value_sp = GetObject(key); 214*75930019STodd Fiala if (!value_sp) 215*75930019STodd Fiala { 216*75930019STodd Fiala // The given key doesn't exist, so we have no value. 217*75930019STodd Fiala return false; 218*75930019STodd Fiala } 219*75930019STodd Fiala 220*75930019STodd Fiala if (JSONTrue::classof(value_sp.get())) 221*75930019STodd Fiala { 222*75930019STodd Fiala // We have the value, and it is true. 223*75930019STodd Fiala value = true; 224*75930019STodd Fiala return true; 225*75930019STodd Fiala } 226*75930019STodd Fiala else if (JSONFalse::classof(value_sp.get())) 227*75930019STodd Fiala { 228*75930019STodd Fiala // We have the value, and it is false. 229*75930019STodd Fiala value = false; 230*75930019STodd Fiala return true; 231*75930019STodd Fiala } 232*75930019STodd Fiala else 233*75930019STodd Fiala { 234*75930019STodd Fiala // We don't have a valid bool value for the given key. 235*75930019STodd Fiala return false; 236*75930019STodd Fiala } 237*75930019STodd Fiala } 238*75930019STodd Fiala 239*75930019STodd Fiala bool 240*75930019STodd Fiala JSONObject::GetObjectAsString (const std::string& key, std::string& value) const 241*75930019STodd Fiala { 242*75930019STodd Fiala auto value_sp = GetObject(key); 243*75930019STodd Fiala if (!value_sp) 244*75930019STodd Fiala { 245*75930019STodd Fiala // The given key doesn't exist, so we have no value. 246*75930019STodd Fiala return false; 247*75930019STodd Fiala } 248*75930019STodd Fiala 249*75930019STodd Fiala if (!JSONString::classof(value_sp.get())) 250*75930019STodd Fiala return false; 251*75930019STodd Fiala 252*75930019STodd Fiala value = static_cast<JSONString*>(value_sp.get())->GetData(); 253*75930019STodd Fiala return true; 254*75930019STodd Fiala } 255*75930019STodd Fiala 256*75930019STodd Fiala JSONArray::JSONArray () : 257*75930019STodd Fiala JSONValue(JSONValue::Kind::Array) 258*75930019STodd Fiala { 259*75930019STodd Fiala } 260*75930019STodd Fiala 261*75930019STodd Fiala void 262*75930019STodd Fiala JSONArray::Write (std::ostream& s) 263*75930019STodd Fiala { 264*75930019STodd Fiala bool first = true; 265*75930019STodd Fiala s << '['; 266*75930019STodd Fiala auto iter = m_elements.begin(), end = m_elements.end(); 267*75930019STodd Fiala for (;iter != end; iter++) 268*75930019STodd Fiala { 269*75930019STodd Fiala if (first) 270*75930019STodd Fiala first = false; 271*75930019STodd Fiala else 272*75930019STodd Fiala s << ','; 273*75930019STodd Fiala (*iter)->Write(s); 274*75930019STodd Fiala } 275*75930019STodd Fiala s << ']'; 276*75930019STodd Fiala } 277*75930019STodd Fiala 278*75930019STodd Fiala bool 279*75930019STodd Fiala JSONArray::SetObject (Index i, 280*75930019STodd Fiala JSONValue::SP value) 281*75930019STodd Fiala { 282*75930019STodd Fiala if (value.get() == nullptr) 283*75930019STodd Fiala return false; 284*75930019STodd Fiala if (i < m_elements.size()) 285*75930019STodd Fiala { 286*75930019STodd Fiala m_elements[i] = value; 287*75930019STodd Fiala return true; 288*75930019STodd Fiala } 289*75930019STodd Fiala if (i == m_elements.size()) 290*75930019STodd Fiala { 291*75930019STodd Fiala m_elements.push_back(value); 292*75930019STodd Fiala return true; 293*75930019STodd Fiala } 294*75930019STodd Fiala return false; 295*75930019STodd Fiala } 296*75930019STodd Fiala 297*75930019STodd Fiala bool 298*75930019STodd Fiala JSONArray::AppendObject (JSONValue::SP value) 299*75930019STodd Fiala { 300*75930019STodd Fiala if (value.get() == nullptr) 301*75930019STodd Fiala return false; 302*75930019STodd Fiala m_elements.push_back(value); 303*75930019STodd Fiala return true; 304*75930019STodd Fiala } 305*75930019STodd Fiala 306*75930019STodd Fiala JSONValue::SP 307*75930019STodd Fiala JSONArray::GetObject (Index i) 308*75930019STodd Fiala { 309*75930019STodd Fiala if (i < m_elements.size()) 310*75930019STodd Fiala return m_elements[i]; 311*75930019STodd Fiala return JSONValue::SP(); 312*75930019STodd Fiala } 313*75930019STodd Fiala 314*75930019STodd Fiala JSONArray::Size 315*75930019STodd Fiala JSONArray::GetNumElements () 316*75930019STodd Fiala { 317*75930019STodd Fiala return m_elements.size(); 318*75930019STodd Fiala } 319*75930019STodd Fiala 320*75930019STodd Fiala 321*75930019STodd Fiala JSONParser::JSONParser (const char *cstr) : 322*75930019STodd Fiala StringExtractor(cstr) 323*75930019STodd Fiala { 324*75930019STodd Fiala } 325*75930019STodd Fiala 326*75930019STodd Fiala JSONParser::Token 327*75930019STodd Fiala JSONParser::GetToken (std::string &value) 328*75930019STodd Fiala { 329*75930019STodd Fiala std::ostringstream error; 330*75930019STodd Fiala 331*75930019STodd Fiala value.clear(); 332*75930019STodd Fiala SkipSpaces (); 333*75930019STodd Fiala const uint64_t start_index = m_index; 334*75930019STodd Fiala const char ch = GetChar(); 335*75930019STodd Fiala switch (ch) 336*75930019STodd Fiala { 337*75930019STodd Fiala case '{': return Token::ObjectStart; 338*75930019STodd Fiala case '}': return Token::ObjectEnd; 339*75930019STodd Fiala case '[': return Token::ArrayStart; 340*75930019STodd Fiala case ']': return Token::ArrayEnd; 341*75930019STodd Fiala case ',': return Token::Comma; 342*75930019STodd Fiala case ':': return Token::Colon; 343*75930019STodd Fiala case '\0': return Token::EndOfFile; 344*75930019STodd Fiala case 't': 345*75930019STodd Fiala if (GetChar() == 'r') 346*75930019STodd Fiala if (GetChar() == 'u') 347*75930019STodd Fiala if (GetChar() == 'e') 348*75930019STodd Fiala return Token::True; 349*75930019STodd Fiala break; 350*75930019STodd Fiala 351*75930019STodd Fiala case 'f': 352*75930019STodd Fiala if (GetChar() == 'a') 353*75930019STodd Fiala if (GetChar() == 'l') 354*75930019STodd Fiala if (GetChar() == 's') 355*75930019STodd Fiala if (GetChar() == 'e') 356*75930019STodd Fiala return Token::False; 357*75930019STodd Fiala break; 358*75930019STodd Fiala 359*75930019STodd Fiala case 'n': 360*75930019STodd Fiala if (GetChar() == 'u') 361*75930019STodd Fiala if (GetChar() == 'l') 362*75930019STodd Fiala if (GetChar() == 'l') 363*75930019STodd Fiala return Token::Null; 364*75930019STodd Fiala break; 365*75930019STodd Fiala 366*75930019STodd Fiala case '"': 367*75930019STodd Fiala { 368*75930019STodd Fiala while (1) 369*75930019STodd Fiala { 370*75930019STodd Fiala bool was_escaped = false; 371*75930019STodd Fiala int escaped_ch = GetEscapedChar(was_escaped); 372*75930019STodd Fiala if (escaped_ch == -1) 373*75930019STodd Fiala { 374*75930019STodd Fiala error << "error: an error occurred getting a character from offset " <<start_index; 375*75930019STodd Fiala value = std::move(error.str()); 376*75930019STodd Fiala return Token::Error; 377*75930019STodd Fiala 378*75930019STodd Fiala } 379*75930019STodd Fiala else 380*75930019STodd Fiala { 381*75930019STodd Fiala const bool is_end_quote = escaped_ch == '"'; 382*75930019STodd Fiala const bool is_null = escaped_ch == 0; 383*75930019STodd Fiala if (was_escaped || (!is_end_quote && !is_null)) 384*75930019STodd Fiala { 385*75930019STodd Fiala if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX) 386*75930019STodd Fiala { 387*75930019STodd Fiala value.append(1, (char)escaped_ch); 388*75930019STodd Fiala } 389*75930019STodd Fiala else 390*75930019STodd Fiala { 391*75930019STodd Fiala error << "error: wide character support is needed for unicode character 0x" << std::setprecision(4) << std::hex << escaped_ch; 392*75930019STodd Fiala error << " at offset " << start_index; 393*75930019STodd Fiala value = std::move(error.str()); 394*75930019STodd Fiala return Token::Error; 395*75930019STodd Fiala } 396*75930019STodd Fiala } 397*75930019STodd Fiala else if (is_end_quote) 398*75930019STodd Fiala { 399*75930019STodd Fiala return Token::String; 400*75930019STodd Fiala } 401*75930019STodd Fiala else if (is_null) 402*75930019STodd Fiala { 403*75930019STodd Fiala value = "error: missing end quote for string"; 404*75930019STodd Fiala return Token::Error; 405*75930019STodd Fiala } 406*75930019STodd Fiala } 407*75930019STodd Fiala } 408*75930019STodd Fiala } 409*75930019STodd Fiala break; 410*75930019STodd Fiala 411*75930019STodd Fiala case '-': 412*75930019STodd Fiala case '0': 413*75930019STodd Fiala case '1': 414*75930019STodd Fiala case '2': 415*75930019STodd Fiala case '3': 416*75930019STodd Fiala case '4': 417*75930019STodd Fiala case '5': 418*75930019STodd Fiala case '6': 419*75930019STodd Fiala case '7': 420*75930019STodd Fiala case '8': 421*75930019STodd Fiala case '9': 422*75930019STodd Fiala { 423*75930019STodd Fiala bool done = false; 424*75930019STodd Fiala bool got_decimal_point = false; 425*75930019STodd Fiala uint64_t exp_index = 0; 426*75930019STodd Fiala bool got_int_digits = (ch >= '0') && (ch <= '9'); 427*75930019STodd Fiala bool got_frac_digits = false; 428*75930019STodd Fiala bool got_exp_digits = false; 429*75930019STodd Fiala while (!done) 430*75930019STodd Fiala { 431*75930019STodd Fiala const char next_ch = PeekChar(); 432*75930019STodd Fiala switch (next_ch) 433*75930019STodd Fiala { 434*75930019STodd Fiala case '0': 435*75930019STodd Fiala case '1': 436*75930019STodd Fiala case '2': 437*75930019STodd Fiala case '3': 438*75930019STodd Fiala case '4': 439*75930019STodd Fiala case '5': 440*75930019STodd Fiala case '6': 441*75930019STodd Fiala case '7': 442*75930019STodd Fiala case '8': 443*75930019STodd Fiala case '9': 444*75930019STodd Fiala if (exp_index != 0) 445*75930019STodd Fiala { 446*75930019STodd Fiala got_exp_digits = true; 447*75930019STodd Fiala } 448*75930019STodd Fiala else if (got_decimal_point) 449*75930019STodd Fiala { 450*75930019STodd Fiala got_frac_digits = true; 451*75930019STodd Fiala } 452*75930019STodd Fiala else 453*75930019STodd Fiala { 454*75930019STodd Fiala got_int_digits = true; 455*75930019STodd Fiala } 456*75930019STodd Fiala ++m_index; // Skip this character 457*75930019STodd Fiala break; 458*75930019STodd Fiala 459*75930019STodd Fiala case '.': 460*75930019STodd Fiala if (got_decimal_point) 461*75930019STodd Fiala { 462*75930019STodd Fiala error << "error: extra decimal point found at offset " << start_index; 463*75930019STodd Fiala value = std::move(error.str()); 464*75930019STodd Fiala return Token::Error; 465*75930019STodd Fiala } 466*75930019STodd Fiala else 467*75930019STodd Fiala { 468*75930019STodd Fiala got_decimal_point = true; 469*75930019STodd Fiala ++m_index; // Skip this character 470*75930019STodd Fiala } 471*75930019STodd Fiala break; 472*75930019STodd Fiala 473*75930019STodd Fiala case 'e': 474*75930019STodd Fiala case 'E': 475*75930019STodd Fiala if (exp_index != 0) 476*75930019STodd Fiala { 477*75930019STodd Fiala error << "error: extra exponent character found at offset " << start_index; 478*75930019STodd Fiala value = std::move(error.str()); 479*75930019STodd Fiala return Token::Error; 480*75930019STodd Fiala } 481*75930019STodd Fiala else 482*75930019STodd Fiala { 483*75930019STodd Fiala exp_index = m_index; 484*75930019STodd Fiala ++m_index; // Skip this character 485*75930019STodd Fiala } 486*75930019STodd Fiala break; 487*75930019STodd Fiala 488*75930019STodd Fiala case '+': 489*75930019STodd Fiala case '-': 490*75930019STodd Fiala // The '+' and '-' can only come after an exponent character... 491*75930019STodd Fiala if (exp_index == m_index - 1) 492*75930019STodd Fiala { 493*75930019STodd Fiala ++m_index; // Skip the exponent sign character 494*75930019STodd Fiala } 495*75930019STodd Fiala else 496*75930019STodd Fiala { 497*75930019STodd Fiala error << "error: unexpected " << next_ch << " character at offset " << start_index; 498*75930019STodd Fiala value = std::move(error.str()); 499*75930019STodd Fiala return Token::Error; 500*75930019STodd Fiala } 501*75930019STodd Fiala break; 502*75930019STodd Fiala 503*75930019STodd Fiala default: 504*75930019STodd Fiala done = true; 505*75930019STodd Fiala break; 506*75930019STodd Fiala } 507*75930019STodd Fiala } 508*75930019STodd Fiala 509*75930019STodd Fiala if (m_index > start_index) 510*75930019STodd Fiala { 511*75930019STodd Fiala value = m_packet.substr(start_index, m_index - start_index); 512*75930019STodd Fiala if (got_decimal_point) 513*75930019STodd Fiala { 514*75930019STodd Fiala if (exp_index != 0) 515*75930019STodd Fiala { 516*75930019STodd Fiala // We have an exponent, make sure we got exponent digits 517*75930019STodd Fiala if (got_exp_digits) 518*75930019STodd Fiala { 519*75930019STodd Fiala return Token::Float; 520*75930019STodd Fiala } 521*75930019STodd Fiala else 522*75930019STodd Fiala { 523*75930019STodd Fiala error << "error: got exponent character but no exponent digits at offset in float value \"" << value.c_str() << "\""; 524*75930019STodd Fiala value = std::move(error.str()); 525*75930019STodd Fiala return Token::Error; 526*75930019STodd Fiala } 527*75930019STodd Fiala } 528*75930019STodd Fiala else 529*75930019STodd Fiala { 530*75930019STodd Fiala // No exponent, but we need at least one decimal after the decimal point 531*75930019STodd Fiala if (got_frac_digits) 532*75930019STodd Fiala { 533*75930019STodd Fiala return Token::Float; 534*75930019STodd Fiala } 535*75930019STodd Fiala else 536*75930019STodd Fiala { 537*75930019STodd Fiala error << "error: no digits after decimal point \"" << value.c_str() << "\""; 538*75930019STodd Fiala value = std::move(error.str()); 539*75930019STodd Fiala return Token::Error; 540*75930019STodd Fiala } 541*75930019STodd Fiala } 542*75930019STodd Fiala } 543*75930019STodd Fiala else 544*75930019STodd Fiala { 545*75930019STodd Fiala // No decimal point 546*75930019STodd Fiala if (got_int_digits) 547*75930019STodd Fiala { 548*75930019STodd Fiala // We need at least some integer digits to make an integer 549*75930019STodd Fiala return Token::Integer; 550*75930019STodd Fiala } 551*75930019STodd Fiala else 552*75930019STodd Fiala { 553*75930019STodd Fiala error << "error: no digits negate sign \"" << value.c_str() << "\""; 554*75930019STodd Fiala value = std::move(error.str()); 555*75930019STodd Fiala return Token::Error; 556*75930019STodd Fiala } 557*75930019STodd Fiala } 558*75930019STodd Fiala } 559*75930019STodd Fiala else 560*75930019STodd Fiala { 561*75930019STodd Fiala error << "error: invalid number found at offset " << start_index; 562*75930019STodd Fiala value = std::move(error.str()); 563*75930019STodd Fiala return Token::Error; 564*75930019STodd Fiala } 565*75930019STodd Fiala } 566*75930019STodd Fiala break; 567*75930019STodd Fiala default: 568*75930019STodd Fiala break; 569*75930019STodd Fiala } 570*75930019STodd Fiala error << "error: failed to parse token at offset " << start_index << " (around character '" << ch << "')"; 571*75930019STodd Fiala value = std::move(error.str()); 572*75930019STodd Fiala return Token::Error; 573*75930019STodd Fiala } 574*75930019STodd Fiala 575*75930019STodd Fiala int 576*75930019STodd Fiala JSONParser::GetEscapedChar(bool &was_escaped) 577*75930019STodd Fiala { 578*75930019STodd Fiala was_escaped = false; 579*75930019STodd Fiala const char ch = GetChar(); 580*75930019STodd Fiala if (ch == '\\') 581*75930019STodd Fiala { 582*75930019STodd Fiala was_escaped = true; 583*75930019STodd Fiala const char ch2 = GetChar(); 584*75930019STodd Fiala switch (ch2) 585*75930019STodd Fiala { 586*75930019STodd Fiala case '"': 587*75930019STodd Fiala case '\\': 588*75930019STodd Fiala case '/': 589*75930019STodd Fiala default: 590*75930019STodd Fiala break; 591*75930019STodd Fiala 592*75930019STodd Fiala case 'b': return '\b'; 593*75930019STodd Fiala case 'f': return '\f'; 594*75930019STodd Fiala case 'n': return '\n'; 595*75930019STodd Fiala case 'r': return '\r'; 596*75930019STodd Fiala case 't': return '\t'; 597*75930019STodd Fiala case 'u': 598*75930019STodd Fiala { 599*75930019STodd Fiala const int hi_byte = DecodeHexU8(); 600*75930019STodd Fiala const int lo_byte = DecodeHexU8(); 601*75930019STodd Fiala if (hi_byte >=0 && lo_byte >= 0) 602*75930019STodd Fiala return hi_byte << 8 | lo_byte; 603*75930019STodd Fiala return -1; 604*75930019STodd Fiala } 605*75930019STodd Fiala break; 606*75930019STodd Fiala } 607*75930019STodd Fiala return ch2; 608*75930019STodd Fiala } 609*75930019STodd Fiala return ch; 610*75930019STodd Fiala } 611*75930019STodd Fiala 612*75930019STodd Fiala JSONValue::SP 613*75930019STodd Fiala JSONParser::ParseJSONObject () 614*75930019STodd Fiala { 615*75930019STodd Fiala // The "JSONParser::Token::ObjectStart" token should have already been consumed 616*75930019STodd Fiala // by the time this function is called 617*75930019STodd Fiala std::unique_ptr<JSONObject> dict_up(new JSONObject()); 618*75930019STodd Fiala 619*75930019STodd Fiala std::string value; 620*75930019STodd Fiala std::string key; 621*75930019STodd Fiala while (1) 622*75930019STodd Fiala { 623*75930019STodd Fiala JSONParser::Token token = GetToken(value); 624*75930019STodd Fiala 625*75930019STodd Fiala if (token == JSONParser::Token::String) 626*75930019STodd Fiala { 627*75930019STodd Fiala key.swap(value); 628*75930019STodd Fiala token = GetToken(value); 629*75930019STodd Fiala if (token == JSONParser::Token::Colon) 630*75930019STodd Fiala { 631*75930019STodd Fiala JSONValue::SP value_sp = ParseJSONValue(); 632*75930019STodd Fiala if (value_sp) 633*75930019STodd Fiala dict_up->SetObject(key, value_sp); 634*75930019STodd Fiala else 635*75930019STodd Fiala break; 636*75930019STodd Fiala } 637*75930019STodd Fiala } 638*75930019STodd Fiala else if (token == JSONParser::Token::ObjectEnd) 639*75930019STodd Fiala { 640*75930019STodd Fiala return JSONValue::SP(dict_up.release()); 641*75930019STodd Fiala } 642*75930019STodd Fiala else if (token == JSONParser::Token::Comma) 643*75930019STodd Fiala { 644*75930019STodd Fiala continue; 645*75930019STodd Fiala } 646*75930019STodd Fiala else 647*75930019STodd Fiala { 648*75930019STodd Fiala break; 649*75930019STodd Fiala } 650*75930019STodd Fiala } 651*75930019STodd Fiala return JSONValue::SP(); 652*75930019STodd Fiala } 653*75930019STodd Fiala 654*75930019STodd Fiala JSONValue::SP 655*75930019STodd Fiala JSONParser::ParseJSONArray () 656*75930019STodd Fiala { 657*75930019STodd Fiala // The "JSONParser::Token::ObjectStart" token should have already been consumed 658*75930019STodd Fiala // by the time this function is called 659*75930019STodd Fiala std::unique_ptr<JSONArray> array_up(new JSONArray()); 660*75930019STodd Fiala 661*75930019STodd Fiala std::string value; 662*75930019STodd Fiala std::string key; 663*75930019STodd Fiala while (1) 664*75930019STodd Fiala { 665*75930019STodd Fiala JSONValue::SP value_sp = ParseJSONValue(); 666*75930019STodd Fiala if (value_sp) 667*75930019STodd Fiala array_up->AppendObject(value_sp); 668*75930019STodd Fiala else 669*75930019STodd Fiala break; 670*75930019STodd Fiala 671*75930019STodd Fiala JSONParser::Token token = GetToken(value); 672*75930019STodd Fiala if (token == JSONParser::Token::Comma) 673*75930019STodd Fiala { 674*75930019STodd Fiala continue; 675*75930019STodd Fiala } 676*75930019STodd Fiala else if (token == JSONParser::Token::ArrayEnd) 677*75930019STodd Fiala { 678*75930019STodd Fiala return JSONValue::SP(array_up.release()); 679*75930019STodd Fiala } 680*75930019STodd Fiala else 681*75930019STodd Fiala { 682*75930019STodd Fiala break; 683*75930019STodd Fiala } 684*75930019STodd Fiala } 685*75930019STodd Fiala return JSONValue::SP(); 686*75930019STodd Fiala } 687*75930019STodd Fiala 688*75930019STodd Fiala JSONValue::SP 689*75930019STodd Fiala JSONParser::ParseJSONValue () 690*75930019STodd Fiala { 691*75930019STodd Fiala std::string value; 692*75930019STodd Fiala const JSONParser::Token token = GetToken(value); 693*75930019STodd Fiala switch (token) 694*75930019STodd Fiala { 695*75930019STodd Fiala case JSONParser::Token::ObjectStart: 696*75930019STodd Fiala return ParseJSONObject(); 697*75930019STodd Fiala 698*75930019STodd Fiala case JSONParser::Token::ArrayStart: 699*75930019STodd Fiala return ParseJSONArray(); 700*75930019STodd Fiala 701*75930019STodd Fiala case JSONParser::Token::Integer: 702*75930019STodd Fiala { 703*75930019STodd Fiala if (value.front() == '-') 704*75930019STodd Fiala { 705*75930019STodd Fiala bool success = false; 706*75930019STodd Fiala int64_t sval = StringConvert::ToSInt64(value.c_str(), 0, 0, &success); 707*75930019STodd Fiala if (success) 708*75930019STodd Fiala return JSONValue::SP(new JSONNumber(sval)); 709*75930019STodd Fiala } 710*75930019STodd Fiala else 711*75930019STodd Fiala { 712*75930019STodd Fiala bool success = false; 713*75930019STodd Fiala uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success); 714*75930019STodd Fiala if (success) 715*75930019STodd Fiala return JSONValue::SP(new JSONNumber(uval)); 716*75930019STodd Fiala } 717*75930019STodd Fiala } 718*75930019STodd Fiala break; 719*75930019STodd Fiala 720*75930019STodd Fiala case JSONParser::Token::Float: 721*75930019STodd Fiala { 722*75930019STodd Fiala bool success = false; 723*75930019STodd Fiala double val = StringConvert::ToDouble(value.c_str(), 0.0, &success); 724*75930019STodd Fiala if (success) 725*75930019STodd Fiala return JSONValue::SP(new JSONNumber(val)); 726*75930019STodd Fiala } 727*75930019STodd Fiala break; 728*75930019STodd Fiala 729*75930019STodd Fiala case JSONParser::Token::String: 730*75930019STodd Fiala return JSONValue::SP(new JSONString(value)); 731*75930019STodd Fiala 732*75930019STodd Fiala case JSONParser::Token::True: 733*75930019STodd Fiala return JSONValue::SP(new JSONTrue()); 734*75930019STodd Fiala 735*75930019STodd Fiala case JSONParser::Token::False: 736*75930019STodd Fiala return JSONValue::SP(new JSONFalse()); 737*75930019STodd Fiala 738*75930019STodd Fiala case JSONParser::Token::Null: 739*75930019STodd Fiala return JSONValue::SP(new JSONNull()); 740*75930019STodd Fiala 741*75930019STodd Fiala default: 742*75930019STodd Fiala break; 743*75930019STodd Fiala } 744*75930019STodd Fiala return JSONValue::SP(); 745*75930019STodd Fiala 746*75930019STodd Fiala } 747