175930019STodd Fiala //===--------------------- JSON.cpp -----------------------------*- C++ -*-===//
275930019STodd Fiala //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
675930019STodd Fiala //
775930019STodd Fiala //===----------------------------------------------------------------------===//
875930019STodd Fiala 
975930019STodd Fiala #include "JSON.h"
1075930019STodd Fiala 
1175930019STodd Fiala // C includes
12*76e47d48SRaphael Isemann #include <cassert>
13*76e47d48SRaphael Isemann #include <climits>
1475930019STodd Fiala 
1575930019STodd Fiala // C++ includes
16b9c1b51eSKate Stone #include "lldb/Host/StringConvert.h"
1775930019STodd Fiala #include <iomanip>
1875930019STodd Fiala #include <sstream>
1975930019STodd Fiala 
2075930019STodd Fiala using namespace lldb_private;
2175930019STodd Fiala 
22b9c1b51eSKate Stone std::string JSONString::json_string_quote_metachars(const std::string &s) {
2375930019STodd Fiala   if (s.find('"') == std::string::npos)
2475930019STodd Fiala     return s;
2575930019STodd Fiala 
2675930019STodd Fiala   std::string output;
2775930019STodd Fiala   const size_t s_size = s.size();
2875930019STodd Fiala   const char *s_chars = s.c_str();
29b9c1b51eSKate Stone   for (size_t i = 0; i < s_size; i++) {
3075930019STodd Fiala     unsigned char ch = *(s_chars + i);
31b9c1b51eSKate Stone     if (ch == '"') {
3275930019STodd Fiala       output.push_back('\\');
3375930019STodd Fiala     }
3475930019STodd Fiala     output.push_back(ch);
3575930019STodd Fiala   }
3675930019STodd Fiala   return output;
3775930019STodd Fiala }
3875930019STodd Fiala 
39b9c1b51eSKate Stone JSONString::JSONString() : JSONValue(JSONValue::Kind::String), m_data() {}
4075930019STodd Fiala 
41b9c1b51eSKate Stone JSONString::JSONString(const char *s)
42b9c1b51eSKate Stone     : JSONValue(JSONValue::Kind::String), m_data(s ? s : "") {}
4375930019STodd Fiala 
44b9c1b51eSKate Stone JSONString::JSONString(const std::string &s)
45b9c1b51eSKate Stone     : JSONValue(JSONValue::Kind::String), m_data(s) {}
4675930019STodd Fiala 
47b9c1b51eSKate Stone void JSONString::Write(std::ostream &s) {
4875930019STodd Fiala   s << "\"" << json_string_quote_metachars(m_data).c_str() << "\"";
4975930019STodd Fiala }
5075930019STodd Fiala 
51b9c1b51eSKate Stone uint64_t JSONNumber::GetAsUnsigned() const {
52b9c1b51eSKate Stone   switch (m_data_type) {
5375930019STodd Fiala   case DataType::Unsigned:
5475930019STodd Fiala     return m_data.m_unsigned;
5575930019STodd Fiala   case DataType::Signed:
5675930019STodd Fiala     return (uint64_t)m_data.m_signed;
5775930019STodd Fiala   case DataType::Double:
5875930019STodd Fiala     return (uint64_t)m_data.m_double;
5975930019STodd Fiala   }
6075930019STodd Fiala }
6175930019STodd Fiala 
62b9c1b51eSKate Stone int64_t JSONNumber::GetAsSigned() const {
63b9c1b51eSKate Stone   switch (m_data_type) {
6475930019STodd Fiala   case DataType::Unsigned:
6575930019STodd Fiala     return (int64_t)m_data.m_unsigned;
6675930019STodd Fiala   case DataType::Signed:
6775930019STodd Fiala     return m_data.m_signed;
6875930019STodd Fiala   case DataType::Double:
6975930019STodd Fiala     return (int64_t)m_data.m_double;
7075930019STodd Fiala   }
7175930019STodd Fiala }
7275930019STodd Fiala 
73b9c1b51eSKate Stone double JSONNumber::GetAsDouble() const {
74b9c1b51eSKate Stone   switch (m_data_type) {
7575930019STodd Fiala   case DataType::Unsigned:
7675930019STodd Fiala     return (double)m_data.m_unsigned;
7775930019STodd Fiala   case DataType::Signed:
7875930019STodd Fiala     return (double)m_data.m_signed;
7975930019STodd Fiala   case DataType::Double:
8075930019STodd Fiala     return m_data.m_double;
8175930019STodd Fiala   }
8275930019STodd Fiala }
8375930019STodd Fiala 
84b9c1b51eSKate Stone void JSONNumber::Write(std::ostream &s) {
85b9c1b51eSKate Stone   switch (m_data_type) {
8675930019STodd Fiala   case DataType::Unsigned:
8775930019STodd Fiala     s << m_data.m_unsigned;
8875930019STodd Fiala     break;
8975930019STodd Fiala   case DataType::Signed:
9075930019STodd Fiala     s << m_data.m_signed;
9175930019STodd Fiala     break;
9275930019STodd Fiala   case DataType::Double:
9375930019STodd Fiala     // Set max precision to emulate %g.
9475930019STodd Fiala     s << std::setprecision(std::numeric_limits<double>::digits10 + 1);
9575930019STodd Fiala     s << m_data.m_double;
9675930019STodd Fiala     break;
9775930019STodd Fiala   }
9875930019STodd Fiala }
9975930019STodd Fiala 
100b9c1b51eSKate Stone JSONTrue::JSONTrue() : JSONValue(JSONValue::Kind::True) {}
10175930019STodd Fiala 
102b9c1b51eSKate Stone void JSONTrue::Write(std::ostream &s) { s << "true"; }
10375930019STodd Fiala 
104b9c1b51eSKate Stone JSONFalse::JSONFalse() : JSONValue(JSONValue::Kind::False) {}
10575930019STodd Fiala 
106b9c1b51eSKate Stone void JSONFalse::Write(std::ostream &s) { s << "false"; }
10775930019STodd Fiala 
108b9c1b51eSKate Stone JSONNull::JSONNull() : JSONValue(JSONValue::Kind::Null) {}
10975930019STodd Fiala 
110b9c1b51eSKate Stone void JSONNull::Write(std::ostream &s) { s << "null"; }
11175930019STodd Fiala 
112b9c1b51eSKate Stone JSONObject::JSONObject() : JSONValue(JSONValue::Kind::Object) {}
11375930019STodd Fiala 
114b9c1b51eSKate Stone void JSONObject::Write(std::ostream &s) {
11575930019STodd Fiala   bool first = true;
11675930019STodd Fiala   s << '{';
11775930019STodd Fiala   auto iter = m_elements.begin(), end = m_elements.end();
118b9c1b51eSKate Stone   for (; iter != end; iter++) {
11975930019STodd Fiala     if (first)
12075930019STodd Fiala       first = false;
12175930019STodd Fiala     else
12275930019STodd Fiala       s << ',';
12375930019STodd Fiala     JSONString key(iter->first);
12475930019STodd Fiala     JSONValue::SP value(iter->second);
12575930019STodd Fiala     key.Write(s);
12675930019STodd Fiala     s << ':';
12775930019STodd Fiala     value->Write(s);
12875930019STodd Fiala   }
12975930019STodd Fiala   s << '}';
13075930019STodd Fiala }
13175930019STodd Fiala 
132b9c1b51eSKate Stone bool JSONObject::SetObject(const std::string &key, JSONValue::SP value) {
13375930019STodd Fiala   if (key.empty() || nullptr == value.get())
13475930019STodd Fiala     return false;
13575930019STodd Fiala   m_elements[key] = value;
13675930019STodd Fiala   return true;
13775930019STodd Fiala }
13875930019STodd Fiala 
139b9c1b51eSKate Stone JSONValue::SP JSONObject::GetObject(const std::string &key) const {
14075930019STodd Fiala   auto iter = m_elements.find(key), end = m_elements.end();
14175930019STodd Fiala   if (iter == end)
14275930019STodd Fiala     return JSONValue::SP();
14375930019STodd Fiala   return iter->second;
14475930019STodd Fiala }
14575930019STodd Fiala 
146b9c1b51eSKate Stone bool JSONObject::GetObjectAsBool(const std::string &key, bool &value) const {
14775930019STodd Fiala   auto value_sp = GetObject(key);
148b9c1b51eSKate Stone   if (!value_sp) {
14975930019STodd Fiala     // The given key doesn't exist, so we have no value.
15075930019STodd Fiala     return false;
15175930019STodd Fiala   }
15275930019STodd Fiala 
153b9c1b51eSKate Stone   if (JSONTrue::classof(value_sp.get())) {
15475930019STodd Fiala     // We have the value, and it is true.
15575930019STodd Fiala     value = true;
15675930019STodd Fiala     return true;
157b9c1b51eSKate Stone   } else if (JSONFalse::classof(value_sp.get())) {
15875930019STodd Fiala     // We have the value, and it is false.
15975930019STodd Fiala     value = false;
16075930019STodd Fiala     return true;
161b9c1b51eSKate Stone   } else {
16275930019STodd Fiala     // We don't have a valid bool value for the given key.
16375930019STodd Fiala     return false;
16475930019STodd Fiala   }
16575930019STodd Fiala }
16675930019STodd Fiala 
167b9c1b51eSKate Stone bool JSONObject::GetObjectAsString(const std::string &key,
168b9c1b51eSKate Stone                                    std::string &value) const {
16975930019STodd Fiala   auto value_sp = GetObject(key);
170b9c1b51eSKate Stone   if (!value_sp) {
17175930019STodd Fiala     // The given key doesn't exist, so we have no value.
17275930019STodd Fiala     return false;
17375930019STodd Fiala   }
17475930019STodd Fiala 
17575930019STodd Fiala   if (!JSONString::classof(value_sp.get()))
17675930019STodd Fiala     return false;
17775930019STodd Fiala 
17875930019STodd Fiala   value = static_cast<JSONString *>(value_sp.get())->GetData();
17975930019STodd Fiala   return true;
18075930019STodd Fiala }
18175930019STodd Fiala 
182b9c1b51eSKate Stone JSONArray::JSONArray() : JSONValue(JSONValue::Kind::Array) {}
18375930019STodd Fiala 
184b9c1b51eSKate Stone void JSONArray::Write(std::ostream &s) {
18575930019STodd Fiala   bool first = true;
18675930019STodd Fiala   s << '[';
18775930019STodd Fiala   auto iter = m_elements.begin(), end = m_elements.end();
188b9c1b51eSKate Stone   for (; iter != end; iter++) {
18975930019STodd Fiala     if (first)
19075930019STodd Fiala       first = false;
19175930019STodd Fiala     else
19275930019STodd Fiala       s << ',';
19375930019STodd Fiala     (*iter)->Write(s);
19475930019STodd Fiala   }
19575930019STodd Fiala   s << ']';
19675930019STodd Fiala }
19775930019STodd Fiala 
198b9c1b51eSKate Stone bool JSONArray::SetObject(Index i, JSONValue::SP value) {
19975930019STodd Fiala   if (value.get() == nullptr)
20075930019STodd Fiala     return false;
201b9c1b51eSKate Stone   if (i < m_elements.size()) {
20275930019STodd Fiala     m_elements[i] = value;
20375930019STodd Fiala     return true;
20475930019STodd Fiala   }
205b9c1b51eSKate Stone   if (i == m_elements.size()) {
20675930019STodd Fiala     m_elements.push_back(value);
20775930019STodd Fiala     return true;
20875930019STodd Fiala   }
20975930019STodd Fiala   return false;
21075930019STodd Fiala }
21175930019STodd Fiala 
212b9c1b51eSKate Stone bool JSONArray::AppendObject(JSONValue::SP value) {
21375930019STodd Fiala   if (value.get() == nullptr)
21475930019STodd Fiala     return false;
21575930019STodd Fiala   m_elements.push_back(value);
21675930019STodd Fiala   return true;
21775930019STodd Fiala }
21875930019STodd Fiala 
219b9c1b51eSKate Stone JSONValue::SP JSONArray::GetObject(Index i) {
22075930019STodd Fiala   if (i < m_elements.size())
22175930019STodd Fiala     return m_elements[i];
22275930019STodd Fiala   return JSONValue::SP();
22375930019STodd Fiala }
22475930019STodd Fiala 
225b9c1b51eSKate Stone JSONArray::Size JSONArray::GetNumElements() { return m_elements.size(); }
22675930019STodd Fiala 
227b9c1b51eSKate Stone JSONParser::JSONParser(const char *cstr) : StdStringExtractor(cstr) {}
22875930019STodd Fiala 
229b9c1b51eSKate Stone JSONParser::Token JSONParser::GetToken(std::string &value) {
23075930019STodd Fiala   std::ostringstream error;
23175930019STodd Fiala 
23275930019STodd Fiala   value.clear();
23375930019STodd Fiala   SkipSpaces();
23475930019STodd Fiala   const uint64_t start_index = m_index;
23575930019STodd Fiala   const char ch = GetChar();
236b9c1b51eSKate Stone   switch (ch) {
237b9c1b51eSKate Stone   case '{':
238b9c1b51eSKate Stone     return Token::ObjectStart;
239b9c1b51eSKate Stone   case '}':
240b9c1b51eSKate Stone     return Token::ObjectEnd;
241b9c1b51eSKate Stone   case '[':
242b9c1b51eSKate Stone     return Token::ArrayStart;
243b9c1b51eSKate Stone   case ']':
244b9c1b51eSKate Stone     return Token::ArrayEnd;
245b9c1b51eSKate Stone   case ',':
246b9c1b51eSKate Stone     return Token::Comma;
247b9c1b51eSKate Stone   case ':':
248b9c1b51eSKate Stone     return Token::Colon;
249b9c1b51eSKate Stone   case '\0':
250b9c1b51eSKate Stone     return Token::EndOfFile;
25175930019STodd Fiala   case 't':
25275930019STodd Fiala     if (GetChar() == 'r')
25375930019STodd Fiala       if (GetChar() == 'u')
25475930019STodd Fiala         if (GetChar() == 'e')
25575930019STodd Fiala           return Token::True;
25675930019STodd Fiala     break;
25775930019STodd Fiala 
25875930019STodd Fiala   case 'f':
25975930019STodd Fiala     if (GetChar() == 'a')
26075930019STodd Fiala       if (GetChar() == 'l')
26175930019STodd Fiala         if (GetChar() == 's')
26275930019STodd Fiala           if (GetChar() == 'e')
26375930019STodd Fiala             return Token::False;
26475930019STodd Fiala     break;
26575930019STodd Fiala 
26675930019STodd Fiala   case 'n':
26775930019STodd Fiala     if (GetChar() == 'u')
26875930019STodd Fiala       if (GetChar() == 'l')
26975930019STodd Fiala         if (GetChar() == 'l')
27075930019STodd Fiala           return Token::Null;
27175930019STodd Fiala     break;
27275930019STodd Fiala 
273b9c1b51eSKate Stone   case '"': {
27409ad8c8fSJonas Devlieghere     while (true) {
27575930019STodd Fiala       bool was_escaped = false;
27675930019STodd Fiala       int escaped_ch = GetEscapedChar(was_escaped);
277b9c1b51eSKate Stone       if (escaped_ch == -1) {
278b9c1b51eSKate Stone         error << "error: an error occurred getting a character from offset "
279b9c1b51eSKate Stone               << start_index;
280c1566308SPavel Labath         value = error.str();
28197206d57SZachary Turner         return Token::Status;
28275930019STodd Fiala 
283b9c1b51eSKate Stone       } else {
28475930019STodd Fiala         const bool is_end_quote = escaped_ch == '"';
28575930019STodd Fiala         const bool is_null = escaped_ch == 0;
286b9c1b51eSKate Stone         if (was_escaped || (!is_end_quote && !is_null)) {
287b9c1b51eSKate Stone           if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX) {
28875930019STodd Fiala             value.append(1, (char)escaped_ch);
289b9c1b51eSKate Stone           } else {
290b9c1b51eSKate Stone             error << "error: wide character support is needed for unicode "
291b9c1b51eSKate Stone                      "character 0x"
292b9c1b51eSKate Stone                   << std::setprecision(4) << std::hex << escaped_ch;
29375930019STodd Fiala             error << " at offset " << start_index;
294c1566308SPavel Labath             value = error.str();
29597206d57SZachary Turner             return Token::Status;
29675930019STodd Fiala           }
297b9c1b51eSKate Stone         } else if (is_end_quote) {
29875930019STodd Fiala           return Token::String;
299b9c1b51eSKate Stone         } else if (is_null) {
30075930019STodd Fiala           value = "error: missing end quote for string";
30197206d57SZachary Turner           return Token::Status;
30275930019STodd Fiala         }
30375930019STodd Fiala       }
30475930019STodd Fiala     }
305b9c1b51eSKate Stone   } break;
30675930019STodd Fiala 
30775930019STodd Fiala   case '-':
30875930019STodd Fiala   case '0':
30975930019STodd Fiala   case '1':
31075930019STodd Fiala   case '2':
31175930019STodd Fiala   case '3':
31275930019STodd Fiala   case '4':
31375930019STodd Fiala   case '5':
31475930019STodd Fiala   case '6':
31575930019STodd Fiala   case '7':
31675930019STodd Fiala   case '8':
317b9c1b51eSKate Stone   case '9': {
31875930019STodd Fiala     bool done = false;
31975930019STodd Fiala     bool got_decimal_point = false;
32075930019STodd Fiala     uint64_t exp_index = 0;
32175930019STodd Fiala     bool got_int_digits = (ch >= '0') && (ch <= '9');
32275930019STodd Fiala     bool got_frac_digits = false;
32375930019STodd Fiala     bool got_exp_digits = false;
324b9c1b51eSKate Stone     while (!done) {
32575930019STodd Fiala       const char next_ch = PeekChar();
326b9c1b51eSKate Stone       switch (next_ch) {
32775930019STodd Fiala       case '0':
32875930019STodd Fiala       case '1':
32975930019STodd Fiala       case '2':
33075930019STodd Fiala       case '3':
33175930019STodd Fiala       case '4':
33275930019STodd Fiala       case '5':
33375930019STodd Fiala       case '6':
33475930019STodd Fiala       case '7':
33575930019STodd Fiala       case '8':
33675930019STodd Fiala       case '9':
337b9c1b51eSKate Stone         if (exp_index != 0) {
33875930019STodd Fiala           got_exp_digits = true;
339b9c1b51eSKate Stone         } else if (got_decimal_point) {
34075930019STodd Fiala           got_frac_digits = true;
341b9c1b51eSKate Stone         } else {
34275930019STodd Fiala           got_int_digits = true;
34375930019STodd Fiala         }
34475930019STodd Fiala         ++m_index; // Skip this character
34575930019STodd Fiala         break;
34675930019STodd Fiala 
34775930019STodd Fiala       case '.':
348b9c1b51eSKate Stone         if (got_decimal_point) {
34975930019STodd Fiala           error << "error: extra decimal point found at offset " << start_index;
350c1566308SPavel Labath           value = error.str();
35197206d57SZachary Turner           return Token::Status;
352b9c1b51eSKate Stone         } else {
35375930019STodd Fiala           got_decimal_point = true;
35475930019STodd Fiala           ++m_index; // Skip this character
35575930019STodd Fiala         }
35675930019STodd Fiala         break;
35775930019STodd Fiala 
35875930019STodd Fiala       case 'e':
35975930019STodd Fiala       case 'E':
360b9c1b51eSKate Stone         if (exp_index != 0) {
361b9c1b51eSKate Stone           error << "error: extra exponent character found at offset "
362b9c1b51eSKate Stone                 << start_index;
363c1566308SPavel Labath           value = error.str();
36497206d57SZachary Turner           return Token::Status;
365b9c1b51eSKate Stone         } else {
36675930019STodd Fiala           exp_index = m_index;
36775930019STodd Fiala           ++m_index; // Skip this character
36875930019STodd Fiala         }
36975930019STodd Fiala         break;
37075930019STodd Fiala 
37175930019STodd Fiala       case '+':
37275930019STodd Fiala       case '-':
37375930019STodd Fiala         // The '+' and '-' can only come after an exponent character...
374b9c1b51eSKate Stone         if (exp_index == m_index - 1) {
37575930019STodd Fiala           ++m_index; // Skip the exponent sign character
376b9c1b51eSKate Stone         } else {
377b9c1b51eSKate Stone           error << "error: unexpected " << next_ch << " character at offset "
378b9c1b51eSKate Stone                 << start_index;
379c1566308SPavel Labath           value = error.str();
38097206d57SZachary Turner           return Token::Status;
38175930019STodd Fiala         }
38275930019STodd Fiala         break;
38375930019STodd Fiala 
38475930019STodd Fiala       default:
38575930019STodd Fiala         done = true;
38675930019STodd Fiala         break;
38775930019STodd Fiala       }
38875930019STodd Fiala     }
38975930019STodd Fiala 
390b9c1b51eSKate Stone     if (m_index > start_index) {
39175930019STodd Fiala       value = m_packet.substr(start_index, m_index - start_index);
392b9c1b51eSKate Stone       if (got_decimal_point) {
393b9c1b51eSKate Stone         if (exp_index != 0) {
39475930019STodd Fiala           // We have an exponent, make sure we got exponent digits
395b9c1b51eSKate Stone           if (got_exp_digits) {
39675930019STodd Fiala             return Token::Float;
397b9c1b51eSKate Stone           } else {
398b9c1b51eSKate Stone             error << "error: got exponent character but no exponent digits at "
399b9c1b51eSKate Stone                      "offset in float value \""
400b9c1b51eSKate Stone                   << value.c_str() << "\"";
401b9c1b51eSKate Stone             value = error.str();
40297206d57SZachary Turner             return Token::Status;
40375930019STodd Fiala           }
404b9c1b51eSKate Stone         } else {
405b9c1b51eSKate Stone           // No exponent, but we need at least one decimal after the decimal
406b9c1b51eSKate Stone           // point
407b9c1b51eSKate Stone           if (got_frac_digits) {
408b9c1b51eSKate Stone             return Token::Float;
409b9c1b51eSKate Stone           } else {
410b9c1b51eSKate Stone             error << "error: no digits after decimal point \"" << value.c_str()
411b9c1b51eSKate Stone                   << "\"";
412c1566308SPavel Labath             value = error.str();
41397206d57SZachary Turner             return Token::Status;
41475930019STodd Fiala           }
41575930019STodd Fiala         }
416b9c1b51eSKate Stone       } else {
41775930019STodd Fiala         // No decimal point
418b9c1b51eSKate Stone         if (got_int_digits) {
41975930019STodd Fiala           // We need at least some integer digits to make an integer
42075930019STodd Fiala           return Token::Integer;
421b9c1b51eSKate Stone         } else {
42275930019STodd Fiala           error << "error: no digits negate sign \"" << value.c_str() << "\"";
423c1566308SPavel Labath           value = error.str();
42497206d57SZachary Turner           return Token::Status;
42575930019STodd Fiala         }
42675930019STodd Fiala       }
427b9c1b51eSKate Stone     } else {
42875930019STodd Fiala       error << "error: invalid number found at offset " << start_index;
429c1566308SPavel Labath       value = error.str();
43097206d57SZachary Turner       return Token::Status;
43175930019STodd Fiala     }
432b9c1b51eSKate Stone   } break;
43375930019STodd Fiala   default:
43475930019STodd Fiala     break;
43575930019STodd Fiala   }
436b9c1b51eSKate Stone   error << "error: failed to parse token at offset " << start_index
437b9c1b51eSKate Stone         << " (around character '" << ch << "')";
438c1566308SPavel Labath   value = error.str();
43997206d57SZachary Turner   return Token::Status;
44075930019STodd Fiala }
44175930019STodd Fiala 
442b9c1b51eSKate Stone int JSONParser::GetEscapedChar(bool &was_escaped) {
44375930019STodd Fiala   was_escaped = false;
44475930019STodd Fiala   const char ch = GetChar();
445b9c1b51eSKate Stone   if (ch == '\\') {
44675930019STodd Fiala     was_escaped = true;
44775930019STodd Fiala     const char ch2 = GetChar();
448b9c1b51eSKate Stone     switch (ch2) {
44975930019STodd Fiala     case '"':
45075930019STodd Fiala     case '\\':
45175930019STodd Fiala     case '/':
45275930019STodd Fiala     default:
45375930019STodd Fiala       break;
45475930019STodd Fiala 
455b9c1b51eSKate Stone     case 'b':
456b9c1b51eSKate Stone       return '\b';
457b9c1b51eSKate Stone     case 'f':
458b9c1b51eSKate Stone       return '\f';
459b9c1b51eSKate Stone     case 'n':
460b9c1b51eSKate Stone       return '\n';
461b9c1b51eSKate Stone     case 'r':
462b9c1b51eSKate Stone       return '\r';
463b9c1b51eSKate Stone     case 't':
464b9c1b51eSKate Stone       return '\t';
465b9c1b51eSKate Stone     case 'u': {
46675930019STodd Fiala       const int hi_byte = DecodeHexU8();
46775930019STodd Fiala       const int lo_byte = DecodeHexU8();
46875930019STodd Fiala       if (hi_byte >= 0 && lo_byte >= 0)
46975930019STodd Fiala         return hi_byte << 8 | lo_byte;
47075930019STodd Fiala       return -1;
471b9c1b51eSKate Stone     } break;
47275930019STodd Fiala     }
47375930019STodd Fiala     return ch2;
47475930019STodd Fiala   }
47575930019STodd Fiala   return ch;
47675930019STodd Fiala }
47775930019STodd Fiala 
478b9c1b51eSKate Stone JSONValue::SP JSONParser::ParseJSONObject() {
479b9c1b51eSKate Stone   // The "JSONParser::Token::ObjectStart" token should have already been
480b9c1b51eSKate Stone   // consumed
48175930019STodd Fiala   // by the time this function is called
48275930019STodd Fiala   std::unique_ptr<JSONObject> dict_up(new JSONObject());
48375930019STodd Fiala 
48475930019STodd Fiala   std::string value;
48575930019STodd Fiala   std::string key;
48609ad8c8fSJonas Devlieghere   while (true) {
48775930019STodd Fiala     JSONParser::Token token = GetToken(value);
48875930019STodd Fiala 
489b9c1b51eSKate Stone     if (token == JSONParser::Token::String) {
49075930019STodd Fiala       key.swap(value);
49175930019STodd Fiala       token = GetToken(value);
492b9c1b51eSKate Stone       if (token == JSONParser::Token::Colon) {
49375930019STodd Fiala         JSONValue::SP value_sp = ParseJSONValue();
49475930019STodd Fiala         if (value_sp)
49575930019STodd Fiala           dict_up->SetObject(key, value_sp);
49675930019STodd Fiala         else
49775930019STodd Fiala           break;
49875930019STodd Fiala       }
499b9c1b51eSKate Stone     } else if (token == JSONParser::Token::ObjectEnd) {
50075930019STodd Fiala       return JSONValue::SP(dict_up.release());
501b9c1b51eSKate Stone     } else if (token == JSONParser::Token::Comma) {
50275930019STodd Fiala       continue;
503b9c1b51eSKate Stone     } else {
50475930019STodd Fiala       break;
50575930019STodd Fiala     }
50675930019STodd Fiala   }
50775930019STodd Fiala   return JSONValue::SP();
50875930019STodd Fiala }
50975930019STodd Fiala 
510b9c1b51eSKate Stone JSONValue::SP JSONParser::ParseJSONArray() {
511b9c1b51eSKate Stone   // The "JSONParser::Token::ObjectStart" token should have already been
512b9c1b51eSKate Stone   // consumed
51375930019STodd Fiala   // by the time this function is called
51475930019STodd Fiala   std::unique_ptr<JSONArray> array_up(new JSONArray());
51575930019STodd Fiala 
51675930019STodd Fiala   std::string value;
51775930019STodd Fiala   std::string key;
51809ad8c8fSJonas Devlieghere   while (true) {
51910b85143SAlex Cameron     JSONParser::Token token = GetToken(value);
52010b85143SAlex Cameron     if (token == JSONParser::Token::ArrayEnd)
52110b85143SAlex Cameron       return JSONValue::SP(array_up.release());
52210b85143SAlex Cameron     JSONValue::SP value_sp = ParseJSONValue(value, token);
52375930019STodd Fiala     if (value_sp)
52475930019STodd Fiala       array_up->AppendObject(value_sp);
52575930019STodd Fiala     else
52675930019STodd Fiala       break;
52775930019STodd Fiala 
52810b85143SAlex Cameron     token = GetToken(value);
529b9c1b51eSKate Stone     if (token == JSONParser::Token::Comma) {
53075930019STodd Fiala       continue;
531b9c1b51eSKate Stone     } else if (token == JSONParser::Token::ArrayEnd) {
53275930019STodd Fiala       return JSONValue::SP(array_up.release());
533b9c1b51eSKate Stone     } else {
53475930019STodd Fiala       break;
53575930019STodd Fiala     }
53675930019STodd Fiala   }
53775930019STodd Fiala   return JSONValue::SP();
53875930019STodd Fiala }
53975930019STodd Fiala 
540b9c1b51eSKate Stone JSONValue::SP JSONParser::ParseJSONValue() {
54175930019STodd Fiala   std::string value;
54275930019STodd Fiala   const JSONParser::Token token = GetToken(value);
54310b85143SAlex Cameron   return ParseJSONValue(value, token);
54410b85143SAlex Cameron }
54510b85143SAlex Cameron 
54610b85143SAlex Cameron JSONValue::SP JSONParser::ParseJSONValue(const std::string &value,
54710b85143SAlex Cameron                                          const Token &token) {
548b9c1b51eSKate Stone   switch (token) {
54975930019STodd Fiala   case JSONParser::Token::ObjectStart:
55075930019STodd Fiala     return ParseJSONObject();
55175930019STodd Fiala 
55275930019STodd Fiala   case JSONParser::Token::ArrayStart:
55375930019STodd Fiala     return ParseJSONArray();
55475930019STodd Fiala 
555b9c1b51eSKate Stone   case JSONParser::Token::Integer: {
556b9c1b51eSKate Stone     if (value.front() == '-') {
55775930019STodd Fiala       bool success = false;
55875930019STodd Fiala       int64_t sval = StringConvert::ToSInt64(value.c_str(), 0, 0, &success);
55975930019STodd Fiala       if (success)
56075930019STodd Fiala         return JSONValue::SP(new JSONNumber(sval));
561b9c1b51eSKate Stone     } else {
56275930019STodd Fiala       bool success = false;
56375930019STodd Fiala       uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success);
56475930019STodd Fiala       if (success)
56575930019STodd Fiala         return JSONValue::SP(new JSONNumber(uval));
56675930019STodd Fiala     }
567b9c1b51eSKate Stone   } break;
56875930019STodd Fiala 
569b9c1b51eSKate Stone   case JSONParser::Token::Float: {
57075930019STodd Fiala     bool success = false;
57175930019STodd Fiala     double val = StringConvert::ToDouble(value.c_str(), 0.0, &success);
57275930019STodd Fiala     if (success)
57375930019STodd Fiala       return JSONValue::SP(new JSONNumber(val));
574b9c1b51eSKate Stone   } break;
57575930019STodd Fiala 
57675930019STodd Fiala   case JSONParser::Token::String:
57775930019STodd Fiala     return JSONValue::SP(new JSONString(value));
57875930019STodd Fiala 
57975930019STodd Fiala   case JSONParser::Token::True:
58075930019STodd Fiala     return JSONValue::SP(new JSONTrue());
58175930019STodd Fiala 
58275930019STodd Fiala   case JSONParser::Token::False:
58375930019STodd Fiala     return JSONValue::SP(new JSONFalse());
58475930019STodd Fiala 
58575930019STodd Fiala   case JSONParser::Token::Null:
58675930019STodd Fiala     return JSONValue::SP(new JSONNull());
58775930019STodd Fiala 
58875930019STodd Fiala   default:
58975930019STodd Fiala     break;
59075930019STodd Fiala   }
59175930019STodd Fiala   return JSONValue::SP();
59275930019STodd Fiala }
593