1 //===--------------------- JSON.cpp -----------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
16 #include "StringConvert.h"
20 std::string
JSONString::json_string_quote_metachars(const std::string
&s
) {
21 if (s
.find('"') == std::string::npos
)
25 const size_t s_size
= s
.size();
26 const char *s_chars
= s
.c_str();
27 for (size_t i
= 0; i
< s_size
; i
++) {
28 unsigned char ch
= *(s_chars
+ i
);
30 output
.push_back('\\');
37 JSONString::JSONString() : JSONValue(JSONValue::Kind::String
), m_data() {}
39 JSONString::JSONString(const char *s
)
40 : JSONValue(JSONValue::Kind::String
), m_data(s
? s
: "") {}
42 JSONString::JSONString(const std::string
&s
)
43 : JSONValue(JSONValue::Kind::String
), m_data(s
) {}
45 void JSONString::Write(std::ostream
&s
) {
46 s
<< "\"" << json_string_quote_metachars(m_data
).c_str() << "\"";
49 uint64_t JSONNumber::GetAsUnsigned() const {
50 switch (m_data_type
) {
51 case DataType::Unsigned
:
52 return m_data
.m_unsigned
;
53 case DataType::Signed
:
54 return (uint64_t)m_data
.m_signed
;
55 case DataType::Double
:
56 return (uint64_t)m_data
.m_double
;
60 int64_t JSONNumber::GetAsSigned() const {
61 switch (m_data_type
) {
62 case DataType::Unsigned
:
63 return (int64_t)m_data
.m_unsigned
;
64 case DataType::Signed
:
65 return m_data
.m_signed
;
66 case DataType::Double
:
67 return (int64_t)m_data
.m_double
;
71 double JSONNumber::GetAsDouble() const {
72 switch (m_data_type
) {
73 case DataType::Unsigned
:
74 return (double)m_data
.m_unsigned
;
75 case DataType::Signed
:
76 return (double)m_data
.m_signed
;
77 case DataType::Double
:
78 return m_data
.m_double
;
82 void JSONNumber::Write(std::ostream
&s
) {
83 switch (m_data_type
) {
84 case DataType::Unsigned
:
85 s
<< m_data
.m_unsigned
;
87 case DataType::Signed
:
90 case DataType::Double
:
91 // Set max precision to emulate %g.
92 s
<< std::setprecision(std::numeric_limits
<double>::digits10
+ 1);
98 JSONTrue::JSONTrue() : JSONValue(JSONValue::Kind::True
) {}
100 void JSONTrue::Write(std::ostream
&s
) { s
<< "true"; }
102 JSONFalse::JSONFalse() : JSONValue(JSONValue::Kind::False
) {}
104 void JSONFalse::Write(std::ostream
&s
) { s
<< "false"; }
106 JSONNull::JSONNull() : JSONValue(JSONValue::Kind::Null
) {}
108 void JSONNull::Write(std::ostream
&s
) { s
<< "null"; }
110 JSONObject::JSONObject() : JSONValue(JSONValue::Kind::Object
) {}
112 void JSONObject::Write(std::ostream
&s
) {
115 auto iter
= m_elements
.begin(), end
= m_elements
.end();
116 for (; iter
!= end
; iter
++) {
121 JSONString
key(iter
->first
);
122 JSONValue::SP
value(iter
->second
);
130 bool JSONObject::SetObject(const std::string
&key
, JSONValue::SP value
) {
131 if (key
.empty() || nullptr == value
.get())
133 m_elements
[key
] = value
;
137 JSONValue::SP
JSONObject::GetObject(const std::string
&key
) const {
138 auto iter
= m_elements
.find(key
), end
= m_elements
.end();
140 return JSONValue::SP();
144 bool JSONObject::GetObjectAsBool(const std::string
&key
, bool &value
) const {
145 auto value_sp
= GetObject(key
);
147 // The given key doesn't exist, so we have no value.
151 if (JSONTrue::classof(value_sp
.get())) {
152 // We have the value, and it is true.
155 } else if (JSONFalse::classof(value_sp
.get())) {
156 // We have the value, and it is false.
160 // We don't have a valid bool value for the given key.
165 bool JSONObject::GetObjectAsString(const std::string
&key
,
166 std::string
&value
) const {
167 auto value_sp
= GetObject(key
);
169 // The given key doesn't exist, so we have no value.
173 if (!JSONString::classof(value_sp
.get()))
176 value
= static_cast<JSONString
*>(value_sp
.get())->GetData();
180 JSONArray::JSONArray() : JSONValue(JSONValue::Kind::Array
) {}
182 void JSONArray::Write(std::ostream
&s
) {
185 auto iter
= m_elements
.begin(), end
= m_elements
.end();
186 for (; iter
!= end
; iter
++) {
196 bool JSONArray::SetObject(Index i
, JSONValue::SP value
) {
197 if (value
.get() == nullptr)
199 if (i
< m_elements
.size()) {
200 m_elements
[i
] = value
;
203 if (i
== m_elements
.size()) {
204 m_elements
.push_back(value
);
210 bool JSONArray::AppendObject(JSONValue::SP value
) {
211 if (value
.get() == nullptr)
213 m_elements
.push_back(value
);
217 JSONValue::SP
JSONArray::GetObject(Index i
) {
218 if (i
< m_elements
.size())
219 return m_elements
[i
];
220 return JSONValue::SP();
223 JSONArray::Size
JSONArray::GetNumElements() { return m_elements
.size(); }
225 JSONParser::JSONParser(const char *cstr
) : StdStringExtractor(cstr
) {}
227 JSONParser::Token
JSONParser::GetToken(std::string
&value
) {
228 std::ostringstream error
;
232 const uint64_t start_index
= m_index
;
233 const char ch
= GetChar();
236 return Token::ObjectStart
;
238 return Token::ObjectEnd
;
240 return Token::ArrayStart
;
242 return Token::ArrayEnd
;
248 return Token::EndOfFile
;
250 if (GetChar() == 'r')
251 if (GetChar() == 'u')
252 if (GetChar() == 'e')
257 if (GetChar() == 'a')
258 if (GetChar() == 'l')
259 if (GetChar() == 's')
260 if (GetChar() == 'e')
265 if (GetChar() == 'u')
266 if (GetChar() == 'l')
267 if (GetChar() == 'l')
273 bool was_escaped
= false;
274 int escaped_ch
= GetEscapedChar(was_escaped
);
275 if (escaped_ch
== -1) {
276 error
<< "error: an error occurred getting a character from offset "
279 return Token::Status
;
282 const bool is_end_quote
= escaped_ch
== '"';
283 const bool is_null
= escaped_ch
== 0;
284 if (was_escaped
|| (!is_end_quote
&& !is_null
)) {
285 if (CHAR_MIN
<= escaped_ch
&& escaped_ch
<= CHAR_MAX
) {
286 value
.append(1, (char)escaped_ch
);
288 error
<< "error: wide character support is needed for unicode "
290 << std::setprecision(4) << std::hex
<< escaped_ch
;
291 error
<< " at offset " << start_index
;
293 return Token::Status
;
295 } else if (is_end_quote
) {
296 return Token::String
;
297 } else if (is_null
) {
298 value
= "error: missing end quote for string";
299 return Token::Status
;
317 bool got_decimal_point
= false;
318 uint64_t exp_index
= 0;
319 bool got_int_digits
= (ch
>= '0') && (ch
<= '9');
320 bool got_frac_digits
= false;
321 bool got_exp_digits
= false;
323 const char next_ch
= PeekChar();
335 if (exp_index
!= 0) {
336 got_exp_digits
= true;
337 } else if (got_decimal_point
) {
338 got_frac_digits
= true;
340 got_int_digits
= true;
342 ++m_index
; // Skip this character
346 if (got_decimal_point
) {
347 error
<< "error: extra decimal point found at offset " << start_index
;
349 return Token::Status
;
351 got_decimal_point
= true;
352 ++m_index
; // Skip this character
358 if (exp_index
!= 0) {
359 error
<< "error: extra exponent character found at offset "
362 return Token::Status
;
365 ++m_index
; // Skip this character
371 // The '+' and '-' can only come after an exponent character...
372 if (exp_index
== m_index
- 1) {
373 ++m_index
; // Skip the exponent sign character
375 error
<< "error: unexpected " << next_ch
<< " character at offset "
378 return Token::Status
;
388 if (m_index
> start_index
) {
389 value
= m_packet
.substr(start_index
, m_index
- start_index
);
390 if (got_decimal_point
) {
391 if (exp_index
!= 0) {
392 // We have an exponent, make sure we got exponent digits
393 if (got_exp_digits
) {
396 error
<< "error: got exponent character but no exponent digits at "
397 "offset in float value \""
398 << value
.c_str() << "\"";
400 return Token::Status
;
403 // No exponent, but we need at least one decimal after the decimal
405 if (got_frac_digits
) {
408 error
<< "error: no digits after decimal point \"" << value
.c_str()
411 return Token::Status
;
416 if (got_int_digits
) {
417 // We need at least some integer digits to make an integer
418 return Token::Integer
;
420 error
<< "error: no digits negate sign \"" << value
.c_str() << "\"";
422 return Token::Status
;
426 error
<< "error: invalid number found at offset " << start_index
;
428 return Token::Status
;
434 error
<< "error: failed to parse token at offset " << start_index
435 << " (around character '" << ch
<< "')";
437 return Token::Status
;
440 int JSONParser::GetEscapedChar(bool &was_escaped
) {
442 const char ch
= GetChar();
445 const char ch2
= GetChar();
464 const int hi_byte
= DecodeHexU8();
465 const int lo_byte
= DecodeHexU8();
466 if (hi_byte
>= 0 && lo_byte
>= 0)
467 return hi_byte
<< 8 | lo_byte
;
476 JSONValue::SP
JSONParser::ParseJSONObject() {
477 // The "JSONParser::Token::ObjectStart" token should have already been
479 // by the time this function is called
480 std::unique_ptr
<JSONObject
> dict_up(new JSONObject());
485 JSONParser::Token token
= GetToken(value
);
487 if (token
== JSONParser::Token::String
) {
489 token
= GetToken(value
);
490 if (token
== JSONParser::Token::Colon
) {
491 JSONValue::SP value_sp
= ParseJSONValue();
493 dict_up
->SetObject(key
, value_sp
);
497 } else if (token
== JSONParser::Token::ObjectEnd
) {
498 return JSONValue::SP(dict_up
.release());
499 } else if (token
== JSONParser::Token::Comma
) {
505 return JSONValue::SP();
508 JSONValue::SP
JSONParser::ParseJSONArray() {
509 // The "JSONParser::Token::ObjectStart" token should have already been
511 // by the time this function is called
512 std::unique_ptr
<JSONArray
> array_up(new JSONArray());
517 JSONParser::Token token
= GetToken(value
);
518 if (token
== JSONParser::Token::ArrayEnd
)
519 return JSONValue::SP(array_up
.release());
520 JSONValue::SP value_sp
= ParseJSONValue(value
, token
);
522 array_up
->AppendObject(value_sp
);
526 token
= GetToken(value
);
527 if (token
== JSONParser::Token::Comma
) {
529 } else if (token
== JSONParser::Token::ArrayEnd
) {
530 return JSONValue::SP(array_up
.release());
535 return JSONValue::SP();
538 JSONValue::SP
JSONParser::ParseJSONValue() {
540 const JSONParser::Token token
= GetToken(value
);
541 return ParseJSONValue(value
, token
);
544 JSONValue::SP
JSONParser::ParseJSONValue(const std::string
&value
,
545 const Token
&token
) {
547 case JSONParser::Token::ObjectStart
:
548 return ParseJSONObject();
550 case JSONParser::Token::ArrayStart
:
551 return ParseJSONArray();
553 case JSONParser::Token::Integer
: {
554 if (value
.front() == '-') {
555 bool success
= false;
556 int64_t sval
= StringConvert::ToSInt64(value
.c_str(), 0, 0, &success
);
558 return JSONValue::SP(new JSONNumber(sval
));
560 bool success
= false;
561 uint64_t uval
= StringConvert::ToUInt64(value
.c_str(), 0, 0, &success
);
563 return JSONValue::SP(new JSONNumber(uval
));
567 case JSONParser::Token::Float
: {
568 bool success
= false;
569 double val
= StringConvert::ToDouble(value
.c_str(), 0.0, &success
);
571 return JSONValue::SP(new JSONNumber(val
));
574 case JSONParser::Token::String
:
575 return JSONValue::SP(new JSONString(value
));
577 case JSONParser::Token::True
:
578 return JSONValue::SP(new JSONTrue());
580 case JSONParser::Token::False
:
581 return JSONValue::SP(new JSONFalse());
583 case JSONParser::Token::Null
:
584 return JSONValue::SP(new JSONNull());
589 return JSONValue::SP();