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