blob: a2c440948af1538a4173681ad1bbe8240a7e251d [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 }
Greg Clayton358cf1e2015-06-25 21:46:34 +0000301 else if (*c == '[')
302 {
303 object_sp = read_json_array (&c);
304 }
Jason Molenda705b1802014-06-13 02:37:02 +0000305 else
306 {
307 // We have bad characters here, this is likely an illegal JSON string.
308 return object_sp;
309 }
310 }
311 }
312 return object_sp;
313}
314
315StructuredData::ObjectSP
316StructuredData::Object::GetObjectForDotSeparatedPath (llvm::StringRef path)
317{
318 if (this->GetType() == Type::eTypeDictionary)
319 {
320 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.');
321 std::string key = match.first.str();
322 ObjectSP value = this->GetAsDictionary()->GetValueForKey (key.c_str());
323 if (value.get())
324 {
325 // Do we have additional words to descend? If not, return the
326 // value we're at right now.
327 if (match.second.empty())
328 {
329 return value;
330 }
331 else
332 {
333 return value->GetObjectForDotSeparatedPath (match.second);
334 }
335 }
336 return ObjectSP();
337 }
338
339 if (this->GetType() == Type::eTypeArray)
340 {
341 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('[');
342 if (match.second.size() == 0)
343 {
344 return this->shared_from_this();
345 }
346 errno = 0;
347 uint64_t val = strtoul (match.second.str().c_str(), NULL, 10);
348 if (errno == 0)
349 {
350 return this->GetAsArray()->GetItemAtIndex(val);
351 }
352 return ObjectSP();
353 }
354
355 return this->shared_from_this();
356}
357
358void
Zachary Turner0641ca12015-03-17 20:04:04 +0000359StructuredData::Object::DumpToStdout() const
360{
361 StreamString stream;
362 Dump(stream);
Greg Clayton66b82942015-05-27 03:23:26 +0000363 printf("%s\n", stream.GetString().c_str());
Zachary Turner0641ca12015-03-17 20:04:04 +0000364}
365
366void
367StructuredData::Array::Dump(Stream &s) const
Jason Molenda705b1802014-06-13 02:37:02 +0000368{
Greg Clayton66b82942015-05-27 03:23:26 +0000369 bool first = true;
370 s << "[\n";
371 s.IndentMore();
372 for (const auto &item_sp : m_items)
Jason Molenda705b1802014-06-13 02:37:02 +0000373 {
Greg Clayton66b82942015-05-27 03:23:26 +0000374 if (first)
375 first = false;
376 else
377 s << ",\n";
378
379 s.Indent();
380 item_sp->Dump(s);
Jason Molenda705b1802014-06-13 02:37:02 +0000381 }
Greg Clayton66b82942015-05-27 03:23:26 +0000382 s.IndentLess();
383 s.EOL();
384 s.Indent();
Jason Molenda705b1802014-06-13 02:37:02 +0000385 s << "]";
386}
387
388void
389StructuredData::Integer::Dump (Stream &s) const
390{
391 s.Printf ("%" PRIu64, m_value);
392}
393
394
395void
396StructuredData::Float::Dump (Stream &s) const
397{
398 s.Printf ("%lf", m_value);
399}
400
401void
402StructuredData::Boolean::Dump (Stream &s) const
403{
404 if (m_value == true)
405 s.PutCString ("true");
406 else
407 s.PutCString ("false");
408}
409
410
411void
412StructuredData::String::Dump (Stream &s) const
413{
414 std::string quoted;
415 const size_t strsize = m_value.size();
416 for (size_t i = 0; i < strsize ; ++i)
417 {
418 char ch = m_value[i];
419 if (ch == '"')
420 quoted.push_back ('\\');
421 quoted.push_back (ch);
422 }
423 s.Printf ("\"%s\"", quoted.c_str());
424}
425
426void
427StructuredData::Dictionary::Dump (Stream &s) const
428{
Greg Clayton66b82942015-05-27 03:23:26 +0000429 bool first = true;
430 s << "{\n";
431 s.IndentMore();
432 for (const auto &pair : m_dict)
Jason Molenda705b1802014-06-13 02:37:02 +0000433 {
Greg Clayton66b82942015-05-27 03:23:26 +0000434 if (first)
435 first = false;
Jason Molenda705b1802014-06-13 02:37:02 +0000436 else
Greg Clayton66b82942015-05-27 03:23:26 +0000437 s << ",\n";
438 s.Indent();
439 s << "\"" << pair.first.AsCString() << "\" : ";
440 pair.second->Dump(s);
Jason Molenda705b1802014-06-13 02:37:02 +0000441 }
Greg Clayton66b82942015-05-27 03:23:26 +0000442 s.IndentLess();
443 s.EOL();
444 s.Indent();
Jason Molenda705b1802014-06-13 02:37:02 +0000445 s << "}";
446}
447
448void
449StructuredData::Null::Dump (Stream &s) const
450{
451 s << "null";
452}
Zachary Turner0641ca12015-03-17 20:04:04 +0000453
454void
455StructuredData::Generic::Dump(Stream &s) const
456{
457 s << "0x" << m_object;
458}