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
1276e47d48SRaphael Isemann #include <cassert>
1376e47d48SRaphael Isemann #include <climits>
1475930019STodd Fiala
1575930019STodd Fiala // C++ includes
16*9da2fa27SMichał Górny #include "StringConvert.h"
1775930019STodd Fiala #include <iomanip>
1875930019STodd Fiala #include <sstream>
1975930019STodd Fiala
json_string_quote_metachars(const std::string & s)20b9c1b51eSKate Stone std::string JSONString::json_string_quote_metachars(const std::string &s) {
2175930019STodd Fiala if (s.find('"') == std::string::npos)
2275930019STodd Fiala return s;
2375930019STodd Fiala
2475930019STodd Fiala std::string output;
2575930019STodd Fiala const size_t s_size = s.size();
2675930019STodd Fiala const char *s_chars = s.c_str();
27b9c1b51eSKate Stone for (size_t i = 0; i < s_size; i++) {
2875930019STodd Fiala unsigned char ch = *(s_chars + i);
29b9c1b51eSKate Stone if (ch == '"') {
3075930019STodd Fiala output.push_back('\\');
3175930019STodd Fiala }
3275930019STodd Fiala output.push_back(ch);
3375930019STodd Fiala }
3475930019STodd Fiala return output;
3575930019STodd Fiala }
3675930019STodd Fiala
JSONString()37b9c1b51eSKate Stone JSONString::JSONString() : JSONValue(JSONValue::Kind::String), m_data() {}
3875930019STodd Fiala
JSONString(const char * s)39b9c1b51eSKate Stone JSONString::JSONString(const char *s)
40b9c1b51eSKate Stone : JSONValue(JSONValue::Kind::String), m_data(s ? s : "") {}
4175930019STodd Fiala
JSONString(const std::string & s)42b9c1b51eSKate Stone JSONString::JSONString(const std::string &s)
43b9c1b51eSKate Stone : JSONValue(JSONValue::Kind::String), m_data(s) {}
4475930019STodd Fiala
Write(std::ostream & s)45b9c1b51eSKate Stone void JSONString::Write(std::ostream &s) {
4675930019STodd Fiala s << "\"" << json_string_quote_metachars(m_data).c_str() << "\"";
4775930019STodd Fiala }
4875930019STodd Fiala
GetAsUnsigned() const49b9c1b51eSKate Stone uint64_t JSONNumber::GetAsUnsigned() const {
50b9c1b51eSKate Stone switch (m_data_type) {
5175930019STodd Fiala case DataType::Unsigned:
5275930019STodd Fiala return m_data.m_unsigned;
5375930019STodd Fiala case DataType::Signed:
5475930019STodd Fiala return (uint64_t)m_data.m_signed;
5575930019STodd Fiala case DataType::Double:
5675930019STodd Fiala return (uint64_t)m_data.m_double;
5775930019STodd Fiala }
5875930019STodd Fiala }
5975930019STodd Fiala
GetAsSigned() const60b9c1b51eSKate Stone int64_t JSONNumber::GetAsSigned() const {
61b9c1b51eSKate Stone switch (m_data_type) {
6275930019STodd Fiala case DataType::Unsigned:
6375930019STodd Fiala return (int64_t)m_data.m_unsigned;
6475930019STodd Fiala case DataType::Signed:
6575930019STodd Fiala return m_data.m_signed;
6675930019STodd Fiala case DataType::Double:
6775930019STodd Fiala return (int64_t)m_data.m_double;
6875930019STodd Fiala }
6975930019STodd Fiala }
7075930019STodd Fiala
GetAsDouble() const71b9c1b51eSKate Stone double JSONNumber::GetAsDouble() const {
72b9c1b51eSKate Stone switch (m_data_type) {
7375930019STodd Fiala case DataType::Unsigned:
7475930019STodd Fiala return (double)m_data.m_unsigned;
7575930019STodd Fiala case DataType::Signed:
7675930019STodd Fiala return (double)m_data.m_signed;
7775930019STodd Fiala case DataType::Double:
7875930019STodd Fiala return m_data.m_double;
7975930019STodd Fiala }
8075930019STodd Fiala }
8175930019STodd Fiala
Write(std::ostream & s)82b9c1b51eSKate Stone void JSONNumber::Write(std::ostream &s) {
83b9c1b51eSKate Stone switch (m_data_type) {
8475930019STodd Fiala case DataType::Unsigned:
8575930019STodd Fiala s << m_data.m_unsigned;
8675930019STodd Fiala break;
8775930019STodd Fiala case DataType::Signed:
8875930019STodd Fiala s << m_data.m_signed;
8975930019STodd Fiala break;
9075930019STodd Fiala case DataType::Double:
9175930019STodd Fiala // Set max precision to emulate %g.
9275930019STodd Fiala s << std::setprecision(std::numeric_limits<double>::digits10 + 1);
9375930019STodd Fiala s << m_data.m_double;
9475930019STodd Fiala break;
9575930019STodd Fiala }
9675930019STodd Fiala }
9775930019STodd Fiala
JSONTrue()98b9c1b51eSKate Stone JSONTrue::JSONTrue() : JSONValue(JSONValue::Kind::True) {}
9975930019STodd Fiala
Write(std::ostream & s)100b9c1b51eSKate Stone void JSONTrue::Write(std::ostream &s) { s << "true"; }
10175930019STodd Fiala
JSONFalse()102b9c1b51eSKate Stone JSONFalse::JSONFalse() : JSONValue(JSONValue::Kind::False) {}
10375930019STodd Fiala
Write(std::ostream & s)104b9c1b51eSKate Stone void JSONFalse::Write(std::ostream &s) { s << "false"; }
10575930019STodd Fiala
JSONNull()106b9c1b51eSKate Stone JSONNull::JSONNull() : JSONValue(JSONValue::Kind::Null) {}
10775930019STodd Fiala
Write(std::ostream & s)108b9c1b51eSKate Stone void JSONNull::Write(std::ostream &s) { s << "null"; }
10975930019STodd Fiala
JSONObject()110b9c1b51eSKate Stone JSONObject::JSONObject() : JSONValue(JSONValue::Kind::Object) {}
11175930019STodd Fiala
Write(std::ostream & s)112b9c1b51eSKate Stone void JSONObject::Write(std::ostream &s) {
11375930019STodd Fiala bool first = true;
11475930019STodd Fiala s << '{';
11575930019STodd Fiala auto iter = m_elements.begin(), end = m_elements.end();
116b9c1b51eSKate Stone for (; iter != end; iter++) {
11775930019STodd Fiala if (first)
11875930019STodd Fiala first = false;
11975930019STodd Fiala else
12075930019STodd Fiala s << ',';
12175930019STodd Fiala JSONString key(iter->first);
12275930019STodd Fiala JSONValue::SP value(iter->second);
12375930019STodd Fiala key.Write(s);
12475930019STodd Fiala s << ':';
12575930019STodd Fiala value->Write(s);
12675930019STodd Fiala }
12775930019STodd Fiala s << '}';
12875930019STodd Fiala }
12975930019STodd Fiala
SetObject(const std::string & key,JSONValue::SP value)130b9c1b51eSKate Stone bool JSONObject::SetObject(const std::string &key, JSONValue::SP value) {
13175930019STodd Fiala if (key.empty() || nullptr == value.get())
13275930019STodd Fiala return false;
13375930019STodd Fiala m_elements[key] = value;
13475930019STodd Fiala return true;
13575930019STodd Fiala }
13675930019STodd Fiala
GetObject(const std::string & key) const137b9c1b51eSKate Stone JSONValue::SP JSONObject::GetObject(const std::string &key) const {
13875930019STodd Fiala auto iter = m_elements.find(key), end = m_elements.end();
13975930019STodd Fiala if (iter == end)
14075930019STodd Fiala return JSONValue::SP();
14175930019STodd Fiala return iter->second;
14275930019STodd Fiala }
14375930019STodd Fiala
GetObjectAsBool(const std::string & key,bool & value) const144b9c1b51eSKate Stone bool JSONObject::GetObjectAsBool(const std::string &key, bool &value) const {
14575930019STodd Fiala auto value_sp = GetObject(key);
146b9c1b51eSKate Stone if (!value_sp) {
14775930019STodd Fiala // The given key doesn't exist, so we have no value.
14875930019STodd Fiala return false;
14975930019STodd Fiala }
15075930019STodd Fiala
151b9c1b51eSKate Stone if (JSONTrue::classof(value_sp.get())) {
15275930019STodd Fiala // We have the value, and it is true.
15375930019STodd Fiala value = true;
15475930019STodd Fiala return true;
155b9c1b51eSKate Stone } else if (JSONFalse::classof(value_sp.get())) {
15675930019STodd Fiala // We have the value, and it is false.
15775930019STodd Fiala value = false;
15875930019STodd Fiala return true;
159b9c1b51eSKate Stone } else {
16075930019STodd Fiala // We don't have a valid bool value for the given key.
16175930019STodd Fiala return false;
16275930019STodd Fiala }
16375930019STodd Fiala }
16475930019STodd Fiala
GetObjectAsString(const std::string & key,std::string & value) const165b9c1b51eSKate Stone bool JSONObject::GetObjectAsString(const std::string &key,
166b9c1b51eSKate Stone std::string &value) const {
16775930019STodd Fiala auto value_sp = GetObject(key);
168b9c1b51eSKate Stone if (!value_sp) {
16975930019STodd Fiala // The given key doesn't exist, so we have no value.
17075930019STodd Fiala return false;
17175930019STodd Fiala }
17275930019STodd Fiala
17375930019STodd Fiala if (!JSONString::classof(value_sp.get()))
17475930019STodd Fiala return false;
17575930019STodd Fiala
17675930019STodd Fiala value = static_cast<JSONString *>(value_sp.get())->GetData();
17775930019STodd Fiala return true;
17875930019STodd Fiala }
17975930019STodd Fiala
JSONArray()180b9c1b51eSKate Stone JSONArray::JSONArray() : JSONValue(JSONValue::Kind::Array) {}
18175930019STodd Fiala
Write(std::ostream & s)182b9c1b51eSKate Stone void JSONArray::Write(std::ostream &s) {
18375930019STodd Fiala bool first = true;
18475930019STodd Fiala s << '[';
18575930019STodd Fiala auto iter = m_elements.begin(), end = m_elements.end();
186b9c1b51eSKate Stone for (; iter != end; iter++) {
18775930019STodd Fiala if (first)
18875930019STodd Fiala first = false;
18975930019STodd Fiala else
19075930019STodd Fiala s << ',';
19175930019STodd Fiala (*iter)->Write(s);
19275930019STodd Fiala }
19375930019STodd Fiala s << ']';
19475930019STodd Fiala }
19575930019STodd Fiala
SetObject(Index i,JSONValue::SP value)196b9c1b51eSKate Stone bool JSONArray::SetObject(Index i, JSONValue::SP value) {
19775930019STodd Fiala if (value.get() == nullptr)
19875930019STodd Fiala return false;
199b9c1b51eSKate Stone if (i < m_elements.size()) {
20075930019STodd Fiala m_elements[i] = value;
20175930019STodd Fiala return true;
20275930019STodd Fiala }
203b9c1b51eSKate Stone if (i == m_elements.size()) {
20475930019STodd Fiala m_elements.push_back(value);
20575930019STodd Fiala return true;
20675930019STodd Fiala }
20775930019STodd Fiala return false;
20875930019STodd Fiala }
20975930019STodd Fiala
AppendObject(JSONValue::SP value)210b9c1b51eSKate Stone bool JSONArray::AppendObject(JSONValue::SP value) {
21175930019STodd Fiala if (value.get() == nullptr)
21275930019STodd Fiala return false;
21375930019STodd Fiala m_elements.push_back(value);
21475930019STodd Fiala return true;
21575930019STodd Fiala }
21675930019STodd Fiala
GetObject(Index i)217b9c1b51eSKate Stone JSONValue::SP JSONArray::GetObject(Index i) {
21875930019STodd Fiala if (i < m_elements.size())
21975930019STodd Fiala return m_elements[i];
22075930019STodd Fiala return JSONValue::SP();
22175930019STodd Fiala }
22275930019STodd Fiala
GetNumElements()223b9c1b51eSKate Stone JSONArray::Size JSONArray::GetNumElements() { return m_elements.size(); }
22475930019STodd Fiala
JSONParser(const char * cstr)225b9c1b51eSKate Stone JSONParser::JSONParser(const char *cstr) : StdStringExtractor(cstr) {}
22675930019STodd Fiala
GetToken(std::string & value)227b9c1b51eSKate Stone JSONParser::Token JSONParser::GetToken(std::string &value) {
22875930019STodd Fiala std::ostringstream error;
22975930019STodd Fiala
23075930019STodd Fiala value.clear();
23175930019STodd Fiala SkipSpaces();
23275930019STodd Fiala const uint64_t start_index = m_index;
23375930019STodd Fiala const char ch = GetChar();
234b9c1b51eSKate Stone switch (ch) {
235b9c1b51eSKate Stone case '{':
236b9c1b51eSKate Stone return Token::ObjectStart;
237b9c1b51eSKate Stone case '}':
238b9c1b51eSKate Stone return Token::ObjectEnd;
239b9c1b51eSKate Stone case '[':
240b9c1b51eSKate Stone return Token::ArrayStart;
241b9c1b51eSKate Stone case ']':
242b9c1b51eSKate Stone return Token::ArrayEnd;
243b9c1b51eSKate Stone case ',':
244b9c1b51eSKate Stone return Token::Comma;
245b9c1b51eSKate Stone case ':':
246b9c1b51eSKate Stone return Token::Colon;
247b9c1b51eSKate Stone case '\0':
248b9c1b51eSKate Stone return Token::EndOfFile;
24975930019STodd Fiala case 't':
25075930019STodd Fiala if (GetChar() == 'r')
25175930019STodd Fiala if (GetChar() == 'u')
25275930019STodd Fiala if (GetChar() == 'e')
25375930019STodd Fiala return Token::True;
25475930019STodd Fiala break;
25575930019STodd Fiala
25675930019STodd Fiala case 'f':
25775930019STodd Fiala if (GetChar() == 'a')
25875930019STodd Fiala if (GetChar() == 'l')
25975930019STodd Fiala if (GetChar() == 's')
26075930019STodd Fiala if (GetChar() == 'e')
26175930019STodd Fiala return Token::False;
26275930019STodd Fiala break;
26375930019STodd Fiala
26475930019STodd Fiala case 'n':
26575930019STodd Fiala if (GetChar() == 'u')
26675930019STodd Fiala if (GetChar() == 'l')
26775930019STodd Fiala if (GetChar() == 'l')
26875930019STodd Fiala return Token::Null;
26975930019STodd Fiala break;
27075930019STodd Fiala
271b9c1b51eSKate Stone case '"': {
27209ad8c8fSJonas Devlieghere while (true) {
27375930019STodd Fiala bool was_escaped = false;
27475930019STodd Fiala int escaped_ch = GetEscapedChar(was_escaped);
275b9c1b51eSKate Stone if (escaped_ch == -1) {
276b9c1b51eSKate Stone error << "error: an error occurred getting a character from offset "
277b9c1b51eSKate Stone << start_index;
278c1566308SPavel Labath value = error.str();
27997206d57SZachary Turner return Token::Status;
28075930019STodd Fiala
281b9c1b51eSKate Stone } else {
28275930019STodd Fiala const bool is_end_quote = escaped_ch == '"';
28375930019STodd Fiala const bool is_null = escaped_ch == 0;
284b9c1b51eSKate Stone if (was_escaped || (!is_end_quote && !is_null)) {
285b9c1b51eSKate Stone if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX) {
28675930019STodd Fiala value.append(1, (char)escaped_ch);
287b9c1b51eSKate Stone } else {
288b9c1b51eSKate Stone error << "error: wide character support is needed for unicode "
289b9c1b51eSKate Stone "character 0x"
290b9c1b51eSKate Stone << std::setprecision(4) << std::hex << escaped_ch;
29175930019STodd Fiala error << " at offset " << start_index;
292c1566308SPavel Labath value = error.str();
29397206d57SZachary Turner return Token::Status;
29475930019STodd Fiala }
295b9c1b51eSKate Stone } else if (is_end_quote) {
29675930019STodd Fiala return Token::String;
297b9c1b51eSKate Stone } else if (is_null) {
29875930019STodd Fiala value = "error: missing end quote for string";
29997206d57SZachary Turner return Token::Status;
30075930019STodd Fiala }
30175930019STodd Fiala }
30275930019STodd Fiala }
303b9c1b51eSKate Stone } break;
30475930019STodd Fiala
30575930019STodd Fiala case '-':
30675930019STodd Fiala case '0':
30775930019STodd Fiala case '1':
30875930019STodd Fiala case '2':
30975930019STodd Fiala case '3':
31075930019STodd Fiala case '4':
31175930019STodd Fiala case '5':
31275930019STodd Fiala case '6':
31375930019STodd Fiala case '7':
31475930019STodd Fiala case '8':
315b9c1b51eSKate Stone case '9': {
31675930019STodd Fiala bool done = false;
31775930019STodd Fiala bool got_decimal_point = false;
31875930019STodd Fiala uint64_t exp_index = 0;
31975930019STodd Fiala bool got_int_digits = (ch >= '0') && (ch <= '9');
32075930019STodd Fiala bool got_frac_digits = false;
32175930019STodd Fiala bool got_exp_digits = false;
322b9c1b51eSKate Stone while (!done) {
32375930019STodd Fiala const char next_ch = PeekChar();
324b9c1b51eSKate Stone switch (next_ch) {
32575930019STodd Fiala case '0':
32675930019STodd Fiala case '1':
32775930019STodd Fiala case '2':
32875930019STodd Fiala case '3':
32975930019STodd Fiala case '4':
33075930019STodd Fiala case '5':
33175930019STodd Fiala case '6':
33275930019STodd Fiala case '7':
33375930019STodd Fiala case '8':
33475930019STodd Fiala case '9':
335b9c1b51eSKate Stone if (exp_index != 0) {
33675930019STodd Fiala got_exp_digits = true;
337b9c1b51eSKate Stone } else if (got_decimal_point) {
33875930019STodd Fiala got_frac_digits = true;
339b9c1b51eSKate Stone } else {
34075930019STodd Fiala got_int_digits = true;
34175930019STodd Fiala }
34275930019STodd Fiala ++m_index; // Skip this character
34375930019STodd Fiala break;
34475930019STodd Fiala
34575930019STodd Fiala case '.':
346b9c1b51eSKate Stone if (got_decimal_point) {
34775930019STodd Fiala error << "error: extra decimal point found at offset " << start_index;
348c1566308SPavel Labath value = error.str();
34997206d57SZachary Turner return Token::Status;
350b9c1b51eSKate Stone } else {
35175930019STodd Fiala got_decimal_point = true;
35275930019STodd Fiala ++m_index; // Skip this character
35375930019STodd Fiala }
35475930019STodd Fiala break;
35575930019STodd Fiala
35675930019STodd Fiala case 'e':
35775930019STodd Fiala case 'E':
358b9c1b51eSKate Stone if (exp_index != 0) {
359b9c1b51eSKate Stone error << "error: extra exponent character found at offset "
360b9c1b51eSKate Stone << start_index;
361c1566308SPavel Labath value = error.str();
36297206d57SZachary Turner return Token::Status;
363b9c1b51eSKate Stone } else {
36475930019STodd Fiala exp_index = m_index;
36575930019STodd Fiala ++m_index; // Skip this character
36675930019STodd Fiala }
36775930019STodd Fiala break;
36875930019STodd Fiala
36975930019STodd Fiala case '+':
37075930019STodd Fiala case '-':
37175930019STodd Fiala // The '+' and '-' can only come after an exponent character...
372b9c1b51eSKate Stone if (exp_index == m_index - 1) {
37375930019STodd Fiala ++m_index; // Skip the exponent sign character
374b9c1b51eSKate Stone } else {
375b9c1b51eSKate Stone error << "error: unexpected " << next_ch << " character at offset "
376b9c1b51eSKate Stone << start_index;
377c1566308SPavel Labath value = error.str();
37897206d57SZachary Turner return Token::Status;
37975930019STodd Fiala }
38075930019STodd Fiala break;
38175930019STodd Fiala
38275930019STodd Fiala default:
38375930019STodd Fiala done = true;
38475930019STodd Fiala break;
38575930019STodd Fiala }
38675930019STodd Fiala }
38775930019STodd Fiala
388b9c1b51eSKate Stone if (m_index > start_index) {
38975930019STodd Fiala value = m_packet.substr(start_index, m_index - start_index);
390b9c1b51eSKate Stone if (got_decimal_point) {
391b9c1b51eSKate Stone if (exp_index != 0) {
39275930019STodd Fiala // We have an exponent, make sure we got exponent digits
393b9c1b51eSKate Stone if (got_exp_digits) {
39475930019STodd Fiala return Token::Float;
395b9c1b51eSKate Stone } else {
396b9c1b51eSKate Stone error << "error: got exponent character but no exponent digits at "
397b9c1b51eSKate Stone "offset in float value \""
398b9c1b51eSKate Stone << value.c_str() << "\"";
399b9c1b51eSKate Stone value = error.str();
40097206d57SZachary Turner return Token::Status;
40175930019STodd Fiala }
402b9c1b51eSKate Stone } else {
403b9c1b51eSKate Stone // No exponent, but we need at least one decimal after the decimal
404b9c1b51eSKate Stone // point
405b9c1b51eSKate Stone if (got_frac_digits) {
406b9c1b51eSKate Stone return Token::Float;
407b9c1b51eSKate Stone } else {
408b9c1b51eSKate Stone error << "error: no digits after decimal point \"" << value.c_str()
409b9c1b51eSKate Stone << "\"";
410c1566308SPavel Labath value = error.str();
41197206d57SZachary Turner return Token::Status;
41275930019STodd Fiala }
41375930019STodd Fiala }
414b9c1b51eSKate Stone } else {
41575930019STodd Fiala // No decimal point
416b9c1b51eSKate Stone if (got_int_digits) {
41775930019STodd Fiala // We need at least some integer digits to make an integer
41875930019STodd Fiala return Token::Integer;
419b9c1b51eSKate Stone } else {
42075930019STodd Fiala error << "error: no digits negate sign \"" << value.c_str() << "\"";
421c1566308SPavel Labath value = error.str();
42297206d57SZachary Turner return Token::Status;
42375930019STodd Fiala }
42475930019STodd Fiala }
425b9c1b51eSKate Stone } else {
42675930019STodd Fiala error << "error: invalid number found at offset " << start_index;
427c1566308SPavel Labath value = error.str();
42897206d57SZachary Turner return Token::Status;
42975930019STodd Fiala }
430b9c1b51eSKate Stone } break;
43175930019STodd Fiala default:
43275930019STodd Fiala break;
43375930019STodd Fiala }
434b9c1b51eSKate Stone error << "error: failed to parse token at offset " << start_index
435b9c1b51eSKate Stone << " (around character '" << ch << "')";
436c1566308SPavel Labath value = error.str();
43797206d57SZachary Turner return Token::Status;
43875930019STodd Fiala }
43975930019STodd Fiala
GetEscapedChar(bool & was_escaped)440b9c1b51eSKate Stone int JSONParser::GetEscapedChar(bool &was_escaped) {
44175930019STodd Fiala was_escaped = false;
44275930019STodd Fiala const char ch = GetChar();
443b9c1b51eSKate Stone if (ch == '\\') {
44475930019STodd Fiala was_escaped = true;
44575930019STodd Fiala const char ch2 = GetChar();
446b9c1b51eSKate Stone switch (ch2) {
44775930019STodd Fiala case '"':
44875930019STodd Fiala case '\\':
44975930019STodd Fiala case '/':
45075930019STodd Fiala default:
45175930019STodd Fiala break;
45275930019STodd Fiala
453b9c1b51eSKate Stone case 'b':
454b9c1b51eSKate Stone return '\b';
455b9c1b51eSKate Stone case 'f':
456b9c1b51eSKate Stone return '\f';
457b9c1b51eSKate Stone case 'n':
458b9c1b51eSKate Stone return '\n';
459b9c1b51eSKate Stone case 'r':
460b9c1b51eSKate Stone return '\r';
461b9c1b51eSKate Stone case 't':
462b9c1b51eSKate Stone return '\t';
463b9c1b51eSKate Stone case 'u': {
46475930019STodd Fiala const int hi_byte = DecodeHexU8();
46575930019STodd Fiala const int lo_byte = DecodeHexU8();
46675930019STodd Fiala if (hi_byte >= 0 && lo_byte >= 0)
46775930019STodd Fiala return hi_byte << 8 | lo_byte;
46875930019STodd Fiala return -1;
469b9c1b51eSKate Stone } break;
47075930019STodd Fiala }
47175930019STodd Fiala return ch2;
47275930019STodd Fiala }
47375930019STodd Fiala return ch;
47475930019STodd Fiala }
47575930019STodd Fiala
ParseJSONObject()476b9c1b51eSKate Stone JSONValue::SP JSONParser::ParseJSONObject() {
477b9c1b51eSKate Stone // The "JSONParser::Token::ObjectStart" token should have already been
478b9c1b51eSKate Stone // consumed
47975930019STodd Fiala // by the time this function is called
48075930019STodd Fiala std::unique_ptr<JSONObject> dict_up(new JSONObject());
48175930019STodd Fiala
48275930019STodd Fiala std::string value;
48375930019STodd Fiala std::string key;
48409ad8c8fSJonas Devlieghere while (true) {
48575930019STodd Fiala JSONParser::Token token = GetToken(value);
48675930019STodd Fiala
487b9c1b51eSKate Stone if (token == JSONParser::Token::String) {
48875930019STodd Fiala key.swap(value);
48975930019STodd Fiala token = GetToken(value);
490b9c1b51eSKate Stone if (token == JSONParser::Token::Colon) {
49175930019STodd Fiala JSONValue::SP value_sp = ParseJSONValue();
49275930019STodd Fiala if (value_sp)
49375930019STodd Fiala dict_up->SetObject(key, value_sp);
49475930019STodd Fiala else
49575930019STodd Fiala break;
49675930019STodd Fiala }
497b9c1b51eSKate Stone } else if (token == JSONParser::Token::ObjectEnd) {
49875930019STodd Fiala return JSONValue::SP(dict_up.release());
499b9c1b51eSKate Stone } else if (token == JSONParser::Token::Comma) {
50075930019STodd Fiala continue;
501b9c1b51eSKate Stone } else {
50275930019STodd Fiala break;
50375930019STodd Fiala }
50475930019STodd Fiala }
50575930019STodd Fiala return JSONValue::SP();
50675930019STodd Fiala }
50775930019STodd Fiala
ParseJSONArray()508b9c1b51eSKate Stone JSONValue::SP JSONParser::ParseJSONArray() {
509b9c1b51eSKate Stone // The "JSONParser::Token::ObjectStart" token should have already been
510b9c1b51eSKate Stone // consumed
51175930019STodd Fiala // by the time this function is called
51275930019STodd Fiala std::unique_ptr<JSONArray> array_up(new JSONArray());
51375930019STodd Fiala
51475930019STodd Fiala std::string value;
51575930019STodd Fiala std::string key;
51609ad8c8fSJonas Devlieghere while (true) {
51710b85143SAlex Cameron JSONParser::Token token = GetToken(value);
51810b85143SAlex Cameron if (token == JSONParser::Token::ArrayEnd)
51910b85143SAlex Cameron return JSONValue::SP(array_up.release());
52010b85143SAlex Cameron JSONValue::SP value_sp = ParseJSONValue(value, token);
52175930019STodd Fiala if (value_sp)
52275930019STodd Fiala array_up->AppendObject(value_sp);
52375930019STodd Fiala else
52475930019STodd Fiala break;
52575930019STodd Fiala
52610b85143SAlex Cameron token = GetToken(value);
527b9c1b51eSKate Stone if (token == JSONParser::Token::Comma) {
52875930019STodd Fiala continue;
529b9c1b51eSKate Stone } else if (token == JSONParser::Token::ArrayEnd) {
53075930019STodd Fiala return JSONValue::SP(array_up.release());
531b9c1b51eSKate Stone } else {
53275930019STodd Fiala break;
53375930019STodd Fiala }
53475930019STodd Fiala }
53575930019STodd Fiala return JSONValue::SP();
53675930019STodd Fiala }
53775930019STodd Fiala
ParseJSONValue()538b9c1b51eSKate Stone JSONValue::SP JSONParser::ParseJSONValue() {
53975930019STodd Fiala std::string value;
54075930019STodd Fiala const JSONParser::Token token = GetToken(value);
54110b85143SAlex Cameron return ParseJSONValue(value, token);
54210b85143SAlex Cameron }
54310b85143SAlex Cameron
ParseJSONValue(const std::string & value,const Token & token)54410b85143SAlex Cameron JSONValue::SP JSONParser::ParseJSONValue(const std::string &value,
54510b85143SAlex Cameron const Token &token) {
546b9c1b51eSKate Stone switch (token) {
54775930019STodd Fiala case JSONParser::Token::ObjectStart:
54875930019STodd Fiala return ParseJSONObject();
54975930019STodd Fiala
55075930019STodd Fiala case JSONParser::Token::ArrayStart:
55175930019STodd Fiala return ParseJSONArray();
55275930019STodd Fiala
553b9c1b51eSKate Stone case JSONParser::Token::Integer: {
554b9c1b51eSKate Stone if (value.front() == '-') {
55575930019STodd Fiala bool success = false;
55675930019STodd Fiala int64_t sval = StringConvert::ToSInt64(value.c_str(), 0, 0, &success);
55775930019STodd Fiala if (success)
55875930019STodd Fiala return JSONValue::SP(new JSONNumber(sval));
559b9c1b51eSKate Stone } else {
56075930019STodd Fiala bool success = false;
56175930019STodd Fiala uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success);
56275930019STodd Fiala if (success)
56375930019STodd Fiala return JSONValue::SP(new JSONNumber(uval));
56475930019STodd Fiala }
565b9c1b51eSKate Stone } break;
56675930019STodd Fiala
567b9c1b51eSKate Stone case JSONParser::Token::Float: {
56875930019STodd Fiala bool success = false;
56975930019STodd Fiala double val = StringConvert::ToDouble(value.c_str(), 0.0, &success);
57075930019STodd Fiala if (success)
57175930019STodd Fiala return JSONValue::SP(new JSONNumber(val));
572b9c1b51eSKate Stone } break;
57375930019STodd Fiala
57475930019STodd Fiala case JSONParser::Token::String:
57575930019STodd Fiala return JSONValue::SP(new JSONString(value));
57675930019STodd Fiala
57775930019STodd Fiala case JSONParser::Token::True:
57875930019STodd Fiala return JSONValue::SP(new JSONTrue());
57975930019STodd Fiala
58075930019STodd Fiala case JSONParser::Token::False:
58175930019STodd Fiala return JSONValue::SP(new JSONFalse());
58275930019STodd Fiala
58375930019STodd Fiala case JSONParser::Token::Null:
58475930019STodd Fiala return JSONValue::SP(new JSONNull());
58575930019STodd Fiala
58675930019STodd Fiala default:
58775930019STodd Fiala break;
58875930019STodd Fiala }
58975930019STodd Fiala return JSONValue::SP();
59075930019STodd Fiala }
591