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