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 liblldb_StructuredData_h_
10#define liblldb_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
31namespace lldb_private {
32class Status;
33}
34
35namespace 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
50class StructuredData {
51public:
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(ObjectSP item) { m_items.push_back(item); }
275
276    void AddItem(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 = 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), m_dict() {}
355
356    ~Dictionary() override = default;
357
358    size_t GetSize() const { return m_dict.size(); }
359
360    void ForEach(std::function<bool(ConstString key, Object *object)> const
361                     &callback) const {
362      for (const auto &pair : m_dict) {
363        if (!callback(pair.first, pair.second.get()))
364          break;
365      }
366    }
367
368    ObjectSP GetKeys() const {
369      auto object_sp = std::make_shared<Array>();
370      collection::const_iterator iter;
371      for (iter = m_dict.begin(); iter != m_dict.end(); ++iter) {
372        auto key_object_sp = std::make_shared<String>();
373        key_object_sp->SetValue(iter->first.AsCString());
374        object_sp->Push(key_object_sp);
375      }
376      return object_sp;
377    }
378
379    ObjectSP GetValueForKey(llvm::StringRef key) const {
380      ObjectSP value_sp;
381      if (!key.empty()) {
382        ConstString key_cs(key);
383        collection::const_iterator iter = m_dict.find(key_cs);
384        if (iter != m_dict.end())
385          value_sp = iter->second;
386      }
387      return value_sp;
388    }
389
390    bool GetValueForKeyAsBoolean(llvm::StringRef key, bool &result) const {
391      bool success = false;
392      ObjectSP value_sp = GetValueForKey(key);
393      if (value_sp.get()) {
394        Boolean *result_ptr = value_sp->GetAsBoolean();
395        if (result_ptr) {
396          result = result_ptr->GetValue();
397          success = true;
398        }
399      }
400      return success;
401    }
402    template <class IntType>
403    bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result) const {
404      ObjectSP value_sp = GetValueForKey(key);
405      if (value_sp) {
406        if (auto int_value = value_sp->GetAsInteger()) {
407          result = static_cast<IntType>(int_value->GetValue());
408          return true;
409        }
410      }
411      return false;
412    }
413
414    template <class IntType>
415    bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result,
416                                 IntType default_val) const {
417      bool success = GetValueForKeyAsInteger<IntType>(key, result);
418      if (!success)
419        result = default_val;
420      return success;
421    }
422
423    bool GetValueForKeyAsString(llvm::StringRef key,
424                                llvm::StringRef &result) const {
425      ObjectSP value_sp = GetValueForKey(key);
426      if (value_sp.get()) {
427        if (auto string_value = value_sp->GetAsString()) {
428          result = string_value->GetValue();
429          return true;
430        }
431      }
432      return false;
433    }
434
435    bool GetValueForKeyAsString(llvm::StringRef key, llvm::StringRef &result,
436                                const char *default_val) const {
437      bool success = GetValueForKeyAsString(key, result);
438      if (!success) {
439        if (default_val)
440          result = default_val;
441        else
442          result = llvm::StringRef();
443      }
444      return success;
445    }
446
447    bool GetValueForKeyAsString(llvm::StringRef key,
448                                ConstString &result) const {
449      ObjectSP value_sp = GetValueForKey(key);
450      if (value_sp.get()) {
451        if (auto string_value = value_sp->GetAsString()) {
452          result = ConstString(string_value->GetValue());
453          return true;
454        }
455      }
456      return false;
457    }
458
459    bool GetValueForKeyAsString(llvm::StringRef key, ConstString &result,
460                                const char *default_val) const {
461      bool success = GetValueForKeyAsString(key, result);
462      if (!success)
463        result.SetCString(default_val);
464      return success;
465    }
466
467    bool GetValueForKeyAsDictionary(llvm::StringRef key,
468                                    Dictionary *&result) const {
469      result = nullptr;
470      ObjectSP value_sp = GetValueForKey(key);
471      if (value_sp.get()) {
472        result = value_sp->GetAsDictionary();
473        return (result != nullptr);
474      }
475      return false;
476    }
477
478    bool GetValueForKeyAsArray(llvm::StringRef key, Array *&result) const {
479      result = nullptr;
480      ObjectSP value_sp = GetValueForKey(key);
481      if (value_sp.get()) {
482        result = value_sp->GetAsArray();
483        return (result != nullptr);
484      }
485      return false;
486    }
487
488    bool HasKey(llvm::StringRef key) const {
489      ConstString key_cs(key);
490      collection::const_iterator search = m_dict.find(key_cs);
491      return search != m_dict.end();
492    }
493
494    void AddItem(llvm::StringRef key, ObjectSP value_sp) {
495      ConstString key_cs(key);
496      m_dict[key_cs] = value_sp;
497    }
498
499    void AddIntegerItem(llvm::StringRef key, uint64_t value) {
500      AddItem(key, std::make_shared<Integer>(value));
501    }
502
503    void AddFloatItem(llvm::StringRef key, double value) {
504      AddItem(key, std::make_shared<Float>(value));
505    }
506
507    void AddStringItem(llvm::StringRef key, llvm::StringRef value) {
508      AddItem(key, std::make_shared<String>(std::move(value)));
509    }
510
511    void AddBooleanItem(llvm::StringRef key, bool value) {
512      AddItem(key, std::make_shared<Boolean>(value));
513    }
514
515    void Serialize(llvm::json::OStream &s) const override;
516
517  protected:
518    typedef std::map<ConstString, ObjectSP> collection;
519    collection m_dict;
520  };
521
522  class Null : public Object {
523  public:
524    Null() : Object(lldb::eStructuredDataTypeNull) {}
525
526    ~Null() override = default;
527
528    bool IsValid() const override { return false; }
529
530    void Serialize(llvm::json::OStream &s) const override;
531  };
532
533  class Generic : public Object {
534  public:
535    explicit Generic(void *object = nullptr)
536        : Object(lldb::eStructuredDataTypeGeneric), m_object(object) {}
537
538    void SetValue(void *value) { m_object = value; }
539
540    void *GetValue() const { return m_object; }
541
542    bool IsValid() const override { return m_object != nullptr; }
543
544    void Serialize(llvm::json::OStream &s) const override;
545
546  private:
547    void *m_object;
548  };
549
550  static ObjectSP ParseJSON(std::string json_text);
551  static ObjectSP ParseJSONFromFile(const FileSpec &file, Status &error);
552};
553
554} // namespace lldb_private
555
556#endif // liblldb_StructuredData_h_
557