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