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