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)
m_type(t)73         : m_type(t) {}
74 
75     virtual ~Object() = default;
76 
IsValid()77     virtual bool IsValid() const { return true; }
78 
Clear()79     virtual void Clear() { m_type = lldb::eStructuredDataTypeInvalid; }
80 
GetType()81     lldb::StructuredDataType GetType() const { return m_type; }
82 
SetType(lldb::StructuredDataType t)83     void SetType(lldb::StructuredDataType t) { m_type = t; }
84 
GetAsArray()85     Array *GetAsArray() {
86       return ((m_type == lldb::eStructuredDataTypeArray)
87                   ? static_cast<Array *>(this)
88                   : nullptr);
89     }
90 
GetAsDictionary()91     Dictionary *GetAsDictionary() {
92       return ((m_type == lldb::eStructuredDataTypeDictionary)
93                   ? static_cast<Dictionary *>(this)
94                   : nullptr);
95     }
96 
GetAsInteger()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 
GetAsFloat()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 
GetAsBoolean()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 
GetAsString()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 
GetAsGeneric()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 
GetDescription(lldb_private::Stream & s)161     virtual void GetDescription(lldb_private::Stream &s) const {
162       s.IndentMore();
163       Dump(s, false);
164       s.IndentLess();
165     }
166 
167   private:
168     lldb::StructuredDataType m_type;
169   };
170 
171   class Array : public Object {
172   public:
Array()173     Array() : Object(lldb::eStructuredDataTypeArray) {}
174 
175     ~Array() override = default;
176 
177     bool
ForEach(std::function<bool (Object * object)> const & foreach_callback)178     ForEach(std::function<bool(Object *object)> const &foreach_callback) const {
179       for (const auto &object_sp : m_items) {
180         if (!foreach_callback(object_sp.get()))
181           return false;
182       }
183       return true;
184     }
185 
GetSize()186     size_t GetSize() const { return m_items.size(); }
187 
188     ObjectSP operator[](size_t idx) {
189       if (idx < m_items.size())
190         return m_items[idx];
191       return ObjectSP();
192     }
193 
GetItemAtIndex(size_t idx)194     ObjectSP GetItemAtIndex(size_t idx) const {
195       assert(idx < GetSize());
196       if (idx < m_items.size())
197         return m_items[idx];
198       return ObjectSP();
199     }
200 
201     template <class IntType>
GetItemAtIndexAsInteger(size_t idx,IntType & result)202     bool GetItemAtIndexAsInteger(size_t idx, IntType &result) const {
203       ObjectSP value_sp = GetItemAtIndex(idx);
204       if (value_sp.get()) {
205         if (auto int_value = value_sp->GetAsInteger()) {
206           result = static_cast<IntType>(int_value->GetValue());
207           return true;
208         }
209       }
210       return false;
211     }
212 
213     template <class IntType>
GetItemAtIndexAsInteger(size_t idx,IntType & result,IntType default_val)214     bool GetItemAtIndexAsInteger(size_t idx, IntType &result,
215                                  IntType default_val) const {
216       bool success = GetItemAtIndexAsInteger(idx, result);
217       if (!success)
218         result = default_val;
219       return success;
220     }
221 
GetItemAtIndexAsString(size_t idx,llvm::StringRef & result)222     bool GetItemAtIndexAsString(size_t idx, llvm::StringRef &result) const {
223       ObjectSP value_sp = GetItemAtIndex(idx);
224       if (value_sp.get()) {
225         if (auto string_value = value_sp->GetAsString()) {
226           result = string_value->GetValue();
227           return true;
228         }
229       }
230       return false;
231     }
232 
GetItemAtIndexAsString(size_t idx,llvm::StringRef & result,llvm::StringRef default_val)233     bool GetItemAtIndexAsString(size_t idx, llvm::StringRef &result,
234                                 llvm::StringRef default_val) const {
235       bool success = GetItemAtIndexAsString(idx, result);
236       if (!success)
237         result = default_val;
238       return success;
239     }
240 
GetItemAtIndexAsString(size_t idx,ConstString & result)241     bool GetItemAtIndexAsString(size_t idx, ConstString &result) const {
242       ObjectSP value_sp = GetItemAtIndex(idx);
243       if (value_sp.get()) {
244         if (auto string_value = value_sp->GetAsString()) {
245           result = ConstString(string_value->GetValue());
246           return true;
247         }
248       }
249       return false;
250     }
251 
GetItemAtIndexAsString(size_t idx,ConstString & result,const char * default_val)252     bool GetItemAtIndexAsString(size_t idx, ConstString &result,
253                                 const char *default_val) const {
254       bool success = GetItemAtIndexAsString(idx, result);
255       if (!success)
256         result.SetCString(default_val);
257       return success;
258     }
259 
GetItemAtIndexAsDictionary(size_t idx,Dictionary * & result)260     bool GetItemAtIndexAsDictionary(size_t idx, Dictionary *&result) const {
261       result = nullptr;
262       ObjectSP value_sp = GetItemAtIndex(idx);
263       if (value_sp.get()) {
264         result = value_sp->GetAsDictionary();
265         return (result != nullptr);
266       }
267       return false;
268     }
269 
GetItemAtIndexAsArray(size_t idx,Array * & result)270     bool GetItemAtIndexAsArray(size_t idx, Array *&result) const {
271       result = nullptr;
272       ObjectSP value_sp = GetItemAtIndex(idx);
273       if (value_sp.get()) {
274         result = value_sp->GetAsArray();
275         return (result != nullptr);
276       }
277       return false;
278     }
279 
Push(const ObjectSP & item)280     void Push(const ObjectSP &item) { m_items.push_back(item); }
281 
AddItem(const ObjectSP & item)282     void AddItem(const ObjectSP &item) { m_items.push_back(item); }
283 
284     void Serialize(llvm::json::OStream &s) const override;
285 
286     void GetDescription(lldb_private::Stream &s) const override;
287 
288   protected:
289     typedef std::vector<ObjectSP> collection;
290     collection m_items;
291   };
292 
293   class Integer : public Object {
294   public:
295     Integer(uint64_t i = 0)
Object(lldb::eStructuredDataTypeInteger)296         : Object(lldb::eStructuredDataTypeInteger), m_value(i) {}
297 
298     ~Integer() override = default;
299 
SetValue(uint64_t value)300     void SetValue(uint64_t value) { m_value = value; }
301 
GetValue()302     uint64_t GetValue() { return m_value; }
303 
304     void Serialize(llvm::json::OStream &s) const override;
305 
306     void GetDescription(lldb_private::Stream &s) const override;
307 
308   protected:
309     uint64_t m_value;
310   };
311 
312   class Float : public Object {
313   public:
314     Float(double d = 0.0)
Object(lldb::eStructuredDataTypeFloat)315         : Object(lldb::eStructuredDataTypeFloat), m_value(d) {}
316 
317     ~Float() override = default;
318 
SetValue(double value)319     void SetValue(double value) { m_value = value; }
320 
GetValue()321     double GetValue() { return m_value; }
322 
323     void Serialize(llvm::json::OStream &s) const override;
324 
325     void GetDescription(lldb_private::Stream &s) const override;
326 
327   protected:
328     double m_value;
329   };
330 
331   class Boolean : public Object {
332   public:
333     Boolean(bool b = false)
Object(lldb::eStructuredDataTypeBoolean)334         : Object(lldb::eStructuredDataTypeBoolean), m_value(b) {}
335 
336     ~Boolean() override = default;
337 
SetValue(bool value)338     void SetValue(bool value) { m_value = value; }
339 
GetValue()340     bool GetValue() { return m_value; }
341 
342     void Serialize(llvm::json::OStream &s) const override;
343 
344     void GetDescription(lldb_private::Stream &s) const override;
345 
346   protected:
347     bool m_value;
348   };
349 
350   class String : public Object {
351   public:
String()352     String() : Object(lldb::eStructuredDataTypeString) {}
String(llvm::StringRef S)353     explicit String(llvm::StringRef S)
354         : Object(lldb::eStructuredDataTypeString), m_value(S) {}
355 
SetValue(llvm::StringRef S)356     void SetValue(llvm::StringRef S) { m_value = std::string(S); }
357 
GetValue()358     llvm::StringRef GetValue() { return m_value; }
359 
360     void Serialize(llvm::json::OStream &s) const override;
361 
362     void GetDescription(lldb_private::Stream &s) const override;
363 
364   protected:
365     std::string m_value;
366   };
367 
368   class Dictionary : public Object {
369   public:
Dictionary()370     Dictionary() : Object(lldb::eStructuredDataTypeDictionary) {}
371 
Dictionary(ObjectSP obj_sp)372     Dictionary(ObjectSP obj_sp) : Object(lldb::eStructuredDataTypeDictionary) {
373       if (!obj_sp || obj_sp->GetType() != lldb::eStructuredDataTypeDictionary) {
374         SetType(lldb::eStructuredDataTypeInvalid);
375         return;
376       }
377 
378       Dictionary *dict = obj_sp->GetAsDictionary();
379       m_dict = dict->m_dict;
380     }
381 
382     ~Dictionary() override = default;
383 
GetSize()384     size_t GetSize() const { return m_dict.size(); }
385 
ForEach(std::function<bool (ConstString key,Object * object)> const & callback)386     void ForEach(std::function<bool(ConstString key, Object *object)> const
387                      &callback) const {
388       for (const auto &pair : m_dict) {
389         if (!callback(pair.first, pair.second.get()))
390           break;
391       }
392     }
393 
GetKeys()394     ArraySP GetKeys() const {
395       auto array_sp = std::make_shared<Array>();
396       collection::const_iterator iter;
397       for (iter = m_dict.begin(); iter != m_dict.end(); ++iter) {
398         auto key_object_sp = std::make_shared<String>();
399         key_object_sp->SetValue(iter->first.AsCString());
400         array_sp->Push(key_object_sp);
401       }
402       return array_sp;
403     }
404 
GetValueForKey(llvm::StringRef key)405     ObjectSP GetValueForKey(llvm::StringRef key) const {
406       ObjectSP value_sp;
407       if (!key.empty()) {
408         ConstString key_cs(key);
409         collection::const_iterator iter = m_dict.find(key_cs);
410         if (iter != m_dict.end())
411           value_sp = iter->second;
412       }
413       return value_sp;
414     }
415 
GetValueForKeyAsBoolean(llvm::StringRef key,bool & result)416     bool GetValueForKeyAsBoolean(llvm::StringRef key, bool &result) const {
417       bool success = false;
418       ObjectSP value_sp = GetValueForKey(key);
419       if (value_sp.get()) {
420         Boolean *result_ptr = value_sp->GetAsBoolean();
421         if (result_ptr) {
422           result = result_ptr->GetValue();
423           success = true;
424         }
425       }
426       return success;
427     }
428     template <class IntType>
GetValueForKeyAsInteger(llvm::StringRef key,IntType & result)429     bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result) const {
430       ObjectSP value_sp = GetValueForKey(key);
431       if (value_sp) {
432         if (auto int_value = value_sp->GetAsInteger()) {
433           result = static_cast<IntType>(int_value->GetValue());
434           return true;
435         }
436       }
437       return false;
438     }
439 
440     template <class IntType>
GetValueForKeyAsInteger(llvm::StringRef key,IntType & result,IntType default_val)441     bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result,
442                                  IntType default_val) const {
443       bool success = GetValueForKeyAsInteger<IntType>(key, result);
444       if (!success)
445         result = default_val;
446       return success;
447     }
448 
GetValueForKeyAsString(llvm::StringRef key,llvm::StringRef & result)449     bool GetValueForKeyAsString(llvm::StringRef key,
450                                 llvm::StringRef &result) const {
451       ObjectSP value_sp = GetValueForKey(key);
452       if (value_sp.get()) {
453         if (auto string_value = value_sp->GetAsString()) {
454           result = string_value->GetValue();
455           return true;
456         }
457       }
458       return false;
459     }
460 
GetValueForKeyAsString(llvm::StringRef key,llvm::StringRef & result,const char * default_val)461     bool GetValueForKeyAsString(llvm::StringRef key, llvm::StringRef &result,
462                                 const char *default_val) const {
463       bool success = GetValueForKeyAsString(key, result);
464       if (!success) {
465         if (default_val)
466           result = default_val;
467         else
468           result = llvm::StringRef();
469       }
470       return success;
471     }
472 
GetValueForKeyAsString(llvm::StringRef key,ConstString & result)473     bool GetValueForKeyAsString(llvm::StringRef key,
474                                 ConstString &result) const {
475       ObjectSP value_sp = GetValueForKey(key);
476       if (value_sp.get()) {
477         if (auto string_value = value_sp->GetAsString()) {
478           result = ConstString(string_value->GetValue());
479           return true;
480         }
481       }
482       return false;
483     }
484 
GetValueForKeyAsString(llvm::StringRef key,ConstString & result,const char * default_val)485     bool GetValueForKeyAsString(llvm::StringRef key, ConstString &result,
486                                 const char *default_val) const {
487       bool success = GetValueForKeyAsString(key, result);
488       if (!success)
489         result.SetCString(default_val);
490       return success;
491     }
492 
GetValueForKeyAsDictionary(llvm::StringRef key,Dictionary * & result)493     bool GetValueForKeyAsDictionary(llvm::StringRef key,
494                                     Dictionary *&result) const {
495       result = nullptr;
496       ObjectSP value_sp = GetValueForKey(key);
497       if (value_sp.get()) {
498         result = value_sp->GetAsDictionary();
499         return (result != nullptr);
500       }
501       return false;
502     }
503 
GetValueForKeyAsArray(llvm::StringRef key,Array * & result)504     bool GetValueForKeyAsArray(llvm::StringRef key, Array *&result) const {
505       result = nullptr;
506       ObjectSP value_sp = GetValueForKey(key);
507       if (value_sp.get()) {
508         result = value_sp->GetAsArray();
509         return (result != nullptr);
510       }
511       return false;
512     }
513 
HasKey(llvm::StringRef key)514     bool HasKey(llvm::StringRef key) const {
515       ConstString key_cs(key);
516       collection::const_iterator search = m_dict.find(key_cs);
517       return search != m_dict.end();
518     }
519 
AddItem(llvm::StringRef key,ObjectSP value_sp)520     void AddItem(llvm::StringRef key, ObjectSP value_sp) {
521       ConstString key_cs(key);
522       m_dict[key_cs] = std::move(value_sp);
523     }
524 
AddIntegerItem(llvm::StringRef key,uint64_t value)525     void AddIntegerItem(llvm::StringRef key, uint64_t value) {
526       AddItem(key, std::make_shared<Integer>(value));
527     }
528 
AddFloatItem(llvm::StringRef key,double value)529     void AddFloatItem(llvm::StringRef key, double value) {
530       AddItem(key, std::make_shared<Float>(value));
531     }
532 
AddStringItem(llvm::StringRef key,llvm::StringRef value)533     void AddStringItem(llvm::StringRef key, llvm::StringRef value) {
534       AddItem(key, std::make_shared<String>(std::move(value)));
535     }
536 
AddBooleanItem(llvm::StringRef key,bool value)537     void AddBooleanItem(llvm::StringRef key, bool value) {
538       AddItem(key, std::make_shared<Boolean>(value));
539     }
540 
541     void Serialize(llvm::json::OStream &s) const override;
542 
543     void GetDescription(lldb_private::Stream &s) const override;
544 
545   protected:
546     typedef std::map<ConstString, ObjectSP> collection;
547     collection m_dict;
548   };
549 
550   class Null : public Object {
551   public:
Null()552     Null() : Object(lldb::eStructuredDataTypeNull) {}
553 
554     ~Null() override = default;
555 
IsValid()556     bool IsValid() const override { return false; }
557 
558     void Serialize(llvm::json::OStream &s) const override;
559 
560     void GetDescription(lldb_private::Stream &s) const override;
561   };
562 
563   class Generic : public Object {
564   public:
565     explicit Generic(void *object = nullptr)
Object(lldb::eStructuredDataTypeGeneric)566         : Object(lldb::eStructuredDataTypeGeneric), m_object(object) {}
567 
SetValue(void * value)568     void SetValue(void *value) { m_object = value; }
569 
GetValue()570     void *GetValue() const { return m_object; }
571 
IsValid()572     bool IsValid() const override { return m_object != nullptr; }
573 
574     void Serialize(llvm::json::OStream &s) const override;
575 
576     void GetDescription(lldb_private::Stream &s) const override;
577 
578   private:
579     void *m_object;
580   };
581 
582   static ObjectSP ParseJSON(const std::string &json_text);
583   static ObjectSP ParseJSONFromFile(const FileSpec &file, Status &error);
584   static bool IsRecordType(const ObjectSP object_sp);
585 };
586 
587 } // namespace lldb_private
588 
589 #endif // LLDB_UTILITY_STRUCTUREDDATA_H
590