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