1 //===-- StructuredData.h ----------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLDB_UTILITY_STRUCTUREDDATA_H
10 #define LLDB_UTILITY_STRUCTUREDDATA_H
11 
12 #include "llvm/ADT/StringRef.h"
13 #include "llvm/Support/JSON.h"
14 
15 #include "lldb/Utility/ConstString.h"
16 #include "lldb/Utility/FileSpec.h"
17 #include "lldb/Utility/Stream.h"
18 #include "lldb/lldb-enumerations.h"
19 
20 #include <cassert>
21 #include <cstddef>
22 #include <cstdint>
23 #include <functional>
24 #include <map>
25 #include <memory>
26 #include <string>
27 #include <type_traits>
28 #include <utility>
29 #include <vector>
30 
31 namespace lldb_private {
32 class Status;
33 }
34 
35 namespace lldb_private {
36 
37 /// \class StructuredData StructuredData.h "lldb/Utility/StructuredData.h"
38 /// A class which can hold structured data
39 ///
40 /// The StructuredData class is designed to hold the data from a JSON or plist
41 /// style file -- a serialized data structure with dictionaries (maps,
42 /// hashes), arrays, and concrete values like integers, floating point
43 /// numbers, strings, booleans.
44 ///
45 /// StructuredData does not presuppose any knowledge of the schema for the
46 /// data it is holding; it can parse JSON data, for instance, and other parts
47 /// of lldb can iterate through the parsed data set to find keys and values
48 /// that may be present.
49 
50 class StructuredData {
51 public:
52   class Object;
53   class Array;
54   class Integer;
55   class Float;
56   class Boolean;
57   class String;
58   class Dictionary;
59   class Generic;
60 
61   typedef std::shared_ptr<Object> ObjectSP;
62   typedef std::shared_ptr<Array> ArraySP;
63   typedef std::shared_ptr<Integer> IntegerSP;
64   typedef std::shared_ptr<Float> FloatSP;
65   typedef std::shared_ptr<Boolean> BooleanSP;
66   typedef std::shared_ptr<String> StringSP;
67   typedef std::shared_ptr<Dictionary> DictionarySP;
68   typedef std::shared_ptr<Generic> GenericSP;
69 
70   class Object : public std::enable_shared_from_this<Object> {
71   public:
72     Object(lldb::StructuredDataType t = lldb::eStructuredDataTypeInvalid)
73         : m_type(t) {}
74 
75     virtual ~Object() = default;
76 
77     virtual bool IsValid() const { return true; }
78 
79     virtual void Clear() { m_type = lldb::eStructuredDataTypeInvalid; }
80 
81     lldb::StructuredDataType GetType() const { return m_type; }
82 
83     void SetType(lldb::StructuredDataType t) { m_type = t; }
84 
85     Array *GetAsArray() {
86       return ((m_type == lldb::eStructuredDataTypeArray)
87                   ? static_cast<Array *>(this)
88                   : nullptr);
89     }
90 
91     Dictionary *GetAsDictionary() {
92       return ((m_type == lldb::eStructuredDataTypeDictionary)
93                   ? static_cast<Dictionary *>(this)
94                   : nullptr);
95     }
96 
97     Integer *GetAsInteger() {
98       return ((m_type == lldb::eStructuredDataTypeInteger)
99                   ? static_cast<Integer *>(this)
100                   : nullptr);
101     }
102 
103     uint64_t GetIntegerValue(uint64_t fail_value = 0) {
104       Integer *integer = GetAsInteger();
105       return ((integer != nullptr) ? integer->GetValue() : fail_value);
106     }
107 
108     Float *GetAsFloat() {
109       return ((m_type == lldb::eStructuredDataTypeFloat)
110                   ? static_cast<Float *>(this)
111                   : nullptr);
112     }
113 
114     double GetFloatValue(double fail_value = 0.0) {
115       Float *f = GetAsFloat();
116       return ((f != nullptr) ? f->GetValue() : fail_value);
117     }
118 
119     Boolean *GetAsBoolean() {
120       return ((m_type == lldb::eStructuredDataTypeBoolean)
121                   ? static_cast<Boolean *>(this)
122                   : nullptr);
123     }
124 
125     bool GetBooleanValue(bool fail_value = false) {
126       Boolean *b = GetAsBoolean();
127       return ((b != nullptr) ? b->GetValue() : fail_value);
128     }
129 
130     String *GetAsString() {
131       return ((m_type == lldb::eStructuredDataTypeString)
132                   ? static_cast<String *>(this)
133                   : nullptr);
134     }
135 
136     llvm::StringRef GetStringValue(const char *fail_value = nullptr) {
137       String *s = GetAsString();
138       if (s)
139         return s->GetValue();
140 
141       return fail_value;
142     }
143 
144     Generic *GetAsGeneric() {
145       return ((m_type == lldb::eStructuredDataTypeGeneric)
146                   ? static_cast<Generic *>(this)
147                   : nullptr);
148     }
149 
150     ObjectSP GetObjectForDotSeparatedPath(llvm::StringRef path);
151 
152     void DumpToStdout(bool pretty_print = true) const;
153 
154     virtual void Serialize(llvm::json::OStream &s) const = 0;
155 
156     void Dump(lldb_private::Stream &s, bool pretty_print = true) const {
157       llvm::json::OStream jso(s.AsRawOstream(), pretty_print ? 2 : 0);
158       Serialize(jso);
159     }
160 
161   private:
162     lldb::StructuredDataType m_type;
163   };
164 
165   class Array : public Object {
166   public:
167     Array() : Object(lldb::eStructuredDataTypeArray) {}
168 
169     ~Array() override = default;
170 
171     bool
172     ForEach(std::function<bool(Object *object)> const &foreach_callback) const {
173       for (const auto &object_sp : m_items) {
174         if (!foreach_callback(object_sp.get()))
175           return false;
176       }
177       return true;
178     }
179 
180     size_t GetSize() const { return m_items.size(); }
181 
182     ObjectSP operator[](size_t idx) {
183       if (idx < m_items.size())
184         return m_items[idx];
185       return ObjectSP();
186     }
187 
188     ObjectSP GetItemAtIndex(size_t idx) const {
189       assert(idx < GetSize());
190       if (idx < m_items.size())
191         return m_items[idx];
192       return ObjectSP();
193     }
194 
195     template <class IntType>
196     bool GetItemAtIndexAsInteger(size_t idx, IntType &result) const {
197       ObjectSP value_sp = GetItemAtIndex(idx);
198       if (value_sp.get()) {
199         if (auto int_value = value_sp->GetAsInteger()) {
200           result = static_cast<IntType>(int_value->GetValue());
201           return true;
202         }
203       }
204       return false;
205     }
206 
207     template <class IntType>
208     bool GetItemAtIndexAsInteger(size_t idx, IntType &result,
209                                  IntType default_val) const {
210       bool success = GetItemAtIndexAsInteger(idx, result);
211       if (!success)
212         result = default_val;
213       return success;
214     }
215 
216     bool GetItemAtIndexAsString(size_t idx, llvm::StringRef &result) const {
217       ObjectSP value_sp = GetItemAtIndex(idx);
218       if (value_sp.get()) {
219         if (auto string_value = value_sp->GetAsString()) {
220           result = string_value->GetValue();
221           return true;
222         }
223       }
224       return false;
225     }
226 
227     bool GetItemAtIndexAsString(size_t idx, llvm::StringRef &result,
228                                 llvm::StringRef default_val) const {
229       bool success = GetItemAtIndexAsString(idx, result);
230       if (!success)
231         result = default_val;
232       return success;
233     }
234 
235     bool GetItemAtIndexAsString(size_t idx, ConstString &result) const {
236       ObjectSP value_sp = GetItemAtIndex(idx);
237       if (value_sp.get()) {
238         if (auto string_value = value_sp->GetAsString()) {
239           result = ConstString(string_value->GetValue());
240           return true;
241         }
242       }
243       return false;
244     }
245 
246     bool GetItemAtIndexAsString(size_t idx, ConstString &result,
247                                 const char *default_val) const {
248       bool success = GetItemAtIndexAsString(idx, result);
249       if (!success)
250         result.SetCString(default_val);
251       return success;
252     }
253 
254     bool GetItemAtIndexAsDictionary(size_t idx, Dictionary *&result) const {
255       result = nullptr;
256       ObjectSP value_sp = GetItemAtIndex(idx);
257       if (value_sp.get()) {
258         result = value_sp->GetAsDictionary();
259         return (result != nullptr);
260       }
261       return false;
262     }
263 
264     bool GetItemAtIndexAsArray(size_t idx, Array *&result) const {
265       result = nullptr;
266       ObjectSP value_sp = GetItemAtIndex(idx);
267       if (value_sp.get()) {
268         result = value_sp->GetAsArray();
269         return (result != nullptr);
270       }
271       return false;
272     }
273 
274     void Push(const ObjectSP &item) { m_items.push_back(item); }
275 
276     void AddItem(const ObjectSP &item) { m_items.push_back(item); }
277 
278     void Serialize(llvm::json::OStream &s) const override;
279 
280   protected:
281     typedef std::vector<ObjectSP> collection;
282     collection m_items;
283   };
284 
285   class Integer : public Object {
286   public:
287     Integer(uint64_t i = 0)
288         : Object(lldb::eStructuredDataTypeInteger), m_value(i) {}
289 
290     ~Integer() override = default;
291 
292     void SetValue(uint64_t value) { m_value = value; }
293 
294     uint64_t GetValue() { return m_value; }
295 
296     void Serialize(llvm::json::OStream &s) const override;
297 
298   protected:
299     uint64_t m_value;
300   };
301 
302   class Float : public Object {
303   public:
304     Float(double d = 0.0)
305         : Object(lldb::eStructuredDataTypeFloat), m_value(d) {}
306 
307     ~Float() override = default;
308 
309     void SetValue(double value) { m_value = value; }
310 
311     double GetValue() { return m_value; }
312 
313     void Serialize(llvm::json::OStream &s) const override;
314 
315   protected:
316     double m_value;
317   };
318 
319   class Boolean : public Object {
320   public:
321     Boolean(bool b = false)
322         : Object(lldb::eStructuredDataTypeBoolean), m_value(b) {}
323 
324     ~Boolean() override = default;
325 
326     void SetValue(bool value) { m_value = value; }
327 
328     bool GetValue() { return m_value; }
329 
330     void Serialize(llvm::json::OStream &s) const override;
331 
332   protected:
333     bool m_value;
334   };
335 
336   class String : public Object {
337   public:
338     String() : Object(lldb::eStructuredDataTypeString) {}
339     explicit String(llvm::StringRef S)
340         : Object(lldb::eStructuredDataTypeString), m_value(S) {}
341 
342     void SetValue(llvm::StringRef S) { m_value = std::string(S); }
343 
344     llvm::StringRef GetValue() { return m_value; }
345 
346     void Serialize(llvm::json::OStream &s) const override;
347 
348   protected:
349     std::string m_value;
350   };
351 
352   class Dictionary : public Object {
353   public:
354     Dictionary() : Object(lldb::eStructuredDataTypeDictionary) {}
355 
356     Dictionary(ObjectSP obj_sp) : Object(lldb::eStructuredDataTypeDictionary) {
357       if (!obj_sp || obj_sp->GetType() != lldb::eStructuredDataTypeDictionary) {
358         SetType(lldb::eStructuredDataTypeInvalid);
359         return;
360       }
361 
362       Dictionary *dict = obj_sp->GetAsDictionary();
363       m_dict = dict->m_dict;
364     }
365 
366     ~Dictionary() override = default;
367 
368     size_t GetSize() const { return m_dict.size(); }
369 
370     void ForEach(std::function<bool(ConstString key, Object *object)> const
371                      &callback) const {
372       for (const auto &pair : m_dict) {
373         if (!callback(pair.first, pair.second.get()))
374           break;
375       }
376     }
377 
378     ArraySP GetKeys() const {
379       auto array_sp = std::make_shared<Array>();
380       collection::const_iterator iter;
381       for (iter = m_dict.begin(); iter != m_dict.end(); ++iter) {
382         auto key_object_sp = std::make_shared<String>();
383         key_object_sp->SetValue(iter->first.AsCString());
384         array_sp->Push(key_object_sp);
385       }
386       return array_sp;
387     }
388 
389     ObjectSP GetValueForKey(llvm::StringRef key) const {
390       ObjectSP value_sp;
391       if (!key.empty()) {
392         ConstString key_cs(key);
393         collection::const_iterator iter = m_dict.find(key_cs);
394         if (iter != m_dict.end())
395           value_sp = iter->second;
396       }
397       return value_sp;
398     }
399 
400     bool GetValueForKeyAsBoolean(llvm::StringRef key, bool &result) const {
401       bool success = false;
402       ObjectSP value_sp = GetValueForKey(key);
403       if (value_sp.get()) {
404         Boolean *result_ptr = value_sp->GetAsBoolean();
405         if (result_ptr) {
406           result = result_ptr->GetValue();
407           success = true;
408         }
409       }
410       return success;
411     }
412     template <class IntType>
413     bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result) const {
414       ObjectSP value_sp = GetValueForKey(key);
415       if (value_sp) {
416         if (auto int_value = value_sp->GetAsInteger()) {
417           result = static_cast<IntType>(int_value->GetValue());
418           return true;
419         }
420       }
421       return false;
422     }
423 
424     template <class IntType>
425     bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result,
426                                  IntType default_val) const {
427       bool success = GetValueForKeyAsInteger<IntType>(key, result);
428       if (!success)
429         result = default_val;
430       return success;
431     }
432 
433     bool GetValueForKeyAsString(llvm::StringRef key,
434                                 llvm::StringRef &result) const {
435       ObjectSP value_sp = GetValueForKey(key);
436       if (value_sp.get()) {
437         if (auto string_value = value_sp->GetAsString()) {
438           result = string_value->GetValue();
439           return true;
440         }
441       }
442       return false;
443     }
444 
445     bool GetValueForKeyAsString(llvm::StringRef key, llvm::StringRef &result,
446                                 const char *default_val) const {
447       bool success = GetValueForKeyAsString(key, result);
448       if (!success) {
449         if (default_val)
450           result = default_val;
451         else
452           result = llvm::StringRef();
453       }
454       return success;
455     }
456 
457     bool GetValueForKeyAsString(llvm::StringRef key,
458                                 ConstString &result) const {
459       ObjectSP value_sp = GetValueForKey(key);
460       if (value_sp.get()) {
461         if (auto string_value = value_sp->GetAsString()) {
462           result = ConstString(string_value->GetValue());
463           return true;
464         }
465       }
466       return false;
467     }
468 
469     bool GetValueForKeyAsString(llvm::StringRef key, ConstString &result,
470                                 const char *default_val) const {
471       bool success = GetValueForKeyAsString(key, result);
472       if (!success)
473         result.SetCString(default_val);
474       return success;
475     }
476 
477     bool GetValueForKeyAsDictionary(llvm::StringRef key,
478                                     Dictionary *&result) const {
479       result = nullptr;
480       ObjectSP value_sp = GetValueForKey(key);
481       if (value_sp.get()) {
482         result = value_sp->GetAsDictionary();
483         return (result != nullptr);
484       }
485       return false;
486     }
487 
488     bool GetValueForKeyAsArray(llvm::StringRef key, Array *&result) const {
489       result = nullptr;
490       ObjectSP value_sp = GetValueForKey(key);
491       if (value_sp.get()) {
492         result = value_sp->GetAsArray();
493         return (result != nullptr);
494       }
495       return false;
496     }
497 
498     bool HasKey(llvm::StringRef key) const {
499       ConstString key_cs(key);
500       collection::const_iterator search = m_dict.find(key_cs);
501       return search != m_dict.end();
502     }
503 
504     void AddItem(llvm::StringRef key, ObjectSP value_sp) {
505       ConstString key_cs(key);
506       m_dict[key_cs] = std::move(value_sp);
507     }
508 
509     void AddIntegerItem(llvm::StringRef key, uint64_t value) {
510       AddItem(key, std::make_shared<Integer>(value));
511     }
512 
513     void AddFloatItem(llvm::StringRef key, double value) {
514       AddItem(key, std::make_shared<Float>(value));
515     }
516 
517     void AddStringItem(llvm::StringRef key, llvm::StringRef value) {
518       AddItem(key, std::make_shared<String>(std::move(value)));
519     }
520 
521     void AddBooleanItem(llvm::StringRef key, bool value) {
522       AddItem(key, std::make_shared<Boolean>(value));
523     }
524 
525     void Serialize(llvm::json::OStream &s) const override;
526 
527   protected:
528     typedef std::map<ConstString, ObjectSP> collection;
529     collection m_dict;
530   };
531 
532   class Null : public Object {
533   public:
534     Null() : Object(lldb::eStructuredDataTypeNull) {}
535 
536     ~Null() override = default;
537 
538     bool IsValid() const override { return false; }
539 
540     void Serialize(llvm::json::OStream &s) const override;
541   };
542 
543   class Generic : public Object {
544   public:
545     explicit Generic(void *object = nullptr)
546         : Object(lldb::eStructuredDataTypeGeneric), m_object(object) {}
547 
548     void SetValue(void *value) { m_object = value; }
549 
550     void *GetValue() const { return m_object; }
551 
552     bool IsValid() const override { return m_object != nullptr; }
553 
554     void Serialize(llvm::json::OStream &s) const override;
555 
556   private:
557     void *m_object;
558   };
559 
560   static ObjectSP ParseJSON(const std::string &json_text);
561   static ObjectSP ParseJSONFromFile(const FileSpec &file, Status &error);
562 };
563 
564 } // namespace lldb_private
565 
566 #endif // LLDB_UTILITY_STRUCTUREDDATA_H
567