blob: 9286c3a2991166348496fcdc44c0ac074acf85b5 [file] [log] [blame]
Jason Molenda705b1802014-06-13 02:37:02 +00001//===---------------------StructuredData.cpp ---------------------*- C++ -*-===//
2//
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>
13#include <stdlib.h>
14#include <inttypes.h>
15
Zachary Turner0641ca12015-03-17 20:04:04 +000016#include "lldb/Core/StreamString.h"
17
Jason Molenda705b1802014-06-13 02:37:02 +000018using namespace lldb_private;
19
20
21static StructuredData::ObjectSP read_json_object (const char **ch);
22static StructuredData::ObjectSP read_json_array (const char **ch);
23
24static StructuredData::ObjectSP
25read_json_number (const char **ch)
26{
27 StructuredData::ObjectSP object_sp;
28 while (isspace (**ch))
29 (*ch)++;
30 const char *start_of_number = *ch;
31 bool is_integer = true;
32 bool is_float = false;
33 while (isdigit(**ch) || **ch == '-' || **ch == '.' || **ch == '+' || **ch == 'e' || **ch == 'E')
34 {
35 if (isdigit(**ch) == false && **ch != '-')
36 {
37 is_integer = false;
38 is_float = true;
39 }
40 (*ch)++;
41 }
42 while (isspace (**ch))
43 (*ch)++;
44 if (**ch == ',' || **ch == ']' || **ch == '}')
45 {
46 if (is_integer)
47 {
48 errno = 0;
49 uint64_t val = strtoul (start_of_number, NULL, 10);
50 if (errno == 0)
51 {
52 object_sp.reset(new StructuredData::Integer());
53 object_sp->GetAsInteger()->SetValue (val);
54 }
55 }
56 if (is_float)
57 {
58 char *end_of_number = NULL;
59 errno = 0;
60 double val = strtod (start_of_number, &end_of_number);
61 if (errno == 0 && end_of_number != start_of_number && end_of_number != NULL)
62 {
63 object_sp.reset(new StructuredData::Float());
64 object_sp->GetAsFloat()->SetValue (val);
65 }
66 }
67 }
68 return object_sp;
69}
70
71static std::string
72read_json_string (const char **ch)
73{
74 std::string string;
75 if (**ch == '"')
76 {
77 (*ch)++;
78 while (**ch != '\0')
79 {
80 if (**ch == '"')
81 {
82 (*ch)++;
83 while (isspace (**ch))
84 (*ch)++;
85 break;
86 }
87 else if (**ch == '\\')
88 {
89 switch (**ch)
90 {
91 case '"':
92 string.push_back('"');
93 *ch += 2;
94 break;
95 case '\\':
96 string.push_back('\\');
97 *ch += 2;
98 break;
99 case '/':
100 string.push_back('/');
101 *ch += 2;
102 break;
103 case 'b':
104 string.push_back('\b');
105 *ch += 2;
106 break;
107 case 'f':
108 string.push_back('\f');
109 *ch += 2;
110 break;
111 case 'n':
112 string.push_back('\n');
113 *ch += 2;
114 break;
115 case 'r':
116 string.push_back('\r');
117 *ch += 2;
118 break;
119 case 't':
120 string.push_back('\t');
121 *ch += 2;
122 break;
123 case 'u':
124 // FIXME handle four-hex-digits
125 *ch += 10;
126 break;
127 default:
128 *ch += 1;
129 }
130 }
131 else
132 {
133 string.push_back (**ch);
134 }
135 (*ch)++;
136 }
137 }
138 return string;
139}
140
141static StructuredData::ObjectSP
142read_json_value (const char **ch)
143{
144 StructuredData::ObjectSP object_sp;
145 while (isspace (**ch))
146 (*ch)++;
147
148 if (**ch == '{')
149 {
150 object_sp = read_json_object (ch);
151 }
152 else if (**ch == '[')
153 {
154 object_sp = read_json_array (ch);
155 }
156 else if (**ch == '"')
157 {
158 std::string string = read_json_string (ch);
159 object_sp.reset(new StructuredData::String());
160 object_sp->GetAsString()->SetValue(string);
161 }
162 else
163 {
164 if (strncmp (*ch, "true", 4) == 0)
165 {
166 object_sp.reset(new StructuredData::Boolean());
167 object_sp->GetAsBoolean()->SetValue(true);
168 *ch += 4;
169 }
170 else if (strncmp (*ch, "false", 5) == 0)
171 {
172 object_sp.reset(new StructuredData::Boolean());
173 object_sp->GetAsBoolean()->SetValue(false);
174 *ch += 5;
175 }
176 else if (strncmp (*ch, "null", 4) == 0)
177 {
178 object_sp.reset(new StructuredData::Null());
179 *ch += 4;
180 }
181 else
182 {
183 object_sp = read_json_number (ch);
184 }
185 }
186 return object_sp;
187}
188
189static StructuredData::ObjectSP
190read_json_array (const char **ch)
191{
192 StructuredData::ObjectSP object_sp;
193 if (**ch == '[')
194 {
195 (*ch)++;
196 while (isspace (**ch))
197 (*ch)++;
198
199 bool first_value = true;
200 while (**ch != '\0' && (first_value || **ch == ','))
201 {
202 if (**ch == ',')
203 (*ch)++;
204 first_value = false;
205 while (isspace (**ch))
206 (*ch)++;
207 lldb_private::StructuredData::ObjectSP value_sp = read_json_value (ch);
208 if (value_sp)
209 {
210 if (object_sp.get() == NULL)
211 {
212 object_sp.reset(new StructuredData::Array());
213 }
214 object_sp->GetAsArray()->Push (value_sp);
215 }
216 while (isspace (**ch))
217 (*ch)++;
218 }
219 if (**ch == ']')
220 {
221 // FIXME should throw an error if we don't see a } to close out the JSON object
222 (*ch)++;
223 while (isspace (**ch))
224 (*ch)++;
225 }
226 }
227 return object_sp;
228}
229
230static StructuredData::ObjectSP
231read_json_object (const char **ch)
232{
233 StructuredData::ObjectSP object_sp;
234 if (**ch == '{')
235 {
236 (*ch)++;
237 while (isspace (**ch))
238 (*ch)++;
239 bool first_pair = true;
240 while (**ch != '\0' && (first_pair || **ch == ','))
241 {
242 first_pair = false;
243 if (**ch == ',')
244 (*ch)++;
245 while (isspace (**ch))
246 (*ch)++;
247 if (**ch != '"')
248 break;
249 std::string key_string = read_json_string (ch);
250 while (isspace (**ch))
251 (*ch)++;
252 if (key_string.size() > 0 && **ch == ':')
253 {
254 (*ch)++;
255 while (isspace (**ch))
256 (*ch)++;
257 lldb_private::StructuredData::ObjectSP value_sp = read_json_value (ch);
258 if (value_sp.get())
259 {
260 if (object_sp.get() == NULL)
261 {
262 object_sp.reset(new StructuredData::Dictionary());
263 }
264 object_sp->GetAsDictionary()->AddItem (key_string.c_str(), value_sp);
265 }
266 }
267 while (isspace (**ch))
268 (*ch)++;
269 }
270 if (**ch == '}')
271 {
272 // FIXME should throw an error if we don't see a } to close out the JSON object
273 (*ch)++;
274 while (isspace (**ch))
275 (*ch)++;
276 }
277 }
278 return object_sp;
279}
280
281
282StructuredData::ObjectSP
283StructuredData::ParseJSON (std::string json_text)
284{
285 StructuredData::ObjectSP object_sp;
286 const size_t json_text_size = json_text.size();
287 if (json_text_size > 0)
288 {
289 const char *start_of_json_text = json_text.c_str();
290 const char *c = json_text.c_str();
Saleem Abdulrasoole8e4ae92014-06-13 03:30:42 +0000291 while (*c != '\0' &&
292 static_cast<size_t>(c - start_of_json_text) <= json_text_size)
Jason Molenda705b1802014-06-13 02:37:02 +0000293 {
Saleem Abdulrasoole8e4ae92014-06-13 03:30:42 +0000294 while (isspace (*c) &&
295 static_cast<size_t>(c - start_of_json_text) < json_text_size)
Jason Molenda705b1802014-06-13 02:37:02 +0000296 c++;
297 if (*c == '{')
298 {
299 object_sp = read_json_object (&c);
300 }
301 else
302 {
303 // We have bad characters here, this is likely an illegal JSON string.
304 return object_sp;
305 }
306 }
307 }
308 return object_sp;
309}
310
311StructuredData::ObjectSP
312StructuredData::Object::GetObjectForDotSeparatedPath (llvm::StringRef path)
313{
314 if (this->GetType() == Type::eTypeDictionary)
315 {
316 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.');
317 std::string key = match.first.str();
318 ObjectSP value = this->GetAsDictionary()->GetValueForKey (key.c_str());
319 if (value.get())
320 {
321 // Do we have additional words to descend? If not, return the
322 // value we're at right now.
323 if (match.second.empty())
324 {
325 return value;
326 }
327 else
328 {
329 return value->GetObjectForDotSeparatedPath (match.second);
330 }
331 }
332 return ObjectSP();
333 }
334
335 if (this->GetType() == Type::eTypeArray)
336 {
337 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('[');
338 if (match.second.size() == 0)
339 {
340 return this->shared_from_this();
341 }
342 errno = 0;
343 uint64_t val = strtoul (match.second.str().c_str(), NULL, 10);
344 if (errno == 0)
345 {
346 return this->GetAsArray()->GetItemAtIndex(val);
347 }
348 return ObjectSP();
349 }
350
351 return this->shared_from_this();
352}
353
354void
Zachary Turner0641ca12015-03-17 20:04:04 +0000355StructuredData::Object::DumpToStdout() const
356{
357 StreamString stream;
358 Dump(stream);
Greg Clayton66b82942015-05-27 03:23:26 +0000359 printf("%s\n", stream.GetString().c_str());
Zachary Turner0641ca12015-03-17 20:04:04 +0000360}
361
362void
363StructuredData::Array::Dump(Stream &s) const
Jason Molenda705b1802014-06-13 02:37:02 +0000364{
Greg Clayton66b82942015-05-27 03:23:26 +0000365 bool first = true;
366 s << "[\n";
367 s.IndentMore();
368 for (const auto &item_sp : m_items)
Jason Molenda705b1802014-06-13 02:37:02 +0000369 {
Greg Clayton66b82942015-05-27 03:23:26 +0000370 if (first)
371 first = false;
372 else
373 s << ",\n";
374
375 s.Indent();
376 item_sp->Dump(s);
Jason Molenda705b1802014-06-13 02:37:02 +0000377 }
Greg Clayton66b82942015-05-27 03:23:26 +0000378 s.IndentLess();
379 s.EOL();
380 s.Indent();
Jason Molenda705b1802014-06-13 02:37:02 +0000381 s << "]";
382}
383
384void
385StructuredData::Integer::Dump (Stream &s) const
386{
387 s.Printf ("%" PRIu64, m_value);
388}
389
390
391void
392StructuredData::Float::Dump (Stream &s) const
393{
394 s.Printf ("%lf", m_value);
395}
396
397void
398StructuredData::Boolean::Dump (Stream &s) const
399{
400 if (m_value == true)
401 s.PutCString ("true");
402 else
403 s.PutCString ("false");
404}
405
406
407void
408StructuredData::String::Dump (Stream &s) const
409{
410 std::string quoted;
411 const size_t strsize = m_value.size();
412 for (size_t i = 0; i < strsize ; ++i)
413 {
414 char ch = m_value[i];
415 if (ch == '"')
416 quoted.push_back ('\\');
417 quoted.push_back (ch);
418 }
419 s.Printf ("\"%s\"", quoted.c_str());
420}
421
422void
423StructuredData::Dictionary::Dump (Stream &s) const
424{
Greg Clayton66b82942015-05-27 03:23:26 +0000425 bool first = true;
426 s << "{\n";
427 s.IndentMore();
428 for (const auto &pair : m_dict)
Jason Molenda705b1802014-06-13 02:37:02 +0000429 {
Greg Clayton66b82942015-05-27 03:23:26 +0000430 if (first)
431 first = false;
Jason Molenda705b1802014-06-13 02:37:02 +0000432 else
Greg Clayton66b82942015-05-27 03:23:26 +0000433 s << ",\n";
434 s.Indent();
435 s << "\"" << pair.first.AsCString() << "\" : ";
436 pair.second->Dump(s);
Jason Molenda705b1802014-06-13 02:37:02 +0000437 }
Greg Clayton66b82942015-05-27 03:23:26 +0000438 s.IndentLess();
439 s.EOL();
440 s.Indent();
Jason Molenda705b1802014-06-13 02:37:02 +0000441 s << "}";
442}
443
444void
445StructuredData::Null::Dump (Stream &s) const
446{
447 s << "null";
448}
Zachary Turner0641ca12015-03-17 20:04:04 +0000449
450void
451StructuredData::Generic::Dump(Stream &s) const
452{
453 s << "0x" << m_object;
454}