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 26 class JSONGenerator { 27 public: 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: m_type(t)60 Object(Type t = Type::eTypeInvalid) : m_type(t) {} 61 ~Object()62 virtual ~Object() {} 63 IsValid()64 virtual bool IsValid() const { return true; } 65 Clear()66 virtual void Clear() { m_type = Type::eTypeInvalid; } 67 GetType()68 Type GetType() const { return m_type; } 69 SetType(Type t)70 void SetType(Type t) { m_type = t; } 71 GetAsArray()72 Array *GetAsArray() { 73 if (m_type == Type::eTypeArray) 74 return (Array *)this; 75 return NULL; 76 } 77 GetAsDictionary()78 Dictionary *GetAsDictionary() { 79 if (m_type == Type::eTypeDictionary) 80 return (Dictionary *)this; 81 return NULL; 82 } 83 GetAsInteger()84 Integer *GetAsInteger() { 85 if (m_type == Type::eTypeInteger) 86 return (Integer *)this; 87 return NULL; 88 } 89 GetAsFloat()90 Float *GetAsFloat() { 91 if (m_type == Type::eTypeFloat) 92 return (Float *)this; 93 return NULL; 94 } 95 GetAsBoolean()96 Boolean *GetAsBoolean() { 97 if (m_type == Type::eTypeBoolean) 98 return (Boolean *)this; 99 return NULL; 100 } 101 GetAsString()102 String *GetAsString() { 103 if (m_type == Type::eTypeString) 104 return (String *)this; 105 return NULL; 106 } 107 GetAsGeneric()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: Array()124 Array() : Object(Type::eTypeArray) {} 125 ~Array()126 virtual ~Array() {} 127 AddItem(ObjectSP item)128 void AddItem(ObjectSP item) { m_items.push_back(item); } 129 Dump(std::ostream & s)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 DumpBinaryEscaped(std::ostream & s)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: Object(Type::eTypeInteger)159 Integer(uint64_t value = 0) : Object(Type::eTypeInteger), m_value(value) {} 160 ~Integer()161 virtual ~Integer() {} 162 SetValue(uint64_t value)163 void SetValue(uint64_t value) { m_value = value; } 164 Dump(std::ostream & s)165 void Dump(std::ostream &s) const override { s << m_value; } 166 DumpBinaryEscaped(std::ostream & s)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: Object(Type::eTypeFloat)175 Float(double d = 0.0) : Object(Type::eTypeFloat), m_value(d) {} 176 ~Float()177 virtual ~Float() {} 178 SetValue(double value)179 void SetValue(double value) { m_value = value; } 180 Dump(std::ostream & s)181 void Dump(std::ostream &s) const override { s << m_value; } 182 DumpBinaryEscaped(std::ostream & s)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: Object(Type::eTypeBoolean)191 Boolean(bool b = false) : Object(Type::eTypeBoolean), m_value(b) {} 192 ~Boolean()193 virtual ~Boolean() {} 194 SetValue(bool value)195 void SetValue(bool value) { m_value = value; } 196 Dump(std::ostream & s)197 void Dump(std::ostream &s) const override { 198 if (m_value) 199 s << "true"; 200 else 201 s << "false"; 202 } 203 DumpBinaryEscaped(std::ostream & s)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: String()212 String() : Object(Type::eTypeString), m_value() {} 213 String(const std::string & s)214 String(const std::string &s) : Object(Type::eTypeString), m_value(s) {} 215 String(const std::string && s)216 String(const std::string &&s) : Object(Type::eTypeString), m_value(s) {} 217 SetValue(const std::string & string)218 void SetValue(const std::string &string) { m_value = string; } 219 Dump(std::ostream & s)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 DumpBinaryEscaped(std::ostream & s)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: Dictionary()256 Dictionary() : Object(Type::eTypeDictionary), m_dict() {} 257 ~Dictionary()258 virtual ~Dictionary() {} 259 AddItem(std::string key,ObjectSP value)260 void AddItem(std::string key, ObjectSP value) { 261 m_dict.push_back(Pair(key, value)); 262 } 263 AddIntegerItem(std::string key,uint64_t value)264 void AddIntegerItem(std::string key, uint64_t value) { 265 AddItem(key, ObjectSP(new Integer(value))); 266 } 267 AddFloatItem(std::string key,double value)268 void AddFloatItem(std::string key, double value) { 269 AddItem(key, ObjectSP(new Float(value))); 270 } 271 AddStringItem(std::string key,std::string value)272 void AddStringItem(std::string key, std::string value) { 273 AddItem(key, ObjectSP(new String(std::move(value)))); 274 } 275 AddBytesAsHexASCIIString(std::string key,const uint8_t * src,size_t src_len)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 AddBooleanItem(std::string key,bool value)289 void AddBooleanItem(std::string key, bool value) { 290 AddItem(key, ObjectSP(new Boolean(value))); 291 } 292 Dump(std::ostream & s)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 DumpBinaryEscaped(std::ostream & s)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: binary_encode_string(const std::string & s)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: Null()356 Null() : Object(Type::eTypeNull) {} 357 ~Null()358 virtual ~Null() {} 359 IsValid()360 bool IsValid() const override { return false; } 361 Dump(std::ostream & s)362 void Dump(std::ostream &s) const override { s << "null"; } 363 DumpBinaryEscaped(std::ostream & s)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) Object(Type::eTypeGeneric)372 : Object(Type::eTypeGeneric), m_object(object) {} 373 SetValue(void * value)374 void SetValue(void *value) { m_object = value; } 375 GetValue()376 void *GetValue() const { return m_object; } 377 IsValid()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