391 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLDB_TOOLS_DEBUGSERVER_SOURCE_JSONGENERATOR_H10#define LLDB_TOOLS_DEBUGSERVER_SOURCE_JSONGENERATOR_H11 12#include <iomanip>13#include <sstream>14#include <string>15#include <utility>16#include <vector>17 18/// \class JSONGenerator JSONGenerator.h19/// A class which can construct structured data for the sole purpose20/// of printing it in JSON format.21///22/// A stripped down version of lldb's StructuredData objects which are much23/// general purpose. This variant is intended only for assembling information24/// 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 eTypeDictionary56 };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 else201 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 escaping240 if (ch == '#' || ch == '$' || ch == '}' || ch == '*') {241 s << '}'; // 0x7d next character is escaped242 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 serial323 // 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('}'); // 0x7d338 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 itself347 // when you dump it348 // We aren't accessing keys by name, so this won't affect performance349 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 JSONGenerator389 390#endif // LLDB_TOOLS_DEBUGSERVER_SOURCE_JSONGENERATOR_H391