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(x: 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(x: Pair(key, value));
262 }
263
264 void AddIntegerItem(std::string key, uint64_t value) {
265 AddItem(key, value: ObjectSP(new Integer(value)));
266 }
267
268 void AddFloatItem(std::string key, double value) {
269 AddItem(key, value: ObjectSP(new Float(value)));
270 }
271
272 void AddStringItem(std::string key, std::string value) {
273 AddItem(key, value: 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, value: ObjectSP(new String(std::move(strm.str()))));
284 } else {
285 AddItem(key, value: ObjectSP(new String()));
286 }
287 }
288
289 void AddBooleanItem(std::string key, bool value) {
290 AddItem(key, value: 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(s: 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(c: '}'); // 0x7d
338 output.push_back(c: ch ^ 0x20);
339 } else {
340 output.push_back(c: 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

source code of lldb/tools/debugserver/source/JSONGenerator.h