blob: eeee4d4d63b918717bc1146bcf2ec84383cc4d95 [file] [log] [blame]
Zachary Turnerc1564272016-11-16 21:15:24 +00001//===---------------------StructuredData.cpp ---------------------*- C++-*-===//
Jason Molenda705b1802014-06-13 02:37:02 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "lldb/Core/StructuredData.h"
11
12#include <errno.h>
Jason Molenda705b1802014-06-13 02:37:02 +000013#include <inttypes.h>
Kate Stoneb9c1b512016-09-06 20:57:50 +000014#include <stdlib.h>
Jason Molenda705b1802014-06-13 02:37:02 +000015
Jim Inghame14dc262016-09-12 23:10:56 +000016#include "lldb/Host/File.h"
Greg Clayton98424c42015-07-06 23:40:40 +000017#include "lldb/Host/StringConvert.h"
Zachary Turner666cc0b2017-03-04 01:30:05 +000018#include "lldb/Utility/DataBuffer.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000019#include "lldb/Utility/Error.h"
Zachary Turner5713a052017-03-22 18:40:07 +000020#include "lldb/Utility/FileSpec.h"
Greg Clayton98424c42015-07-06 23:40:40 +000021#include "lldb/Utility/JSON.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000022#include "lldb/Utility/StreamString.h"
Zachary Turner0641ca12015-03-17 20:04:04 +000023
Jason Molenda705b1802014-06-13 02:37:02 +000024using namespace lldb_private;
25
Greg Clayton98424c42015-07-06 23:40:40 +000026//----------------------------------------------------------------------
27// Functions that use a JSONParser to parse JSON into StructuredData
28//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000029static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser);
30static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser);
31static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser);
Jason Molenda705b1802014-06-13 02:37:02 +000032
Jim Ingham01f16662016-09-14 19:07:35 +000033StructuredData::ObjectSP
34StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Error &error) {
Jim Inghame14dc262016-09-12 23:10:56 +000035 StructuredData::ObjectSP return_sp;
36 if (!input_spec.Exists()) {
37 error.SetErrorStringWithFormat("input file %s does not exist.",
38 input_spec.GetPath().c_str());
39 return return_sp;
40 }
41
42 File input_file(nullptr, File::OpenOptions::eOpenOptionRead,
43 lldb::eFilePermissionsUserRead);
44 std::string input_path = input_spec.GetPath();
45 error =
46 input_file.Open(input_path.c_str(), File::OpenOptions::eOpenOptionRead,
47 lldb::eFilePermissionsUserRead);
48
49 if (!error.Success()) {
50 error.SetErrorStringWithFormat("could not open input file: %s - %s.",
51 input_spec.GetPath().c_str(),
52 error.AsCString());
53 return return_sp;
54 }
55
56 lldb::DataBufferSP input_data;
Tamas Berghammerf8199a72016-09-13 09:27:21 +000057 size_t num_bytes = std::numeric_limits<size_t>::max();
Jim Inghame14dc262016-09-12 23:10:56 +000058 off_t offset = 0;
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(),
63 error.AsCString());
64 return return_sp;
65 }
66 JSONParser json_parser((char *)input_data->GetBytes());
67 return_sp = ParseJSONValue(json_parser);
68 return return_sp;
69}
70
Kate Stoneb9c1b512016-09-06 20:57:50 +000071static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser) {
72 // The "JSONParser::Token::ObjectStart" token should have already been
73 // consumed
74 // by the time this function is called
75 std::unique_ptr<StructuredData::Dictionary> dict_up(
76 new StructuredData::Dictionary());
Jason Molenda705b1802014-06-13 02:37:02 +000077
Kate Stoneb9c1b512016-09-06 20:57:50 +000078 std::string value;
79 std::string key;
80 while (1) {
81 JSONParser::Token token = json_parser.GetToken(value);
Jason Molenda705b1802014-06-13 02:37:02 +000082
Kate Stoneb9c1b512016-09-06 20:57:50 +000083 if (token == JSONParser::Token::String) {
84 key.swap(value);
85 token = json_parser.GetToken(value);
86 if (token == JSONParser::Token::Colon) {
Greg Clayton98424c42015-07-06 23:40:40 +000087 StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
88 if (value_sp)
Kate Stoneb9c1b512016-09-06 20:57:50 +000089 dict_up->AddItem(key, value_sp);
Greg Clayton98424c42015-07-06 23:40:40 +000090 else
Kate Stoneb9c1b512016-09-06 20:57:50 +000091 break;
92 }
93 } else if (token == JSONParser::Token::ObjectEnd) {
94 return StructuredData::ObjectSP(dict_up.release());
95 } else if (token == JSONParser::Token::Comma) {
96 continue;
97 } else {
98 break;
Jason Molenda705b1802014-06-13 02:37:02 +000099 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000100 }
101 return StructuredData::ObjectSP();
Jason Molenda705b1802014-06-13 02:37:02 +0000102}
103
Kate Stoneb9c1b512016-09-06 20:57:50 +0000104static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser) {
105 // The "JSONParser::Token::ObjectStart" token should have already been
106 // consumed
107 // by the time this function is called
108 std::unique_ptr<StructuredData::Array> array_up(new StructuredData::Array());
Jason Molenda705b1802014-06-13 02:37:02 +0000109
Kate Stoneb9c1b512016-09-06 20:57:50 +0000110 std::string value;
111 std::string key;
112 while (1) {
113 StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
114 if (value_sp)
115 array_up->AddItem(value_sp);
Jason Molenda705b1802014-06-13 02:37:02 +0000116 else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000117 break;
Jason Molenda705b1802014-06-13 02:37:02 +0000118
Kate Stoneb9c1b512016-09-06 20:57:50 +0000119 JSONParser::Token token = json_parser.GetToken(value);
120 if (token == JSONParser::Token::Comma) {
121 continue;
122 } else if (token == JSONParser::Token::ArrayEnd) {
123 return StructuredData::ObjectSP(array_up.release());
124 } else {
125 break;
Jason Molenda705b1802014-06-13 02:37:02 +0000126 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000127 }
128 return StructuredData::ObjectSP();
Jason Molenda705b1802014-06-13 02:37:02 +0000129}
130
Kate Stoneb9c1b512016-09-06 20:57:50 +0000131static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser) {
132 std::string value;
133 const JSONParser::Token token = json_parser.GetToken(value);
134 switch (token) {
135 case JSONParser::Token::ObjectStart:
136 return ParseJSONObject(json_parser);
137
138 case JSONParser::Token::ArrayStart:
139 return ParseJSONArray(json_parser);
140
141 case JSONParser::Token::Integer: {
142 bool success = false;
143 uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success);
144 if (success)
145 return StructuredData::ObjectSP(new StructuredData::Integer(uval));
146 } break;
147
148 case JSONParser::Token::Float: {
149 bool success = false;
150 double val = StringConvert::ToDouble(value.c_str(), 0.0, &success);
151 if (success)
152 return StructuredData::ObjectSP(new StructuredData::Float(val));
153 } break;
154
155 case JSONParser::Token::String:
156 return StructuredData::ObjectSP(new StructuredData::String(value));
157
158 case JSONParser::Token::True:
159 case JSONParser::Token::False:
160 return StructuredData::ObjectSP(
161 new StructuredData::Boolean(token == JSONParser::Token::True));
162
163 case JSONParser::Token::Null:
164 return StructuredData::ObjectSP(new StructuredData::Null());
165
166 default:
167 break;
168 }
169 return StructuredData::ObjectSP();
170}
171
172StructuredData::ObjectSP StructuredData::ParseJSON(std::string json_text) {
173 JSONParser json_parser(json_text.c_str());
174 StructuredData::ObjectSP object_sp = ParseJSONValue(json_parser);
175 return object_sp;
176}
177
178StructuredData::ObjectSP
179StructuredData::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();
Malcolm Parsons771ef6d2016-11-02 20:34:10 +0000183 ObjectSP value = this->GetAsDictionary()->GetValueForKey(key);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000184 if (value.get()) {
185 // Do we have additional words to descend? If not, return the
186 // value we're at right now.
187 if (match.second.empty()) {
188 return value;
189 } else {
190 return value->GetObjectForDotSeparatedPath(match.second);
191 }
192 }
193 return ObjectSP();
194 }
195
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();
200 }
201 errno = 0;
202 uint64_t val = strtoul(match.second.str().c_str(), NULL, 10);
203 if (errno == 0) {
204 return this->GetAsArray()->GetItemAtIndex(val);
205 }
206 return ObjectSP();
207 }
208
209 return this->shared_from_this();
210}
211
212void StructuredData::Object::DumpToStdout(bool pretty_print) const {
213 StreamString stream;
214 Dump(stream, pretty_print);
Zachary Turnerc1564272016-11-16 21:15:24 +0000215 printf("%s\n", stream.GetData());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000216}
217
218void StructuredData::Array::Dump(Stream &s, bool pretty_print) const {
219 bool first = true;
220 s << "[";
221 if (pretty_print) {
222 s << "\n";
223 s.IndentMore();
224 }
225 for (const auto &item_sp : m_items) {
226 if (first) {
227 first = false;
228 } else {
229 s << ",";
230 if (pretty_print)
Jason Molendae62dda22016-07-21 22:50:01 +0000231 s << "\n";
Jason Molendad9c9da52016-07-20 03:49:02 +0000232 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000233
234 if (pretty_print)
235 s.Indent();
236 item_sp->Dump(s, pretty_print);
237 }
238 if (pretty_print) {
239 s.IndentLess();
240 s.EOL();
241 s.Indent();
242 }
243 s << "]";
244}
245
246void StructuredData::Integer::Dump(Stream &s, bool pretty_print) const {
247 s.Printf("%" PRIu64, m_value);
248}
249
250void StructuredData::Float::Dump(Stream &s, bool pretty_print) const {
251 s.Printf("%lg", m_value);
252}
253
254void StructuredData::Boolean::Dump(Stream &s, bool pretty_print) const {
255 if (m_value == true)
256 s.PutCString("true");
257 else
258 s.PutCString("false");
259}
260
261void StructuredData::String::Dump(Stream &s, bool pretty_print) const {
262 std::string quoted;
263 const size_t strsize = m_value.size();
264 for (size_t i = 0; i < strsize; ++i) {
265 char ch = m_value[i];
Pavel Labath2a668842016-09-22 15:26:43 +0000266 if (ch == '"' || ch == '\\')
Kate Stoneb9c1b512016-09-06 20:57:50 +0000267 quoted.push_back('\\');
268 quoted.push_back(ch);
269 }
270 s.Printf("\"%s\"", quoted.c_str());
271}
272
273void StructuredData::Dictionary::Dump(Stream &s, bool pretty_print) const {
274 bool first = true;
275 s << "{";
276 if (pretty_print) {
277 s << "\n";
278 s.IndentMore();
279 }
280 for (const auto &pair : m_dict) {
281 if (first)
282 first = false;
283 else {
284 s << ",";
285 if (pretty_print)
286 s << "\n";
Jason Molenda705b1802014-06-13 02:37:02 +0000287 }
Jason Molendad9c9da52016-07-20 03:49:02 +0000288 if (pretty_print)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000289 s.Indent();
290 s << "\"" << pair.first.AsCString() << "\" : ";
291 pair.second->Dump(s, pretty_print);
292 }
293 if (pretty_print) {
294 s.IndentLess();
295 s.EOL();
296 s.Indent();
297 }
298 s << "}";
Jason Molenda705b1802014-06-13 02:37:02 +0000299}
300
Kate Stoneb9c1b512016-09-06 20:57:50 +0000301void StructuredData::Null::Dump(Stream &s, bool pretty_print) const {
302 s << "null";
Jason Molenda705b1802014-06-13 02:37:02 +0000303}
Zachary Turner0641ca12015-03-17 20:04:04 +0000304
Kate Stoneb9c1b512016-09-06 20:57:50 +0000305void StructuredData::Generic::Dump(Stream &s, bool pretty_print) const {
306 s << "0x" << m_object;
Zachary Turner0641ca12015-03-17 20:04:04 +0000307}