1 //===-- JSONGenerator.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 __JSONGenerator_h_
10 #define __JSONGenerator_h_
11 
12 
13 #include <iomanip>
14 #include <sstream>
15 #include <string>
16 #include <utility>
17 #include <vector>
18 
19 //----------------------------------------------------------------------
20 /// \class JSONGenerator JSONGenerator.h
21 /// A class which can construct structured data for the sole purpose
22 /// of printing it in JSON format.
23 ///
24 /// A stripped down version of lldb's StructuredData objects which are much
25 /// general purpose.  This variant is intended only for assembling information
26 /// and printing it as a JSON string.
27 //----------------------------------------------------------------------
28 
29 class JSONGenerator {
30 public:
31   class Object;
32   class Array;
33   class Integer;
34   class Float;
35   class Boolean;
36   class String;
37   class Dictionary;
38   class Generic;
39 
40   typedef std::shared_ptr<Object> ObjectSP;
41   typedef std::shared_ptr<Array> ArraySP;
42   typedef std::shared_ptr<Integer> IntegerSP;
43   typedef std::shared_ptr<Float> FloatSP;
44   typedef std::shared_ptr<Boolean> BooleanSP;
45   typedef std::shared_ptr<String> StringSP;
46   typedef std::shared_ptr<Dictionary> DictionarySP;
47   typedef std::shared_ptr<Generic> GenericSP;
48 
49   enum class Type {
50     eTypeInvalid = -1,
51     eTypeNull = 0,
52     eTypeGeneric,
53     eTypeArray,
54     eTypeInteger,
55     eTypeFloat,
56     eTypeBoolean,
57     eTypeString,
58     eTypeDictionary
59   };
60 
61   class Object : public std::enable_shared_from_this<Object> {
62   public:
63     Object(Type t = Type::eTypeInvalid) : m_type(t) {}
64 
65     virtual ~Object() {}
66 
67     virtual bool IsValid() const { return true; }
68 
69     virtual void Clear() { m_type = Type::eTypeInvalid; }
70 
71     Type GetType() const { return m_type; }
72 
73     void SetType(Type t) { m_type = t; }
74 
75     Array *GetAsArray() {
76       if (m_type == Type::eTypeArray)
77         return (Array *)this;
78       return NULL;
79     }
80 
81     Dictionary *GetAsDictionary() {
82       if (m_type == Type::eTypeDictionary)
83         return (Dictionary *)this;
84       return NULL;
85     }
86 
87     Integer *GetAsInteger() {
88       if (m_type == Type::eTypeInteger)
89         return (Integer *)this;
90       return NULL;
91     }
92 
93     Float *GetAsFloat() {
94       if (m_type == Type::eTypeFloat)
95         return (Float *)this;
96       return NULL;
97     }
98 
99     Boolean *GetAsBoolean() {
100       if (m_type == Type::eTypeBoolean)
101         return (Boolean *)this;
102       return NULL;
103     }
104 
105     String *GetAsString() {
106       if (m_type == Type::eTypeString)
107         return (String *)this;
108       return NULL;
109     }
110 
111     Generic *GetAsGeneric() {
112       if (m_type == Type::eTypeGeneric)
113         return (Generic *)this;
114       return NULL;
115     }
116 
117     virtual void Dump(std::ostream &s) const = 0;
118 
119   private:
120     Type m_type;
121   };
122 
123   class Array : public Object {
124   public:
125     Array() : Object(Type::eTypeArray) {}
126 
127     virtual ~Array() {}
128 
129     void AddItem(ObjectSP item) { m_items.push_back(item); }
130 
131     void Dump(std::ostream &s) const override {
132       s << "[";
133       const size_t arrsize = m_items.size();
134       for (size_t i = 0; i < arrsize; ++i) {
135         m_items[i]->Dump(s);
136         if (i + 1 < arrsize)
137           s << ",";
138       }
139       s << "]";
140     }
141 
142   protected:
143     typedef std::vector<ObjectSP> collection;
144     collection m_items;
145   };
146 
147   class Integer : public Object {
148   public:
149     Integer(uint64_t value = 0) : Object(Type::eTypeInteger), m_value(value) {}
150 
151     virtual ~Integer() {}
152 
153     void SetValue(uint64_t value) { m_value = value; }
154 
155     void Dump(std::ostream &s) const override { s << m_value; }
156 
157   protected:
158     uint64_t m_value;
159   };
160 
161   class Float : public Object {
162   public:
163     Float(double d = 0.0) : Object(Type::eTypeFloat), m_value(d) {}
164 
165     virtual ~Float() {}
166 
167     void SetValue(double value) { m_value = value; }
168 
169     void Dump(std::ostream &s) const override { s << m_value; }
170 
171   protected:
172     double m_value;
173   };
174 
175   class Boolean : public Object {
176   public:
177     Boolean(bool b = false) : Object(Type::eTypeBoolean), m_value(b) {}
178 
179     virtual ~Boolean() {}
180 
181     void SetValue(bool value) { m_value = value; }
182 
183     void Dump(std::ostream &s) const override {
184       if (m_value)
185         s << "true";
186       else
187         s << "false";
188     }
189 
190   protected:
191     bool m_value;
192   };
193 
194   class String : public Object {
195   public:
196     String() : Object(Type::eTypeString), m_value() {}
197 
198     String(const std::string &s) : Object(Type::eTypeString), m_value(s) {}
199 
200     String(const std::string &&s) : Object(Type::eTypeString), m_value(s) {}
201 
202     void SetValue(const std::string &string) { m_value = string; }
203 
204     void Dump(std::ostream &s) const override {
205       std::string quoted;
206       const size_t strsize = m_value.size();
207       for (size_t i = 0; i < strsize; ++i) {
208         char ch = m_value[i];
209         if (ch == '"')
210           quoted.push_back('\\');
211         quoted.push_back(ch);
212       }
213       s << '"' << quoted.c_str() << '"';
214     }
215 
216   protected:
217     std::string m_value;
218   };
219 
220   class Dictionary : public Object {
221   public:
222     Dictionary() : Object(Type::eTypeDictionary), m_dict() {}
223 
224     virtual ~Dictionary() {}
225 
226     void AddItem(std::string key, ObjectSP value) {
227       m_dict.push_back(Pair(key, value));
228     }
229 
230     void AddIntegerItem(std::string key, uint64_t value) {
231       AddItem(key, ObjectSP(new Integer(value)));
232     }
233 
234     void AddFloatItem(std::string key, double value) {
235       AddItem(key, ObjectSP(new Float(value)));
236     }
237 
238     void AddStringItem(std::string key, std::string value) {
239       AddItem(key, ObjectSP(new String(std::move(value))));
240     }
241 
242     void AddBytesAsHexASCIIString(std::string key, const uint8_t *src,
243                                   size_t src_len) {
244       if (src && src_len) {
245         std::ostringstream strm;
246         for (size_t i = 0; i < src_len; i++)
247           strm << std::setfill('0') << std::hex << std::right << std::setw(2)
248                << ((uint32_t)(src[i]));
249         AddItem(key, ObjectSP(new String(std::move(strm.str()))));
250       } else {
251         AddItem(key, ObjectSP(new String()));
252       }
253     }
254 
255     void AddBooleanItem(std::string key, bool value) {
256       AddItem(key, ObjectSP(new Boolean(value)));
257     }
258 
259     void Dump(std::ostream &s) const override {
260       bool have_printed_one_elem = false;
261       s << "{";
262       for (collection::const_iterator iter = m_dict.begin();
263            iter != m_dict.end(); ++iter) {
264         if (!have_printed_one_elem) {
265           have_printed_one_elem = true;
266         } else {
267           s << ",";
268         }
269         s << "\"" << iter->first.c_str() << "\":";
270         iter->second->Dump(s);
271       }
272       s << "}";
273     }
274 
275   protected:
276     // Keep the dictionary as a vector so the dictionary doesn't reorder itself
277     // when you dump it
278     // We aren't accessing keys by name, so this won't affect performance
279     typedef std::pair<std::string, ObjectSP> Pair;
280     typedef std::vector<Pair> collection;
281     collection m_dict;
282   };
283 
284   class Null : public Object {
285   public:
286     Null() : Object(Type::eTypeNull) {}
287 
288     virtual ~Null() {}
289 
290     bool IsValid() const override { return false; }
291 
292     void Dump(std::ostream &s) const override { s << "null"; }
293 
294   protected:
295   };
296 
297   class Generic : public Object {
298   public:
299     explicit Generic(void *object = nullptr)
300         : Object(Type::eTypeGeneric), m_object(object) {}
301 
302     void SetValue(void *value) { m_object = value; }
303 
304     void *GetValue() const { return m_object; }
305 
306     bool IsValid() const override { return m_object != nullptr; }
307 
308     void Dump(std::ostream &s) const override;
309 
310   private:
311     void *m_object;
312   };
313 
314 }; // class JSONGenerator
315 
316 #endif // __JSONGenerator_h_
317