xref: /openbsd-src/gnu/llvm/lldb/tools/debugserver/source/JSONGenerator.h (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1061da546Spatrick //===-- JSONGenerator.h ----------------------------------------*- C++ -*-===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9dda28197Spatrick #ifndef LLDB_TOOLS_DEBUGSERVER_SOURCE_JSONGENERATOR_H
10dda28197Spatrick #define LLDB_TOOLS_DEBUGSERVER_SOURCE_JSONGENERATOR_H
11061da546Spatrick 
12061da546Spatrick #include <iomanip>
13061da546Spatrick #include <sstream>
14061da546Spatrick #include <string>
15061da546Spatrick #include <utility>
16061da546Spatrick #include <vector>
17061da546Spatrick 
18061da546Spatrick /// \class JSONGenerator JSONGenerator.h
19061da546Spatrick /// A class which can construct structured data for the sole purpose
20061da546Spatrick /// of printing it in JSON format.
21061da546Spatrick ///
22061da546Spatrick /// A stripped down version of lldb's StructuredData objects which are much
23061da546Spatrick /// general purpose.  This variant is intended only for assembling information
24061da546Spatrick /// and printing it as a JSON string.
25061da546Spatrick 
26061da546Spatrick class JSONGenerator {
27061da546Spatrick public:
28061da546Spatrick   class Object;
29061da546Spatrick   class Array;
30061da546Spatrick   class Integer;
31061da546Spatrick   class Float;
32061da546Spatrick   class Boolean;
33061da546Spatrick   class String;
34061da546Spatrick   class Dictionary;
35061da546Spatrick   class Generic;
36061da546Spatrick 
37061da546Spatrick   typedef std::shared_ptr<Object> ObjectSP;
38061da546Spatrick   typedef std::shared_ptr<Array> ArraySP;
39061da546Spatrick   typedef std::shared_ptr<Integer> IntegerSP;
40061da546Spatrick   typedef std::shared_ptr<Float> FloatSP;
41061da546Spatrick   typedef std::shared_ptr<Boolean> BooleanSP;
42061da546Spatrick   typedef std::shared_ptr<String> StringSP;
43061da546Spatrick   typedef std::shared_ptr<Dictionary> DictionarySP;
44061da546Spatrick   typedef std::shared_ptr<Generic> GenericSP;
45061da546Spatrick 
46061da546Spatrick   enum class Type {
47061da546Spatrick     eTypeInvalid = -1,
48061da546Spatrick     eTypeNull = 0,
49061da546Spatrick     eTypeGeneric,
50061da546Spatrick     eTypeArray,
51061da546Spatrick     eTypeInteger,
52061da546Spatrick     eTypeFloat,
53061da546Spatrick     eTypeBoolean,
54061da546Spatrick     eTypeString,
55061da546Spatrick     eTypeDictionary
56061da546Spatrick   };
57061da546Spatrick 
58061da546Spatrick   class Object : public std::enable_shared_from_this<Object> {
59061da546Spatrick   public:
m_type(t)60061da546Spatrick     Object(Type t = Type::eTypeInvalid) : m_type(t) {}
61061da546Spatrick 
~Object()62061da546Spatrick     virtual ~Object() {}
63061da546Spatrick 
IsValid()64061da546Spatrick     virtual bool IsValid() const { return true; }
65061da546Spatrick 
Clear()66061da546Spatrick     virtual void Clear() { m_type = Type::eTypeInvalid; }
67061da546Spatrick 
GetType()68061da546Spatrick     Type GetType() const { return m_type; }
69061da546Spatrick 
SetType(Type t)70061da546Spatrick     void SetType(Type t) { m_type = t; }
71061da546Spatrick 
GetAsArray()72061da546Spatrick     Array *GetAsArray() {
73061da546Spatrick       if (m_type == Type::eTypeArray)
74061da546Spatrick         return (Array *)this;
75061da546Spatrick       return NULL;
76061da546Spatrick     }
77061da546Spatrick 
GetAsDictionary()78061da546Spatrick     Dictionary *GetAsDictionary() {
79061da546Spatrick       if (m_type == Type::eTypeDictionary)
80061da546Spatrick         return (Dictionary *)this;
81061da546Spatrick       return NULL;
82061da546Spatrick     }
83061da546Spatrick 
GetAsInteger()84061da546Spatrick     Integer *GetAsInteger() {
85061da546Spatrick       if (m_type == Type::eTypeInteger)
86061da546Spatrick         return (Integer *)this;
87061da546Spatrick       return NULL;
88061da546Spatrick     }
89061da546Spatrick 
GetAsFloat()90061da546Spatrick     Float *GetAsFloat() {
91061da546Spatrick       if (m_type == Type::eTypeFloat)
92061da546Spatrick         return (Float *)this;
93061da546Spatrick       return NULL;
94061da546Spatrick     }
95061da546Spatrick 
GetAsBoolean()96061da546Spatrick     Boolean *GetAsBoolean() {
97061da546Spatrick       if (m_type == Type::eTypeBoolean)
98061da546Spatrick         return (Boolean *)this;
99061da546Spatrick       return NULL;
100061da546Spatrick     }
101061da546Spatrick 
GetAsString()102061da546Spatrick     String *GetAsString() {
103061da546Spatrick       if (m_type == Type::eTypeString)
104061da546Spatrick         return (String *)this;
105061da546Spatrick       return NULL;
106061da546Spatrick     }
107061da546Spatrick 
GetAsGeneric()108061da546Spatrick     Generic *GetAsGeneric() {
109061da546Spatrick       if (m_type == Type::eTypeGeneric)
110061da546Spatrick         return (Generic *)this;
111061da546Spatrick       return NULL;
112061da546Spatrick     }
113061da546Spatrick 
114061da546Spatrick     virtual void Dump(std::ostream &s) const = 0;
115061da546Spatrick 
116*f6aab3d8Srobert     virtual void DumpBinaryEscaped(std::ostream &s) const = 0;
117*f6aab3d8Srobert 
118061da546Spatrick   private:
119061da546Spatrick     Type m_type;
120061da546Spatrick   };
121061da546Spatrick 
122061da546Spatrick   class Array : public Object {
123061da546Spatrick   public:
Array()124061da546Spatrick     Array() : Object(Type::eTypeArray) {}
125061da546Spatrick 
~Array()126061da546Spatrick     virtual ~Array() {}
127061da546Spatrick 
AddItem(ObjectSP item)128061da546Spatrick     void AddItem(ObjectSP item) { m_items.push_back(item); }
129061da546Spatrick 
Dump(std::ostream & s)130061da546Spatrick     void Dump(std::ostream &s) const override {
131061da546Spatrick       s << "[";
132061da546Spatrick       const size_t arrsize = m_items.size();
133061da546Spatrick       for (size_t i = 0; i < arrsize; ++i) {
134061da546Spatrick         m_items[i]->Dump(s);
135061da546Spatrick         if (i + 1 < arrsize)
136061da546Spatrick           s << ",";
137061da546Spatrick       }
138061da546Spatrick       s << "]";
139061da546Spatrick     }
140061da546Spatrick 
DumpBinaryEscaped(std::ostream & s)141*f6aab3d8Srobert     void DumpBinaryEscaped(std::ostream &s) const override {
142*f6aab3d8Srobert       s << "[";
143*f6aab3d8Srobert       const size_t arrsize = m_items.size();
144*f6aab3d8Srobert       for (size_t i = 0; i < arrsize; ++i) {
145*f6aab3d8Srobert         m_items[i]->DumpBinaryEscaped(s);
146*f6aab3d8Srobert         if (i + 1 < arrsize)
147*f6aab3d8Srobert           s << ",";
148*f6aab3d8Srobert       }
149*f6aab3d8Srobert       s << "]";
150*f6aab3d8Srobert     }
151*f6aab3d8Srobert 
152061da546Spatrick   protected:
153061da546Spatrick     typedef std::vector<ObjectSP> collection;
154061da546Spatrick     collection m_items;
155061da546Spatrick   };
156061da546Spatrick 
157061da546Spatrick   class Integer : public Object {
158061da546Spatrick   public:
Object(Type::eTypeInteger)159061da546Spatrick     Integer(uint64_t value = 0) : Object(Type::eTypeInteger), m_value(value) {}
160061da546Spatrick 
~Integer()161061da546Spatrick     virtual ~Integer() {}
162061da546Spatrick 
SetValue(uint64_t value)163061da546Spatrick     void SetValue(uint64_t value) { m_value = value; }
164061da546Spatrick 
Dump(std::ostream & s)165061da546Spatrick     void Dump(std::ostream &s) const override { s << m_value; }
166061da546Spatrick 
DumpBinaryEscaped(std::ostream & s)167*f6aab3d8Srobert     void DumpBinaryEscaped(std::ostream &s) const override { Dump(s); }
168*f6aab3d8Srobert 
169061da546Spatrick   protected:
170061da546Spatrick     uint64_t m_value;
171061da546Spatrick   };
172061da546Spatrick 
173061da546Spatrick   class Float : public Object {
174061da546Spatrick   public:
Object(Type::eTypeFloat)175061da546Spatrick     Float(double d = 0.0) : Object(Type::eTypeFloat), m_value(d) {}
176061da546Spatrick 
~Float()177061da546Spatrick     virtual ~Float() {}
178061da546Spatrick 
SetValue(double value)179061da546Spatrick     void SetValue(double value) { m_value = value; }
180061da546Spatrick 
Dump(std::ostream & s)181061da546Spatrick     void Dump(std::ostream &s) const override { s << m_value; }
182061da546Spatrick 
DumpBinaryEscaped(std::ostream & s)183*f6aab3d8Srobert     void DumpBinaryEscaped(std::ostream &s) const override { Dump(s); }
184*f6aab3d8Srobert 
185061da546Spatrick   protected:
186061da546Spatrick     double m_value;
187061da546Spatrick   };
188061da546Spatrick 
189061da546Spatrick   class Boolean : public Object {
190061da546Spatrick   public:
Object(Type::eTypeBoolean)191061da546Spatrick     Boolean(bool b = false) : Object(Type::eTypeBoolean), m_value(b) {}
192061da546Spatrick 
~Boolean()193061da546Spatrick     virtual ~Boolean() {}
194061da546Spatrick 
SetValue(bool value)195061da546Spatrick     void SetValue(bool value) { m_value = value; }
196061da546Spatrick 
Dump(std::ostream & s)197061da546Spatrick     void Dump(std::ostream &s) const override {
198061da546Spatrick       if (m_value)
199061da546Spatrick         s << "true";
200061da546Spatrick       else
201061da546Spatrick         s << "false";
202061da546Spatrick     }
203061da546Spatrick 
DumpBinaryEscaped(std::ostream & s)204*f6aab3d8Srobert     void DumpBinaryEscaped(std::ostream &s) const override { Dump(s); }
205*f6aab3d8Srobert 
206061da546Spatrick   protected:
207061da546Spatrick     bool m_value;
208061da546Spatrick   };
209061da546Spatrick 
210061da546Spatrick   class String : public Object {
211061da546Spatrick   public:
String()212061da546Spatrick     String() : Object(Type::eTypeString), m_value() {}
213061da546Spatrick 
String(const std::string & s)214061da546Spatrick     String(const std::string &s) : Object(Type::eTypeString), m_value(s) {}
215061da546Spatrick 
String(const std::string && s)216061da546Spatrick     String(const std::string &&s) : Object(Type::eTypeString), m_value(s) {}
217061da546Spatrick 
SetValue(const std::string & string)218061da546Spatrick     void SetValue(const std::string &string) { m_value = string; }
219061da546Spatrick 
Dump(std::ostream & s)220061da546Spatrick     void Dump(std::ostream &s) const override {
221*f6aab3d8Srobert       s << '"';
222061da546Spatrick       const size_t strsize = m_value.size();
223061da546Spatrick       for (size_t i = 0; i < strsize; ++i) {
224061da546Spatrick         char ch = m_value[i];
225061da546Spatrick         if (ch == '"')
226*f6aab3d8Srobert           s << '\\';
227*f6aab3d8Srobert         s << ch;
228061da546Spatrick       }
229*f6aab3d8Srobert       s << '"';
230*f6aab3d8Srobert     }
231*f6aab3d8Srobert 
DumpBinaryEscaped(std::ostream & s)232*f6aab3d8Srobert     void DumpBinaryEscaped(std::ostream &s) const override {
233*f6aab3d8Srobert       s << '"';
234*f6aab3d8Srobert       const size_t strsize = m_value.size();
235*f6aab3d8Srobert       for (size_t i = 0; i < strsize; ++i) {
236*f6aab3d8Srobert         char ch = m_value[i];
237*f6aab3d8Srobert         if (ch == '"')
238*f6aab3d8Srobert           s << '\\';
239*f6aab3d8Srobert         // gdb remote serial protocol binary escaping
240*f6aab3d8Srobert         if (ch == '#' || ch == '$' || ch == '}' || ch == '*') {
241*f6aab3d8Srobert           s << '}'; // 0x7d next character is escaped
242*f6aab3d8Srobert           s << static_cast<char>(ch ^ 0x20);
243*f6aab3d8Srobert         } else {
244*f6aab3d8Srobert           s << ch;
245*f6aab3d8Srobert         }
246*f6aab3d8Srobert       }
247*f6aab3d8Srobert       s << '"';
248061da546Spatrick     }
249061da546Spatrick 
250061da546Spatrick   protected:
251061da546Spatrick     std::string m_value;
252061da546Spatrick   };
253061da546Spatrick 
254061da546Spatrick   class Dictionary : public Object {
255061da546Spatrick   public:
Dictionary()256061da546Spatrick     Dictionary() : Object(Type::eTypeDictionary), m_dict() {}
257061da546Spatrick 
~Dictionary()258061da546Spatrick     virtual ~Dictionary() {}
259061da546Spatrick 
AddItem(std::string key,ObjectSP value)260061da546Spatrick     void AddItem(std::string key, ObjectSP value) {
261061da546Spatrick       m_dict.push_back(Pair(key, value));
262061da546Spatrick     }
263061da546Spatrick 
AddIntegerItem(std::string key,uint64_t value)264061da546Spatrick     void AddIntegerItem(std::string key, uint64_t value) {
265061da546Spatrick       AddItem(key, ObjectSP(new Integer(value)));
266061da546Spatrick     }
267061da546Spatrick 
AddFloatItem(std::string key,double value)268061da546Spatrick     void AddFloatItem(std::string key, double value) {
269061da546Spatrick       AddItem(key, ObjectSP(new Float(value)));
270061da546Spatrick     }
271061da546Spatrick 
AddStringItem(std::string key,std::string value)272061da546Spatrick     void AddStringItem(std::string key, std::string value) {
273061da546Spatrick       AddItem(key, ObjectSP(new String(std::move(value))));
274061da546Spatrick     }
275061da546Spatrick 
AddBytesAsHexASCIIString(std::string key,const uint8_t * src,size_t src_len)276061da546Spatrick     void AddBytesAsHexASCIIString(std::string key, const uint8_t *src,
277061da546Spatrick                                   size_t src_len) {
278061da546Spatrick       if (src && src_len) {
279061da546Spatrick         std::ostringstream strm;
280061da546Spatrick         for (size_t i = 0; i < src_len; i++)
281061da546Spatrick           strm << std::setfill('0') << std::hex << std::right << std::setw(2)
282061da546Spatrick                << ((uint32_t)(src[i]));
283061da546Spatrick         AddItem(key, ObjectSP(new String(std::move(strm.str()))));
284061da546Spatrick       } else {
285061da546Spatrick         AddItem(key, ObjectSP(new String()));
286061da546Spatrick       }
287061da546Spatrick     }
288061da546Spatrick 
AddBooleanItem(std::string key,bool value)289061da546Spatrick     void AddBooleanItem(std::string key, bool value) {
290061da546Spatrick       AddItem(key, ObjectSP(new Boolean(value)));
291061da546Spatrick     }
292061da546Spatrick 
Dump(std::ostream & s)293061da546Spatrick     void Dump(std::ostream &s) const override {
294061da546Spatrick       bool have_printed_one_elem = false;
295061da546Spatrick       s << "{";
296061da546Spatrick       for (collection::const_iterator iter = m_dict.begin();
297061da546Spatrick            iter != m_dict.end(); ++iter) {
298061da546Spatrick         if (!have_printed_one_elem) {
299061da546Spatrick           have_printed_one_elem = true;
300061da546Spatrick         } else {
301061da546Spatrick           s << ",";
302061da546Spatrick         }
303061da546Spatrick         s << "\"" << iter->first.c_str() << "\":";
304061da546Spatrick         iter->second->Dump(s);
305061da546Spatrick       }
306061da546Spatrick       s << "}";
307061da546Spatrick     }
308061da546Spatrick 
DumpBinaryEscaped(std::ostream & s)309*f6aab3d8Srobert     void DumpBinaryEscaped(std::ostream &s) const override {
310*f6aab3d8Srobert       bool have_printed_one_elem = false;
311*f6aab3d8Srobert       s << "{";
312*f6aab3d8Srobert       for (collection::const_iterator iter = m_dict.begin();
313*f6aab3d8Srobert            iter != m_dict.end(); ++iter) {
314*f6aab3d8Srobert         if (!have_printed_one_elem) {
315*f6aab3d8Srobert           have_printed_one_elem = true;
316*f6aab3d8Srobert         } else {
317*f6aab3d8Srobert           s << ",";
318*f6aab3d8Srobert         }
319*f6aab3d8Srobert         s << "\"" << binary_encode_string(iter->first) << "\":";
320*f6aab3d8Srobert         iter->second->DumpBinaryEscaped(s);
321*f6aab3d8Srobert       }
322*f6aab3d8Srobert       // '}' must be escaped for the gdb remote serial
323*f6aab3d8Srobert       // protocol.
324*f6aab3d8Srobert       s << "}";
325*f6aab3d8Srobert       s << static_cast<char>('}' ^ 0x20);
326*f6aab3d8Srobert     }
327*f6aab3d8Srobert 
328061da546Spatrick   protected:
binary_encode_string(const std::string & s)329*f6aab3d8Srobert     std::string binary_encode_string(const std::string &s) const {
330*f6aab3d8Srobert       std::string output;
331*f6aab3d8Srobert       const size_t s_size = s.size();
332*f6aab3d8Srobert       const char *s_chars = s.c_str();
333*f6aab3d8Srobert 
334*f6aab3d8Srobert       for (size_t i = 0; i < s_size; i++) {
335*f6aab3d8Srobert         unsigned char ch = *(s_chars + i);
336*f6aab3d8Srobert         if (ch == '#' || ch == '$' || ch == '}' || ch == '*') {
337*f6aab3d8Srobert           output.push_back('}'); // 0x7d
338*f6aab3d8Srobert           output.push_back(ch ^ 0x20);
339*f6aab3d8Srobert         } else {
340*f6aab3d8Srobert           output.push_back(ch);
341*f6aab3d8Srobert         }
342*f6aab3d8Srobert       }
343*f6aab3d8Srobert       return output;
344*f6aab3d8Srobert     }
345*f6aab3d8Srobert 
346061da546Spatrick     // Keep the dictionary as a vector so the dictionary doesn't reorder itself
347061da546Spatrick     // when you dump it
348061da546Spatrick     // We aren't accessing keys by name, so this won't affect performance
349061da546Spatrick     typedef std::pair<std::string, ObjectSP> Pair;
350061da546Spatrick     typedef std::vector<Pair> collection;
351061da546Spatrick     collection m_dict;
352061da546Spatrick   };
353061da546Spatrick 
354061da546Spatrick   class Null : public Object {
355061da546Spatrick   public:
Null()356061da546Spatrick     Null() : Object(Type::eTypeNull) {}
357061da546Spatrick 
~Null()358061da546Spatrick     virtual ~Null() {}
359061da546Spatrick 
IsValid()360061da546Spatrick     bool IsValid() const override { return false; }
361061da546Spatrick 
Dump(std::ostream & s)362061da546Spatrick     void Dump(std::ostream &s) const override { s << "null"; }
363061da546Spatrick 
DumpBinaryEscaped(std::ostream & s)364*f6aab3d8Srobert     void DumpBinaryEscaped(std::ostream &s) const override { Dump(s); }
365*f6aab3d8Srobert 
366061da546Spatrick   protected:
367061da546Spatrick   };
368061da546Spatrick 
369061da546Spatrick   class Generic : public Object {
370061da546Spatrick   public:
371061da546Spatrick     explicit Generic(void *object = nullptr)
Object(Type::eTypeGeneric)372061da546Spatrick         : Object(Type::eTypeGeneric), m_object(object) {}
373061da546Spatrick 
SetValue(void * value)374061da546Spatrick     void SetValue(void *value) { m_object = value; }
375061da546Spatrick 
GetValue()376061da546Spatrick     void *GetValue() const { return m_object; }
377061da546Spatrick 
IsValid()378061da546Spatrick     bool IsValid() const override { return m_object != nullptr; }
379061da546Spatrick 
380061da546Spatrick     void Dump(std::ostream &s) const override;
381061da546Spatrick 
382*f6aab3d8Srobert     void DumpBinaryEscaped(std::ostream &s) const override;
383*f6aab3d8Srobert 
384061da546Spatrick   private:
385061da546Spatrick     void *m_object;
386061da546Spatrick   };
387061da546Spatrick 
388061da546Spatrick }; // class JSONGenerator
389061da546Spatrick 
390dda28197Spatrick #endif // LLDB_TOOLS_DEBUGSERVER_SOURCE_JSONGENERATOR_H
391