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"
12 #include "lldb/Host/File.h"
13 #include "lldb/Host/StringConvert.h"
14 #include "lldb/Utility/DataBuffer.h"
15 #include "lldb/Utility/Error.h"
16 #include "lldb/Utility/FileSpec.h"
17 #include "lldb/Utility/JSON.h"
18 #include "lldb/Utility/Stream.h" // for Stream
19 #include "lldb/Utility/StreamString.h"
20 #include "lldb/lldb-enumerations.h" // for FilePermissions::eFilePermiss...
21 #include "lldb/lldb-forward.h" // for DataBufferSP
23 #include "llvm/ADT/STLExtras.h" // for make_unique
25 #include <limits> // for numeric_limits
29 #include <stdio.h> // for printf
31 #include <sys/types.h> // for off_t
33 using namespace lldb_private;
35 //----------------------------------------------------------------------
36 // Functions that use a JSONParser to parse JSON into StructuredData
37 //----------------------------------------------------------------------
38 static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser);
39 static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser);
40 static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser);
42 StructuredData::ObjectSP
43 StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Error &error) {
44 StructuredData::ObjectSP return_sp;
45 if (!input_spec.Exists()) {
46 error.SetErrorStringWithFormat("input file %s does not exist.",
47 input_spec.GetPath().c_str());
51 File input_file(nullptr, File::OpenOptions::eOpenOptionRead,
52 lldb::eFilePermissionsUserRead);
53 std::string input_path = input_spec.GetPath();
55 input_file.Open(input_path.c_str(), File::OpenOptions::eOpenOptionRead,
56 lldb::eFilePermissionsUserRead);
58 if (!error.Success()) {
59 error.SetErrorStringWithFormat("could not open input file: %s - %s.",
60 input_spec.GetPath().c_str(),
65 lldb::DataBufferSP input_data;
66 size_t num_bytes = std::numeric_limits<size_t>::max();
68 error = input_file.Read(num_bytes, offset, true, input_data);
69 if (!error.Success()) {
70 error.SetErrorStringWithFormat("could not read input file: %s - %s.",
71 input_spec.GetPath().c_str(),
75 JSONParser json_parser((char *)input_data->GetBytes());
76 return_sp = ParseJSONValue(json_parser);
80 static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser) {
81 // The "JSONParser::Token::ObjectStart" token should have already been
82 // consumed by the time this function is called
83 auto dict_up = llvm::make_unique<StructuredData::Dictionary>();
88 JSONParser::Token token = json_parser.GetToken(value);
90 if (token == JSONParser::Token::String) {
92 token = json_parser.GetToken(value);
93 if (token == JSONParser::Token::Colon) {
94 StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
96 dict_up->AddItem(key, value_sp);
100 } else if (token == JSONParser::Token::ObjectEnd) {
101 return StructuredData::ObjectSP(dict_up.release());
102 } else if (token == JSONParser::Token::Comma) {
108 return StructuredData::ObjectSP();
111 static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser) {
112 // The "JSONParser::Token::ObjectStart" token should have already been
114 // by the time this function is called
115 auto array_up = llvm::make_unique<StructuredData::Array>();
120 StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
122 array_up->AddItem(value_sp);
126 JSONParser::Token token = json_parser.GetToken(value);
127 if (token == JSONParser::Token::Comma) {
129 } else if (token == JSONParser::Token::ArrayEnd) {
130 return StructuredData::ObjectSP(array_up.release());
135 return StructuredData::ObjectSP();
138 static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser) {
140 const JSONParser::Token token = json_parser.GetToken(value);
142 case JSONParser::Token::ObjectStart:
143 return ParseJSONObject(json_parser);
145 case JSONParser::Token::ArrayStart:
146 return ParseJSONArray(json_parser);
148 case JSONParser::Token::Integer: {
149 bool success = false;
150 uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success);
152 return std::make_shared<StructuredData::Integer>(uval);
155 case JSONParser::Token::Float: {
156 bool success = false;
157 double val = StringConvert::ToDouble(value.c_str(), 0.0, &success);
159 return std::make_shared<StructuredData::Float>(val);
162 case JSONParser::Token::String:
163 return std::make_shared<StructuredData::String>(value);
165 case JSONParser::Token::True:
166 case JSONParser::Token::False:
167 return std::make_shared<StructuredData::Boolean>(token ==
168 JSONParser::Token::True);
170 case JSONParser::Token::Null:
171 return std::make_shared<StructuredData::Null>();
176 return StructuredData::ObjectSP();
179 StructuredData::ObjectSP StructuredData::ParseJSON(std::string json_text) {
180 JSONParser json_parser(json_text.c_str());
181 StructuredData::ObjectSP object_sp = ParseJSONValue(json_parser);
185 StructuredData::ObjectSP
186 StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) {
187 if (this->GetType() == Type::eTypeDictionary) {
188 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.');
189 std::string key = match.first.str();
190 ObjectSP value = this->GetAsDictionary()->GetValueForKey(key);
192 // Do we have additional words to descend? If not, return the
193 // value we're at right now.
194 if (match.second.empty()) {
197 return value->GetObjectForDotSeparatedPath(match.second);
203 if (this->GetType() == Type::eTypeArray) {
204 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('[');
205 if (match.second.size() == 0) {
206 return this->shared_from_this();
209 uint64_t val = strtoul(match.second.str().c_str(), NULL, 10);
211 return this->GetAsArray()->GetItemAtIndex(val);
216 return this->shared_from_this();
219 void StructuredData::Object::DumpToStdout(bool pretty_print) const {
221 Dump(stream, pretty_print);
222 printf("%s\n", stream.GetData());
225 void StructuredData::Array::Dump(Stream &s, bool pretty_print) const {
232 for (const auto &item_sp : m_items) {
243 item_sp->Dump(s, pretty_print);
253 void StructuredData::Integer::Dump(Stream &s, bool pretty_print) const {
254 s.Printf("%" PRIu64, m_value);
257 void StructuredData::Float::Dump(Stream &s, bool pretty_print) const {
258 s.Printf("%lg", m_value);
261 void StructuredData::Boolean::Dump(Stream &s, bool pretty_print) const {
263 s.PutCString("true");
265 s.PutCString("false");
268 void StructuredData::String::Dump(Stream &s, bool pretty_print) const {
270 const size_t strsize = m_value.size();
271 for (size_t i = 0; i < strsize; ++i) {
272 char ch = m_value[i];
273 if (ch == '"' || ch == '\\')
274 quoted.push_back('\\');
275 quoted.push_back(ch);
277 s.Printf("\"%s\"", quoted.c_str());
280 void StructuredData::Dictionary::Dump(Stream &s, bool pretty_print) const {
287 for (const auto &pair : m_dict) {
297 s << "\"" << pair.first.AsCString() << "\" : ";
298 pair.second->Dump(s, pretty_print);
308 void StructuredData::Null::Dump(Stream &s, bool pretty_print) const {
312 void StructuredData::Generic::Dump(Stream &s, bool pretty_print) const {
313 s << "0x" << m_object;