1 //===---------------------StructuredData.cpp ---------------------*- C++-*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/Core/StructuredData.h"
16 #include "lldb/Core/DataBuffer.h"
17 #include "lldb/Core/Error.h"
18 #include "lldb/Core/StreamString.h"
19 #include "lldb/Host/File.h"
20 #include "lldb/Host/FileSpec.h"
21 #include "lldb/Host/StringConvert.h"
22 #include "lldb/Utility/JSON.h"
24 using namespace lldb_private;
26 //----------------------------------------------------------------------
27 // Functions that use a JSONParser to parse JSON into StructuredData
28 //----------------------------------------------------------------------
29 static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser);
30 static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser);
31 static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser);
33 StructuredData::ObjectSP
34 StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Error &error) {
35 StructuredData::ObjectSP return_sp;
36 if (!input_spec.Exists()) {
37 error.SetErrorStringWithFormat("input file %s does not exist.",
38 input_spec.GetPath().c_str());
42 File input_file(nullptr, File::OpenOptions::eOpenOptionRead,
43 lldb::eFilePermissionsUserRead);
44 std::string input_path = input_spec.GetPath();
46 input_file.Open(input_path.c_str(), File::OpenOptions::eOpenOptionRead,
47 lldb::eFilePermissionsUserRead);
49 if (!error.Success()) {
50 error.SetErrorStringWithFormat("could not open input file: %s - %s.",
51 input_spec.GetPath().c_str(),
56 lldb::DataBufferSP input_data;
57 size_t num_bytes = std::numeric_limits<size_t>::max();
59 error = input_file.Read(num_bytes, offset, true, input_data);
60 if (!error.Success()) {
61 error.SetErrorStringWithFormat("could not read input file: %s - %s.",
62 input_spec.GetPath().c_str(),
66 JSONParser json_parser((char *)input_data->GetBytes());
67 return_sp = ParseJSONValue(json_parser);
71 static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser) {
72 // The "JSONParser::Token::ObjectStart" token should have already been
74 // by the time this function is called
75 std::unique_ptr<StructuredData::Dictionary> dict_up(
76 new StructuredData::Dictionary());
81 JSONParser::Token token = json_parser.GetToken(value);
83 if (token == JSONParser::Token::String) {
85 token = json_parser.GetToken(value);
86 if (token == JSONParser::Token::Colon) {
87 StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
89 dict_up->AddItem(key, value_sp);
93 } else if (token == JSONParser::Token::ObjectEnd) {
94 return StructuredData::ObjectSP(dict_up.release());
95 } else if (token == JSONParser::Token::Comma) {
101 return StructuredData::ObjectSP();
104 static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser) {
105 // The "JSONParser::Token::ObjectStart" token should have already been
107 // by the time this function is called
108 std::unique_ptr<StructuredData::Array> array_up(new StructuredData::Array());
113 StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
115 array_up->AddItem(value_sp);
119 JSONParser::Token token = json_parser.GetToken(value);
120 if (token == JSONParser::Token::Comma) {
122 } else if (token == JSONParser::Token::ArrayEnd) {
123 return StructuredData::ObjectSP(array_up.release());
128 return StructuredData::ObjectSP();
131 static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser) {
133 const JSONParser::Token token = json_parser.GetToken(value);
135 case JSONParser::Token::ObjectStart:
136 return ParseJSONObject(json_parser);
138 case JSONParser::Token::ArrayStart:
139 return ParseJSONArray(json_parser);
141 case JSONParser::Token::Integer: {
142 bool success = false;
143 uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success);
145 return StructuredData::ObjectSP(new StructuredData::Integer(uval));
148 case JSONParser::Token::Float: {
149 bool success = false;
150 double val = StringConvert::ToDouble(value.c_str(), 0.0, &success);
152 return StructuredData::ObjectSP(new StructuredData::Float(val));
155 case JSONParser::Token::String:
156 return StructuredData::ObjectSP(new StructuredData::String(value));
158 case JSONParser::Token::True:
159 case JSONParser::Token::False:
160 return StructuredData::ObjectSP(
161 new StructuredData::Boolean(token == JSONParser::Token::True));
163 case JSONParser::Token::Null:
164 return StructuredData::ObjectSP(new StructuredData::Null());
169 return StructuredData::ObjectSP();
172 StructuredData::ObjectSP StructuredData::ParseJSON(std::string json_text) {
173 JSONParser json_parser(json_text.c_str());
174 StructuredData::ObjectSP object_sp = ParseJSONValue(json_parser);
178 StructuredData::ObjectSP
179 StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) {
180 if (this->GetType() == Type::eTypeDictionary) {
181 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.');
182 std::string key = match.first.str();
183 ObjectSP value = this->GetAsDictionary()->GetValueForKey(key);
185 // Do we have additional words to descend? If not, return the
186 // value we're at right now.
187 if (match.second.empty()) {
190 return value->GetObjectForDotSeparatedPath(match.second);
196 if (this->GetType() == Type::eTypeArray) {
197 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('[');
198 if (match.second.size() == 0) {
199 return this->shared_from_this();
202 uint64_t val = strtoul(match.second.str().c_str(), NULL, 10);
204 return this->GetAsArray()->GetItemAtIndex(val);
209 return this->shared_from_this();
212 void StructuredData::Object::DumpToStdout(bool pretty_print) const {
214 Dump(stream, pretty_print);
215 printf("%s\n", stream.GetData());
218 void StructuredData::Array::Dump(Stream &s, bool pretty_print) const {
225 for (const auto &item_sp : m_items) {
236 item_sp->Dump(s, pretty_print);
246 void StructuredData::Integer::Dump(Stream &s, bool pretty_print) const {
247 s.Printf("%" PRIu64, m_value);
250 void StructuredData::Float::Dump(Stream &s, bool pretty_print) const {
251 s.Printf("%lg", m_value);
254 void StructuredData::Boolean::Dump(Stream &s, bool pretty_print) const {
256 s.PutCString("true");
258 s.PutCString("false");
261 void StructuredData::String::Dump(Stream &s, bool pretty_print) const {
263 const size_t strsize = m_value.size();
264 for (size_t i = 0; i < strsize; ++i) {
265 char ch = m_value[i];
266 if (ch == '"' || ch == '\\')
267 quoted.push_back('\\');
268 quoted.push_back(ch);
270 s.Printf("\"%s\"", quoted.c_str());
273 void StructuredData::Dictionary::Dump(Stream &s, bool pretty_print) const {
280 for (const auto &pair : m_dict) {
290 s << "\"" << pair.first.AsCString() << "\" : ";
291 pair.second->Dump(s, pretty_print);
301 void StructuredData::Null::Dump(Stream &s, bool pretty_print) const {
305 void StructuredData::Generic::Dump(Stream &s, bool pretty_print) const {
306 s << "0x" << m_object;