+++ /dev/null
-//===---------------------JSON.h --------------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef utility_JSON_h_
-#define utility_JSON_h_
-
-#include "lldb/Utility/StringExtractor.h"
-
-#include <map>
-#include <memory>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-#include <stdint.h>
-
-namespace lldb_private {
-class Stream;
-
-class JSONValue {
-public:
- virtual void Write(Stream &s) = 0;
-
- typedef std::shared_ptr<JSONValue> SP;
-
- enum class Kind { String, Number, True, False, Null, Object, Array };
-
- JSONValue(Kind k) : m_kind(k) {}
-
- Kind GetKind() const { return m_kind; }
-
- virtual ~JSONValue() = default;
-
-private:
- const Kind m_kind;
-};
-
-class JSONString : public JSONValue {
-public:
- JSONString();
- JSONString(const char *s);
- JSONString(const std::string &s);
-
- JSONString(const JSONString &s) = delete;
- JSONString &operator=(const JSONString &s) = delete;
-
- void Write(Stream &s) override;
-
- typedef std::shared_ptr<JSONString> SP;
-
- std::string GetData() { return m_data; }
-
- static bool classof(const JSONValue *V) {
- return V->GetKind() == JSONValue::Kind::String;
- }
-
- ~JSONString() override = default;
-
-private:
- static std::string json_string_quote_metachars(const std::string &);
-
- std::string m_data;
-};
-
-class JSONNumber : public JSONValue {
-public:
- typedef std::shared_ptr<JSONNumber> SP;
-
- // We cretae a constructor for all integer and floating point type with using
- // templates and
- // SFINAE to avoid having ambiguous overloads because of the implicit type
- // promotion. If we
- // would have constructors only with int64_t, uint64_t and double types then
- // constructing a JSONNumber from an int32_t (or any other similar type)
- // would fail to compile.
-
- template <typename T, typename std::enable_if<
- std::is_integral<T>::value &&
- std::is_unsigned<T>::value>::type * = nullptr>
- explicit JSONNumber(T u)
- : JSONValue(JSONValue::Kind::Number), m_data_type(DataType::Unsigned) {
- m_data.m_unsigned = u;
- }
-
- template <typename T,
- typename std::enable_if<std::is_integral<T>::value &&
- std::is_signed<T>::value>::type * = nullptr>
- explicit JSONNumber(T s)
- : JSONValue(JSONValue::Kind::Number), m_data_type(DataType::Signed) {
- m_data.m_signed = s;
- }
-
- template <typename T, typename std::enable_if<
- std::is_floating_point<T>::value>::type * = nullptr>
- explicit JSONNumber(T d)
- : JSONValue(JSONValue::Kind::Number), m_data_type(DataType::Double) {
- m_data.m_double = d;
- }
-
- ~JSONNumber() override = default;
-
- JSONNumber(const JSONNumber &s) = delete;
- JSONNumber &operator=(const JSONNumber &s) = delete;
-
- void Write(Stream &s) override;
-
- uint64_t GetAsUnsigned() const;
-
- int64_t GetAsSigned() const;
-
- double GetAsDouble() const;
-
- static bool classof(const JSONValue *V) {
- return V->GetKind() == JSONValue::Kind::Number;
- }
-
-private:
- enum class DataType : uint8_t { Unsigned, Signed, Double } m_data_type;
-
- union {
- uint64_t m_unsigned;
- int64_t m_signed;
- double m_double;
- } m_data;
-};
-
-class JSONTrue : public JSONValue {
-public:
- JSONTrue();
-
- JSONTrue(const JSONTrue &s) = delete;
- JSONTrue &operator=(const JSONTrue &s) = delete;
-
- void Write(Stream &s) override;
-
- typedef std::shared_ptr<JSONTrue> SP;
-
- static bool classof(const JSONValue *V) {
- return V->GetKind() == JSONValue::Kind::True;
- }
-
- ~JSONTrue() override = default;
-};
-
-class JSONFalse : public JSONValue {
-public:
- JSONFalse();
-
- JSONFalse(const JSONFalse &s) = delete;
- JSONFalse &operator=(const JSONFalse &s) = delete;
-
- void Write(Stream &s) override;
-
- typedef std::shared_ptr<JSONFalse> SP;
-
- static bool classof(const JSONValue *V) {
- return V->GetKind() == JSONValue::Kind::False;
- }
-
- ~JSONFalse() override = default;
-};
-
-class JSONNull : public JSONValue {
-public:
- JSONNull();
-
- JSONNull(const JSONNull &s) = delete;
- JSONNull &operator=(const JSONNull &s) = delete;
-
- void Write(Stream &s) override;
-
- typedef std::shared_ptr<JSONNull> SP;
-
- static bool classof(const JSONValue *V) {
- return V->GetKind() == JSONValue::Kind::Null;
- }
-
- ~JSONNull() override = default;
-};
-
-class JSONObject : public JSONValue {
-public:
- JSONObject();
-
- JSONObject(const JSONObject &s) = delete;
- JSONObject &operator=(const JSONObject &s) = delete;
-
- void Write(Stream &s) override;
-
- typedef std::shared_ptr<JSONObject> SP;
-
- static bool classof(const JSONValue *V) {
- return V->GetKind() == JSONValue::Kind::Object;
- }
-
- bool SetObject(const std::string &key, JSONValue::SP value);
-
- JSONValue::SP GetObject(const std::string &key);
-
- ~JSONObject() override = default;
-
-private:
- typedef std::map<std::string, JSONValue::SP> Map;
- typedef Map::iterator Iterator;
- Map m_elements;
-};
-
-class JSONArray : public JSONValue {
-public:
- JSONArray();
-
- JSONArray(const JSONArray &s) = delete;
- JSONArray &operator=(const JSONArray &s) = delete;
-
- void Write(Stream &s) override;
-
- typedef std::shared_ptr<JSONArray> SP;
-
- static bool classof(const JSONValue *V) {
- return V->GetKind() == JSONValue::Kind::Array;
- }
-
-private:
- typedef std::vector<JSONValue::SP> Vector;
- typedef Vector::iterator Iterator;
- typedef Vector::size_type Index;
- typedef Vector::size_type Size;
-
-public:
- bool SetObject(Index i, JSONValue::SP value);
-
- bool AppendObject(JSONValue::SP value);
-
- JSONValue::SP GetObject(Index i);
-
- Size GetNumElements();
-
- ~JSONArray() override = default;
-
- Vector m_elements;
-};
-
-class JSONParser : public StringExtractor {
-public:
- enum Token {
- Invalid,
- Status,
- ObjectStart,
- ObjectEnd,
- ArrayStart,
- ArrayEnd,
- Comma,
- Colon,
- String,
- Integer,
- Float,
- True,
- False,
- Null,
- EndOfFile
- };
-
- JSONParser(llvm::StringRef data);
-
- int GetEscapedChar(bool &was_escaped);
-
- Token GetToken(std::string &value);
-
- JSONValue::SP ParseJSONValue();
-
-protected:
- JSONValue::SP ParseJSONObject();
-
- JSONValue::SP ParseJSONArray();
-};
-} // namespace lldb_private
-
-#endif // utility_JSON_h_
+++ /dev/null
-//===--------------------- JSON.cpp -----------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/JSON.h"
-
-#include "lldb/Utility/Stream.h"
-#include "lldb/Utility/StreamString.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/ErrorHandling.h"
-
-#include <inttypes.h>
-#include <limits.h>
-#include <stddef.h>
-#include <utility>
-
-using namespace lldb_private;
-
-std::string JSONString::json_string_quote_metachars(const std::string &s) {
- if (s.find_first_of("\\\n\"") == std::string::npos)
- return s;
-
- std::string output;
- const size_t s_size = s.size();
- const char *s_chars = s.c_str();
- for (size_t i = 0; i < s_size; i++) {
- unsigned char ch = *(s_chars + i);
- if (ch == '"' || ch == '\\' || ch == '\n') {
- output.push_back('\\');
- if (ch == '\n') ch = 'n';
- }
- output.push_back(ch);
- }
- return output;
-}
-
-JSONString::JSONString() : JSONValue(JSONValue::Kind::String), m_data() {}
-
-JSONString::JSONString(const char *s)
- : JSONValue(JSONValue::Kind::String), m_data(s ? s : "") {}
-
-JSONString::JSONString(const std::string &s)
- : JSONValue(JSONValue::Kind::String), m_data(s) {}
-
-void JSONString::Write(Stream &s) {
- s.Printf("\"%s\"", json_string_quote_metachars(m_data).c_str());
-}
-
-uint64_t JSONNumber::GetAsUnsigned() const {
- switch (m_data_type) {
- case DataType::Unsigned:
- return m_data.m_unsigned;
- case DataType::Signed:
- return static_cast<uint64_t>(m_data.m_signed);
- case DataType::Double:
- return static_cast<uint64_t>(m_data.m_double);
- }
- llvm_unreachable("Unhandled data type");
-}
-
-int64_t JSONNumber::GetAsSigned() const {
- switch (m_data_type) {
- case DataType::Unsigned:
- return static_cast<int64_t>(m_data.m_unsigned);
- case DataType::Signed:
- return m_data.m_signed;
- case DataType::Double:
- return static_cast<int64_t>(m_data.m_double);
- }
- llvm_unreachable("Unhandled data type");
-}
-
-double JSONNumber::GetAsDouble() const {
- switch (m_data_type) {
- case DataType::Unsigned:
- return static_cast<double>(m_data.m_unsigned);
- case DataType::Signed:
- return static_cast<double>(m_data.m_signed);
- case DataType::Double:
- return m_data.m_double;
- }
- llvm_unreachable("Unhandled data type");
-}
-
-void JSONNumber::Write(Stream &s) {
- switch (m_data_type) {
- case DataType::Unsigned:
- s.Printf("%" PRIu64, m_data.m_unsigned);
- break;
- case DataType::Signed:
- s.Printf("%" PRId64, m_data.m_signed);
- break;
- case DataType::Double:
- s.Printf("%g", m_data.m_double);
- break;
- }
-}
-
-JSONTrue::JSONTrue() : JSONValue(JSONValue::Kind::True) {}
-
-void JSONTrue::Write(Stream &s) { s.Printf("true"); }
-
-JSONFalse::JSONFalse() : JSONValue(JSONValue::Kind::False) {}
-
-void JSONFalse::Write(Stream &s) { s.Printf("false"); }
-
-JSONNull::JSONNull() : JSONValue(JSONValue::Kind::Null) {}
-
-void JSONNull::Write(Stream &s) { s.Printf("null"); }
-
-JSONObject::JSONObject() : JSONValue(JSONValue::Kind::Object) {}
-
-void JSONObject::Write(Stream &s) {
- bool first = true;
- s.PutChar('{');
- auto iter = m_elements.begin(), end = m_elements.end();
- for (; iter != end; iter++) {
- if (first)
- first = false;
- else
- s.PutChar(',');
- JSONString key(iter->first);
- JSONValue::SP value(iter->second);
- key.Write(s);
- s.PutChar(':');
- value->Write(s);
- }
- s.PutChar('}');
-}
-
-bool JSONObject::SetObject(const std::string &key, JSONValue::SP value) {
- if (key.empty() || nullptr == value.get())
- return false;
- m_elements[key] = value;
- return true;
-}
-
-JSONValue::SP JSONObject::GetObject(const std::string &key) {
- auto iter = m_elements.find(key), end = m_elements.end();
- if (iter == end)
- return JSONValue::SP();
- return iter->second;
-}
-
-JSONArray::JSONArray() : JSONValue(JSONValue::Kind::Array) {}
-
-void JSONArray::Write(Stream &s) {
- bool first = true;
- s.PutChar('[');
- auto iter = m_elements.begin(), end = m_elements.end();
- for (; iter != end; iter++) {
- if (first)
- first = false;
- else
- s.PutChar(',');
- (*iter)->Write(s);
- }
- s.PutChar(']');
-}
-
-bool JSONArray::SetObject(Index i, JSONValue::SP value) {
- if (value.get() == nullptr)
- return false;
- if (i < m_elements.size()) {
- m_elements[i] = value;
- return true;
- }
- if (i == m_elements.size()) {
- m_elements.push_back(value);
- return true;
- }
- return false;
-}
-
-bool JSONArray::AppendObject(JSONValue::SP value) {
- if (value.get() == nullptr)
- return false;
- m_elements.push_back(value);
- return true;
-}
-
-JSONValue::SP JSONArray::GetObject(Index i) {
- if (i < m_elements.size())
- return m_elements[i];
- return JSONValue::SP();
-}
-
-JSONArray::Size JSONArray::GetNumElements() { return m_elements.size(); }
-
-JSONParser::JSONParser(llvm::StringRef data) : StringExtractor(data) {}
-
-JSONParser::Token JSONParser::GetToken(std::string &value) {
- StreamString error;
-
- value.clear();
- SkipSpaces();
- const uint64_t start_index = m_index;
- const char ch = GetChar();
- switch (ch) {
- case '{':
- return Token::ObjectStart;
- case '}':
- return Token::ObjectEnd;
- case '[':
- return Token::ArrayStart;
- case ']':
- return Token::ArrayEnd;
- case ',':
- return Token::Comma;
- case ':':
- return Token::Colon;
- case '\0':
- return Token::EndOfFile;
- case 't':
- if (GetChar() == 'r')
- if (GetChar() == 'u')
- if (GetChar() == 'e')
- return Token::True;
- break;
-
- case 'f':
- if (GetChar() == 'a')
- if (GetChar() == 'l')
- if (GetChar() == 's')
- if (GetChar() == 'e')
- return Token::False;
- break;
-
- case 'n':
- if (GetChar() == 'u')
- if (GetChar() == 'l')
- if (GetChar() == 'l')
- return Token::Null;
- break;
-
- case '"': {
- while (true) {
- bool was_escaped = false;
- int escaped_ch = GetEscapedChar(was_escaped);
- if (escaped_ch == -1) {
- error.Printf(
- "error: an error occurred getting a character from offset %" PRIu64,
- start_index);
- value = std::move(error.GetString());
- return Token::Status;
-
- } else {
- const bool is_end_quote = escaped_ch == '"';
- const bool is_null = escaped_ch == 0;
- if (was_escaped || (!is_end_quote && !is_null)) {
- if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX) {
- value.append(1, static_cast<char>(escaped_ch));
- } else {
- error.Printf("error: wide character support is needed for unicode "
- "character 0x%4.4x at offset %" PRIu64,
- escaped_ch, start_index);
- value = std::move(error.GetString());
- return Token::Status;
- }
- } else if (is_end_quote) {
- return Token::String;
- } else if (is_null) {
- value = "error: missing end quote for string";
- return Token::Status;
- }
- }
- }
- } break;
-
- case '-':
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9': {
- bool done = false;
- bool got_decimal_point = false;
- uint64_t exp_index = 0;
- bool got_int_digits = (ch >= '0') && (ch <= '9');
- bool got_frac_digits = false;
- bool got_exp_digits = false;
- while (!done) {
- const char next_ch = PeekChar();
- switch (next_ch) {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- if (exp_index != 0) {
- got_exp_digits = true;
- } else if (got_decimal_point) {
- got_frac_digits = true;
- } else {
- got_int_digits = true;
- }
- ++m_index; // Skip this character
- break;
-
- case '.':
- if (got_decimal_point) {
- error.Printf("error: extra decimal point found at offset %" PRIu64,
- start_index);
- value = std::move(error.GetString());
- return Token::Status;
- } else {
- got_decimal_point = true;
- ++m_index; // Skip this character
- }
- break;
-
- case 'e':
- case 'E':
- if (exp_index != 0) {
- error.Printf(
- "error: extra exponent character found at offset %" PRIu64,
- start_index);
- value = std::move(error.GetString());
- return Token::Status;
- } else {
- exp_index = m_index;
- ++m_index; // Skip this character
- }
- break;
-
- case '+':
- case '-':
- // The '+' and '-' can only come after an exponent character...
- if (exp_index == m_index - 1) {
- ++m_index; // Skip the exponent sign character
- } else {
- error.Printf("error: unexpected %c character at offset %" PRIu64,
- next_ch, start_index);
- value = std::move(error.GetString());
- return Token::Status;
- }
- break;
-
- default:
- done = true;
- break;
- }
- }
-
- if (m_index > start_index) {
- value = m_packet.substr(start_index, m_index - start_index);
- if (got_decimal_point) {
- if (exp_index != 0) {
- // We have an exponent, make sure we got exponent digits
- if (got_exp_digits) {
- return Token::Float;
- } else {
- error.Printf("error: got exponent character but no exponent digits "
- "at offset in float value \"%s\"",
- value.c_str());
- value = std::move(error.GetString());
- return Token::Status;
- }
- } else {
- // No exponent, but we need at least one decimal after the decimal
- // point
- if (got_frac_digits) {
- return Token::Float;
- } else {
- error.Printf("error: no digits after decimal point \"%s\"",
- value.c_str());
- value = std::move(error.GetString());
- return Token::Status;
- }
- }
- } else {
- // No decimal point
- if (got_int_digits) {
- // We need at least some integer digits to make an integer
- return Token::Integer;
- } else {
- error.Printf("error: no digits negate sign \"%s\"", value.c_str());
- value = std::move(error.GetString());
- return Token::Status;
- }
- }
- } else {
- error.Printf("error: invalid number found at offset %" PRIu64,
- start_index);
- value = std::move(error.GetString());
- return Token::Status;
- }
- } break;
- default:
- break;
- }
- error.Printf("error: failed to parse token at offset %" PRIu64
- " (around character '%c')",
- start_index, ch);
- value = std::move(error.GetString());
- return Token::Status;
-}
-
-int JSONParser::GetEscapedChar(bool &was_escaped) {
- was_escaped = false;
- const char ch = GetChar();
- if (ch == '\\') {
- was_escaped = true;
- const char ch2 = GetChar();
- switch (ch2) {
- case '"':
- case '\\':
- case '/':
- default:
- break;
-
- case 'b':
- return '\b';
- case 'f':
- return '\f';
- case 'n':
- return '\n';
- case 'r':
- return '\r';
- case 't':
- return '\t';
- case 'u': {
- const int hi_byte = DecodeHexU8();
- const int lo_byte = DecodeHexU8();
- if (hi_byte >= 0 && lo_byte >= 0)
- return hi_byte << 8 | lo_byte;
- return -1;
- } break;
- }
- return ch2;
- }
- return ch;
-}
-
-JSONValue::SP JSONParser::ParseJSONObject() {
- // The "JSONParser::Token::ObjectStart" token should have already been
- // consumed by the time this function is called
- std::unique_ptr<JSONObject> dict_up(new JSONObject());
-
- std::string value;
- std::string key;
- while (true) {
- JSONParser::Token token = GetToken(value);
-
- if (token == JSONParser::Token::String) {
- key.swap(value);
- token = GetToken(value);
- if (token == JSONParser::Token::Colon) {
- JSONValue::SP value_sp = ParseJSONValue();
- if (value_sp)
- dict_up->SetObject(key, value_sp);
- else
- break;
- }
- } else if (token == JSONParser::Token::ObjectEnd) {
- return JSONValue::SP(dict_up.release());
- } else if (token == JSONParser::Token::Comma) {
- continue;
- } else {
- break;
- }
- }
- return JSONValue::SP();
-}
-
-JSONValue::SP JSONParser::ParseJSONArray() {
- // The "JSONParser::Token::ObjectStart" token should have already been
- // consumed by the time this function is called
- std::unique_ptr<JSONArray> array_up(new JSONArray());
-
- std::string value;
- std::string key;
- while (true) {
- JSONValue::SP value_sp = ParseJSONValue();
- if (value_sp)
- array_up->AppendObject(value_sp);
- else
- break;
-
- JSONParser::Token token = GetToken(value);
- if (token == JSONParser::Token::Comma) {
- continue;
- } else if (token == JSONParser::Token::ArrayEnd) {
- return JSONValue::SP(array_up.release());
- } else {
- break;
- }
- }
- return JSONValue::SP();
-}
-
-JSONValue::SP JSONParser::ParseJSONValue() {
- std::string value;
- const JSONParser::Token token = GetToken(value);
- switch (token) {
- case JSONParser::Token::ObjectStart:
- return ParseJSONObject();
-
- case JSONParser::Token::ArrayStart:
- return ParseJSONArray();
-
- case JSONParser::Token::Integer: {
- if (value.front() == '-') {
- int64_t sval = 0;
- if (!llvm::StringRef(value).getAsInteger(0, sval))
- return JSONValue::SP(new JSONNumber(sval));
- } else {
- uint64_t uval = 0;
- if (!llvm::StringRef(value).getAsInteger(0, uval))
- return JSONValue::SP(new JSONNumber(uval));
- }
- } break;
-
- case JSONParser::Token::Float: {
- double D;
- if (!llvm::StringRef(value).getAsDouble(D))
- return JSONValue::SP(new JSONNumber(D));
- } break;
-
- case JSONParser::Token::String:
- return JSONValue::SP(new JSONString(value));
-
- case JSONParser::Token::True:
- return JSONValue::SP(new JSONTrue());
-
- case JSONParser::Token::False:
- return JSONValue::SP(new JSONFalse());
-
- case JSONParser::Token::Null:
- return JSONValue::SP(new JSONNull());
-
- default:
- break;
- }
- return JSONValue::SP();
-}