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