blob: 46be7828f626db53c738417dc021fe0a0ac63bc1 [file] [log] [blame]
Kate Stoneb9c1b512016-09-06 20:57:50 +00001//===---------------------StructuredData.cpp ---------------------*- C++
2//-*-===//
Jason Molenda705b1802014-06-13 02:37:02 +00003//
4// The LLVM Compiler Infrastructure
5//
6// This file is distributed under the University of Illinois Open Source
7// License. See LICENSE.TXT for details.
8//
9//===----------------------------------------------------------------------===//
10
11#include "lldb/Core/StructuredData.h"
12
13#include <errno.h>
Jason Molenda705b1802014-06-13 02:37:02 +000014#include <inttypes.h>
Kate Stoneb9c1b512016-09-06 20:57:50 +000015#include <stdlib.h>
Jason Molenda705b1802014-06-13 02:37:02 +000016
Jim Inghame14dc262016-09-12 23:10:56 +000017#include "lldb/Core/DataBuffer.h"
18#include "lldb/Core/Error.h"
Zachary Turner0641ca12015-03-17 20:04:04 +000019#include "lldb/Core/StreamString.h"
Jim Inghame14dc262016-09-12 23:10:56 +000020#include "lldb/Host/File.h"
21#include "lldb/Host/FileSpec.h"
Greg Clayton98424c42015-07-06 23:40:40 +000022#include "lldb/Host/StringConvert.h"
23#include "lldb/Utility/JSON.h"
Zachary Turner0641ca12015-03-17 20:04:04 +000024
Jason Molenda705b1802014-06-13 02:37:02 +000025using namespace lldb_private;
26
Greg Clayton98424c42015-07-06 23:40:40 +000027//----------------------------------------------------------------------
28// Functions that use a JSONParser to parse JSON into StructuredData
29//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000030static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser);
31static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser);
32static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser);
Jason Molenda705b1802014-06-13 02:37:02 +000033
Jim Ingham01f16662016-09-14 19:07:35 +000034StructuredData::ObjectSP
35StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Error &error) {
Jim Inghame14dc262016-09-12 23:10:56 +000036 StructuredData::ObjectSP return_sp;
37 if (!input_spec.Exists()) {
38 error.SetErrorStringWithFormat("input file %s does not exist.",
39 input_spec.GetPath().c_str());
40 return return_sp;
41 }
42
43 File input_file(nullptr, File::OpenOptions::eOpenOptionRead,
44 lldb::eFilePermissionsUserRead);
45 std::string input_path = input_spec.GetPath();
46 error =
47 input_file.Open(input_path.c_str(), File::OpenOptions::eOpenOptionRead,
48 lldb::eFilePermissionsUserRead);
49
50 if (!error.Success()) {
51 error.SetErrorStringWithFormat("could not open input file: %s - %s.",
52 input_spec.GetPath().c_str(),
53 error.AsCString());
54 return return_sp;
55 }
56
57 lldb::DataBufferSP input_data;
Tamas Berghammerf8199a72016-09-13 09:27:21 +000058 size_t num_bytes = std::numeric_limits<size_t>::max();
Jim Inghame14dc262016-09-12 23:10:56 +000059 off_t offset = 0;
60 error = input_file.Read(num_bytes, offset, true, input_data);
61 if (!error.Success()) {
62 error.SetErrorStringWithFormat("could not read input file: %s - %s.",
63 input_spec.GetPath().c_str(),
64 error.AsCString());
65 return return_sp;
66 }
67 JSONParser json_parser((char *)input_data->GetBytes());
68 return_sp = ParseJSONValue(json_parser);
69 return return_sp;
70}
71
Kate Stoneb9c1b512016-09-06 20:57:50 +000072static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser) {
73 // The "JSONParser::Token::ObjectStart" token should have already been
74 // consumed
75 // by the time this function is called
76 std::unique_ptr<StructuredData::Dictionary> dict_up(
77 new StructuredData::Dictionary());
Jason Molenda705b1802014-06-13 02:37:02 +000078
Kate Stoneb9c1b512016-09-06 20:57:50 +000079 std::string value;
80 std::string key;
81 while (1) {
82 JSONParser::Token token = json_parser.GetToken(value);
Jason Molenda705b1802014-06-13 02:37:02 +000083
Kate Stoneb9c1b512016-09-06 20:57:50 +000084 if (token == JSONParser::Token::String) {
85 key.swap(value);
86 token = json_parser.GetToken(value);
87 if (token == JSONParser::Token::Colon) {
Greg Clayton98424c42015-07-06 23:40:40 +000088 StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
89 if (value_sp)
Kate Stoneb9c1b512016-09-06 20:57:50 +000090 dict_up->AddItem(key, value_sp);
Greg Clayton98424c42015-07-06 23:40:40 +000091 else
Kate Stoneb9c1b512016-09-06 20:57:50 +000092 break;
93 }
94 } else if (token == JSONParser::Token::ObjectEnd) {
95 return StructuredData::ObjectSP(dict_up.release());
96 } else if (token == JSONParser::Token::Comma) {
97 continue;
98 } else {
99 break;
Jason Molenda705b1802014-06-13 02:37:02 +0000100 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000101 }
102 return StructuredData::ObjectSP();
Jason Molenda705b1802014-06-13 02:37:02 +0000103}
104
Kate Stoneb9c1b512016-09-06 20:57:50 +0000105static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser) {
106 // The "JSONParser::Token::ObjectStart" token should have already been
107 // consumed
108 // by the time this function is called
109 std::unique_ptr<StructuredData::Array> array_up(new StructuredData::Array());
Jason Molenda705b1802014-06-13 02:37:02 +0000110
Kate Stoneb9c1b512016-09-06 20:57:50 +0000111 std::string value;
112 std::string key;
113 while (1) {
114 StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
115 if (value_sp)
116 array_up->AddItem(value_sp);
Jason Molenda705b1802014-06-13 02:37:02 +0000117 else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000118 break;
Jason Molenda705b1802014-06-13 02:37:02 +0000119
Kate Stoneb9c1b512016-09-06 20:57:50 +0000120 JSONParser::Token token = json_parser.GetToken(value);
121 if (token == JSONParser::Token::Comma) {
122 continue;
123 } else if (token == JSONParser::Token::ArrayEnd) {
124 return StructuredData::ObjectSP(array_up.release());
125 } else {
126 break;
Jason Molenda705b1802014-06-13 02:37:02 +0000127 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000128 }
129 return StructuredData::ObjectSP();
Jason Molenda705b1802014-06-13 02:37:02 +0000130}
131
Kate Stoneb9c1b512016-09-06 20:57:50 +0000132static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser) {
133 std::string value;
134 const JSONParser::Token token = json_parser.GetToken(value);
135 switch (token) {
136 case JSONParser::Token::ObjectStart:
137 return ParseJSONObject(json_parser);
138
139 case JSONParser::Token::ArrayStart:
140 return ParseJSONArray(json_parser);
141
142 case JSONParser::Token::Integer: {
143 bool success = false;
144 uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success);
145 if (success)
146 return StructuredData::ObjectSP(new StructuredData::Integer(uval));
147 } break;
148
149 case JSONParser::Token::Float: {
150 bool success = false;
151 double val = StringConvert::ToDouble(value.c_str(), 0.0, &success);
152 if (success)
153 return StructuredData::ObjectSP(new StructuredData::Float(val));
154 } break;
155
156 case JSONParser::Token::String:
157 return StructuredData::ObjectSP(new StructuredData::String(value));
158
159 case JSONParser::Token::True:
160 case JSONParser::Token::False:
161 return StructuredData::ObjectSP(
162 new StructuredData::Boolean(token == JSONParser::Token::True));
163
164 case JSONParser::Token::Null:
165 return StructuredData::ObjectSP(new StructuredData::Null());
166
167 default:
168 break;
169 }
170 return StructuredData::ObjectSP();
171}
172
173StructuredData::ObjectSP StructuredData::ParseJSON(std::string json_text) {
174 JSONParser json_parser(json_text.c_str());
175 StructuredData::ObjectSP object_sp = ParseJSONValue(json_parser);
176 return object_sp;
177}
178
179StructuredData::ObjectSP
180StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) {
181 if (this->GetType() == Type::eTypeDictionary) {
182 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.');
183 std::string key = match.first.str();
184 ObjectSP value = this->GetAsDictionary()->GetValueForKey(key.c_str());
185 if (value.get()) {
186 // Do we have additional words to descend? If not, return the
187 // value we're at right now.
188 if (match.second.empty()) {
189 return value;
190 } else {
191 return value->GetObjectForDotSeparatedPath(match.second);
192 }
193 }
194 return ObjectSP();
195 }
196
197 if (this->GetType() == Type::eTypeArray) {
198 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('[');
199 if (match.second.size() == 0) {
200 return this->shared_from_this();
201 }
202 errno = 0;
203 uint64_t val = strtoul(match.second.str().c_str(), NULL, 10);
204 if (errno == 0) {
205 return this->GetAsArray()->GetItemAtIndex(val);
206 }
207 return ObjectSP();
208 }
209
210 return this->shared_from_this();
211}
212
213void StructuredData::Object::DumpToStdout(bool pretty_print) const {
214 StreamString stream;
215 Dump(stream, pretty_print);
216 printf("%s\n", stream.GetString().c_str());
217}
218
219void StructuredData::Array::Dump(Stream &s, bool pretty_print) const {
220 bool first = true;
221 s << "[";
222 if (pretty_print) {
223 s << "\n";
224 s.IndentMore();
225 }
226 for (const auto &item_sp : m_items) {
227 if (first) {
228 first = false;
229 } else {
230 s << ",";
231 if (pretty_print)
Jason Molendae62dda22016-07-21 22:50:01 +0000232 s << "\n";
Jason Molendad9c9da52016-07-20 03:49:02 +0000233 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000234
235 if (pretty_print)
236 s.Indent();
237 item_sp->Dump(s, pretty_print);
238 }
239 if (pretty_print) {
240 s.IndentLess();
241 s.EOL();
242 s.Indent();
243 }
244 s << "]";
245}
246
247void StructuredData::Integer::Dump(Stream &s, bool pretty_print) const {
248 s.Printf("%" PRIu64, m_value);
249}
250
251void StructuredData::Float::Dump(Stream &s, bool pretty_print) const {
252 s.Printf("%lg", m_value);
253}
254
255void StructuredData::Boolean::Dump(Stream &s, bool pretty_print) const {
256 if (m_value == true)
257 s.PutCString("true");
258 else
259 s.PutCString("false");
260}
261
262void StructuredData::String::Dump(Stream &s, bool pretty_print) const {
263 std::string quoted;
264 const size_t strsize = m_value.size();
265 for (size_t i = 0; i < strsize; ++i) {
266 char ch = m_value[i];
Pavel Labath2a668842016-09-22 15:26:43 +0000267 if (ch == '"' || ch == '\\')
Kate Stoneb9c1b512016-09-06 20:57:50 +0000268 quoted.push_back('\\');
269 quoted.push_back(ch);
270 }
271 s.Printf("\"%s\"", quoted.c_str());
272}
273
274void StructuredData::Dictionary::Dump(Stream &s, bool pretty_print) const {
275 bool first = true;
276 s << "{";
277 if (pretty_print) {
278 s << "\n";
279 s.IndentMore();
280 }
281 for (const auto &pair : m_dict) {
282 if (first)
283 first = false;
284 else {
285 s << ",";
286 if (pretty_print)
287 s << "\n";
Jason Molenda705b1802014-06-13 02:37:02 +0000288 }
Jason Molendad9c9da52016-07-20 03:49:02 +0000289 if (pretty_print)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000290 s.Indent();
291 s << "\"" << pair.first.AsCString() << "\" : ";
292 pair.second->Dump(s, pretty_print);
293 }
294 if (pretty_print) {
295 s.IndentLess();
296 s.EOL();
297 s.Indent();
298 }
299 s << "}";
Jason Molenda705b1802014-06-13 02:37:02 +0000300}
301
Kate Stoneb9c1b512016-09-06 20:57:50 +0000302void StructuredData::Null::Dump(Stream &s, bool pretty_print) const {
303 s << "null";
Jason Molenda705b1802014-06-13 02:37:02 +0000304}
Zachary Turner0641ca12015-03-17 20:04:04 +0000305
Kate Stoneb9c1b512016-09-06 20:57:50 +0000306void StructuredData::Generic::Dump(Stream &s, bool pretty_print) const {
307 s << "0x" << m_object;
Zachary Turner0641ca12015-03-17 20:04:04 +0000308}