1320543Sdim//===-- StructuredData.h ----------------------------------------*- C++ -*-===// 2320543Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6320543Sdim// 7320543Sdim//===----------------------------------------------------------------------===// 8320543Sdim 9320543Sdim#ifndef liblldb_StructuredData_h_ 10320543Sdim#define liblldb_StructuredData_h_ 11320543Sdim 12320543Sdim#include "llvm/ADT/StringRef.h" 13360784Sdim#include "llvm/Support/JSON.h" 14320543Sdim 15320543Sdim#include "lldb/Utility/ConstString.h" 16344779Sdim#include "lldb/Utility/FileSpec.h" 17360784Sdim#include "lldb/Utility/Stream.h" 18344779Sdim#include "lldb/lldb-enumerations.h" 19320543Sdim 20344779Sdim#include <cassert> 21344779Sdim#include <cstddef> 22344779Sdim#include <cstdint> 23320543Sdim#include <functional> 24320543Sdim#include <map> 25320543Sdim#include <memory> 26320543Sdim#include <string> 27344779Sdim#include <type_traits> 28320543Sdim#include <utility> 29320543Sdim#include <vector> 30320543Sdim 31320543Sdimnamespace lldb_private { 32320543Sdimclass Status; 33320543Sdim} 34320543Sdim 35320543Sdimnamespace lldb_private { 36320543Sdim 37353358Sdim/// \class StructuredData StructuredData.h "lldb/Utility/StructuredData.h" 38341825Sdim/// A class which can hold structured data 39320543Sdim/// 40341825Sdim/// The StructuredData class is designed to hold the data from a JSON or plist 41341825Sdim/// style file -- a serialized data structure with dictionaries (maps, 42341825Sdim/// hashes), arrays, and concrete values like integers, floating point 43341825Sdim/// numbers, strings, booleans. 44320543Sdim/// 45341825Sdim/// StructuredData does not presuppose any knowledge of the schema for the 46341825Sdim/// data it is holding; it can parse JSON data, for instance, and other parts 47341825Sdim/// of lldb can iterate through the parsed data set to find keys and values 48341825Sdim/// that may be present. 49320543Sdim 50320543Sdimclass StructuredData { 51320543Sdimpublic: 52320543Sdim class Object; 53320543Sdim class Array; 54320543Sdim class Integer; 55320543Sdim class Float; 56320543Sdim class Boolean; 57320543Sdim class String; 58320543Sdim class Dictionary; 59320543Sdim class Generic; 60320543Sdim 61320543Sdim typedef std::shared_ptr<Object> ObjectSP; 62320543Sdim typedef std::shared_ptr<Array> ArraySP; 63320543Sdim typedef std::shared_ptr<Integer> IntegerSP; 64320543Sdim typedef std::shared_ptr<Float> FloatSP; 65320543Sdim typedef std::shared_ptr<Boolean> BooleanSP; 66320543Sdim typedef std::shared_ptr<String> StringSP; 67320543Sdim typedef std::shared_ptr<Dictionary> DictionarySP; 68320543Sdim typedef std::shared_ptr<Generic> GenericSP; 69320543Sdim 70320543Sdim class Object : public std::enable_shared_from_this<Object> { 71320543Sdim public: 72320543Sdim Object(lldb::StructuredDataType t = lldb::eStructuredDataTypeInvalid) 73320543Sdim : m_type(t) {} 74320543Sdim 75320543Sdim virtual ~Object() = default; 76320543Sdim 77320543Sdim virtual bool IsValid() const { return true; } 78320543Sdim 79320543Sdim virtual void Clear() { m_type = lldb::eStructuredDataTypeInvalid; } 80320543Sdim 81320543Sdim lldb::StructuredDataType GetType() const { return m_type; } 82320543Sdim 83320543Sdim void SetType(lldb::StructuredDataType t) { m_type = t; } 84320543Sdim 85320543Sdim Array *GetAsArray() { 86320543Sdim return ((m_type == lldb::eStructuredDataTypeArray) 87320543Sdim ? static_cast<Array *>(this) 88320543Sdim : nullptr); 89320543Sdim } 90320543Sdim 91320543Sdim Dictionary *GetAsDictionary() { 92320543Sdim return ((m_type == lldb::eStructuredDataTypeDictionary) 93320543Sdim ? static_cast<Dictionary *>(this) 94320543Sdim : nullptr); 95320543Sdim } 96320543Sdim 97320543Sdim Integer *GetAsInteger() { 98320543Sdim return ((m_type == lldb::eStructuredDataTypeInteger) 99320543Sdim ? static_cast<Integer *>(this) 100320543Sdim : nullptr); 101320543Sdim } 102320543Sdim 103320543Sdim uint64_t GetIntegerValue(uint64_t fail_value = 0) { 104320543Sdim Integer *integer = GetAsInteger(); 105320543Sdim return ((integer != nullptr) ? integer->GetValue() : fail_value); 106320543Sdim } 107320543Sdim 108320543Sdim Float *GetAsFloat() { 109320543Sdim return ((m_type == lldb::eStructuredDataTypeFloat) 110320543Sdim ? static_cast<Float *>(this) 111320543Sdim : nullptr); 112320543Sdim } 113320543Sdim 114320543Sdim double GetFloatValue(double fail_value = 0.0) { 115320543Sdim Float *f = GetAsFloat(); 116320543Sdim return ((f != nullptr) ? f->GetValue() : fail_value); 117320543Sdim } 118320543Sdim 119320543Sdim Boolean *GetAsBoolean() { 120320543Sdim return ((m_type == lldb::eStructuredDataTypeBoolean) 121320543Sdim ? static_cast<Boolean *>(this) 122320543Sdim : nullptr); 123320543Sdim } 124320543Sdim 125320543Sdim bool GetBooleanValue(bool fail_value = false) { 126320543Sdim Boolean *b = GetAsBoolean(); 127320543Sdim return ((b != nullptr) ? b->GetValue() : fail_value); 128320543Sdim } 129320543Sdim 130320543Sdim String *GetAsString() { 131320543Sdim return ((m_type == lldb::eStructuredDataTypeString) 132320543Sdim ? static_cast<String *>(this) 133320543Sdim : nullptr); 134320543Sdim } 135320543Sdim 136320543Sdim llvm::StringRef GetStringValue(const char *fail_value = nullptr) { 137320543Sdim String *s = GetAsString(); 138320543Sdim if (s) 139320543Sdim return s->GetValue(); 140320543Sdim 141320543Sdim return fail_value; 142320543Sdim } 143320543Sdim 144320543Sdim Generic *GetAsGeneric() { 145320543Sdim return ((m_type == lldb::eStructuredDataTypeGeneric) 146320543Sdim ? static_cast<Generic *>(this) 147320543Sdim : nullptr); 148320543Sdim } 149320543Sdim 150320543Sdim ObjectSP GetObjectForDotSeparatedPath(llvm::StringRef path); 151320543Sdim 152320543Sdim void DumpToStdout(bool pretty_print = true) const; 153320543Sdim 154360784Sdim virtual void Serialize(llvm::json::OStream &s) const = 0; 155320543Sdim 156360784Sdim void Dump(lldb_private::Stream &s, bool pretty_print = true) const { 157360784Sdim llvm::json::OStream jso(s.AsRawOstream(), pretty_print ? 2 : 0); 158360784Sdim Serialize(jso); 159360784Sdim } 160360784Sdim 161320543Sdim private: 162320543Sdim lldb::StructuredDataType m_type; 163320543Sdim }; 164320543Sdim 165320543Sdim class Array : public Object { 166320543Sdim public: 167320543Sdim Array() : Object(lldb::eStructuredDataTypeArray) {} 168320543Sdim 169320543Sdim ~Array() override = default; 170320543Sdim 171320543Sdim bool 172320543Sdim ForEach(std::function<bool(Object *object)> const &foreach_callback) const { 173320543Sdim for (const auto &object_sp : m_items) { 174344779Sdim if (!foreach_callback(object_sp.get())) 175320543Sdim return false; 176320543Sdim } 177320543Sdim return true; 178320543Sdim } 179320543Sdim 180320543Sdim size_t GetSize() const { return m_items.size(); } 181320543Sdim 182320543Sdim ObjectSP operator[](size_t idx) { 183320543Sdim if (idx < m_items.size()) 184320543Sdim return m_items[idx]; 185320543Sdim return ObjectSP(); 186320543Sdim } 187320543Sdim 188320543Sdim ObjectSP GetItemAtIndex(size_t idx) const { 189320543Sdim assert(idx < GetSize()); 190320543Sdim if (idx < m_items.size()) 191320543Sdim return m_items[idx]; 192320543Sdim return ObjectSP(); 193320543Sdim } 194320543Sdim 195320543Sdim template <class IntType> 196320543Sdim bool GetItemAtIndexAsInteger(size_t idx, IntType &result) const { 197320543Sdim ObjectSP value_sp = GetItemAtIndex(idx); 198320543Sdim if (value_sp.get()) { 199320543Sdim if (auto int_value = value_sp->GetAsInteger()) { 200320543Sdim result = static_cast<IntType>(int_value->GetValue()); 201320543Sdim return true; 202320543Sdim } 203320543Sdim } 204320543Sdim return false; 205320543Sdim } 206320543Sdim 207320543Sdim template <class IntType> 208320543Sdim bool GetItemAtIndexAsInteger(size_t idx, IntType &result, 209320543Sdim IntType default_val) const { 210320543Sdim bool success = GetItemAtIndexAsInteger(idx, result); 211320543Sdim if (!success) 212320543Sdim result = default_val; 213320543Sdim return success; 214320543Sdim } 215320543Sdim 216320543Sdim bool GetItemAtIndexAsString(size_t idx, llvm::StringRef &result) const { 217320543Sdim ObjectSP value_sp = GetItemAtIndex(idx); 218320543Sdim if (value_sp.get()) { 219320543Sdim if (auto string_value = value_sp->GetAsString()) { 220320543Sdim result = string_value->GetValue(); 221320543Sdim return true; 222320543Sdim } 223320543Sdim } 224320543Sdim return false; 225320543Sdim } 226320543Sdim 227320543Sdim bool GetItemAtIndexAsString(size_t idx, llvm::StringRef &result, 228320543Sdim llvm::StringRef default_val) const { 229320543Sdim bool success = GetItemAtIndexAsString(idx, result); 230320543Sdim if (!success) 231320543Sdim result = default_val; 232320543Sdim return success; 233320543Sdim } 234320543Sdim 235320543Sdim bool GetItemAtIndexAsString(size_t idx, ConstString &result) const { 236320543Sdim ObjectSP value_sp = GetItemAtIndex(idx); 237320543Sdim if (value_sp.get()) { 238320543Sdim if (auto string_value = value_sp->GetAsString()) { 239320543Sdim result = ConstString(string_value->GetValue()); 240320543Sdim return true; 241320543Sdim } 242320543Sdim } 243320543Sdim return false; 244320543Sdim } 245320543Sdim 246320543Sdim bool GetItemAtIndexAsString(size_t idx, ConstString &result, 247320543Sdim const char *default_val) const { 248320543Sdim bool success = GetItemAtIndexAsString(idx, result); 249320543Sdim if (!success) 250320543Sdim result.SetCString(default_val); 251320543Sdim return success; 252320543Sdim } 253320543Sdim 254320543Sdim bool GetItemAtIndexAsDictionary(size_t idx, Dictionary *&result) const { 255320543Sdim result = nullptr; 256320543Sdim ObjectSP value_sp = GetItemAtIndex(idx); 257320543Sdim if (value_sp.get()) { 258320543Sdim result = value_sp->GetAsDictionary(); 259320543Sdim return (result != nullptr); 260320543Sdim } 261320543Sdim return false; 262320543Sdim } 263320543Sdim 264320543Sdim bool GetItemAtIndexAsArray(size_t idx, Array *&result) const { 265320543Sdim result = nullptr; 266320543Sdim ObjectSP value_sp = GetItemAtIndex(idx); 267320543Sdim if (value_sp.get()) { 268320543Sdim result = value_sp->GetAsArray(); 269320543Sdim return (result != nullptr); 270320543Sdim } 271320543Sdim return false; 272320543Sdim } 273320543Sdim 274320543Sdim void Push(ObjectSP item) { m_items.push_back(item); } 275320543Sdim 276320543Sdim void AddItem(ObjectSP item) { m_items.push_back(item); } 277320543Sdim 278360784Sdim void Serialize(llvm::json::OStream &s) const override; 279320543Sdim 280320543Sdim protected: 281320543Sdim typedef std::vector<ObjectSP> collection; 282320543Sdim collection m_items; 283320543Sdim }; 284320543Sdim 285320543Sdim class Integer : public Object { 286320543Sdim public: 287320543Sdim Integer(uint64_t i = 0) 288320543Sdim : Object(lldb::eStructuredDataTypeInteger), m_value(i) {} 289320543Sdim 290320543Sdim ~Integer() override = default; 291320543Sdim 292320543Sdim void SetValue(uint64_t value) { m_value = value; } 293320543Sdim 294320543Sdim uint64_t GetValue() { return m_value; } 295320543Sdim 296360784Sdim void Serialize(llvm::json::OStream &s) const override; 297320543Sdim 298320543Sdim protected: 299320543Sdim uint64_t m_value; 300320543Sdim }; 301320543Sdim 302320543Sdim class Float : public Object { 303320543Sdim public: 304320543Sdim Float(double d = 0.0) 305320543Sdim : Object(lldb::eStructuredDataTypeFloat), m_value(d) {} 306320543Sdim 307320543Sdim ~Float() override = default; 308320543Sdim 309320543Sdim void SetValue(double value) { m_value = value; } 310320543Sdim 311320543Sdim double GetValue() { return m_value; } 312320543Sdim 313360784Sdim void Serialize(llvm::json::OStream &s) const override; 314320543Sdim 315320543Sdim protected: 316320543Sdim double m_value; 317320543Sdim }; 318320543Sdim 319320543Sdim class Boolean : public Object { 320320543Sdim public: 321320543Sdim Boolean(bool b = false) 322320543Sdim : Object(lldb::eStructuredDataTypeBoolean), m_value(b) {} 323320543Sdim 324320543Sdim ~Boolean() override = default; 325320543Sdim 326320543Sdim void SetValue(bool value) { m_value = value; } 327320543Sdim 328320543Sdim bool GetValue() { return m_value; } 329320543Sdim 330360784Sdim void Serialize(llvm::json::OStream &s) const override; 331320543Sdim 332320543Sdim protected: 333320543Sdim bool m_value; 334320543Sdim }; 335320543Sdim 336320543Sdim class String : public Object { 337320543Sdim public: 338320543Sdim String() : Object(lldb::eStructuredDataTypeString) {} 339320543Sdim explicit String(llvm::StringRef S) 340320543Sdim : Object(lldb::eStructuredDataTypeString), m_value(S) {} 341320543Sdim 342320543Sdim void SetValue(llvm::StringRef S) { m_value = S; } 343320543Sdim 344320543Sdim llvm::StringRef GetValue() { return m_value; } 345320543Sdim 346360784Sdim void Serialize(llvm::json::OStream &s) const override; 347320543Sdim 348320543Sdim protected: 349320543Sdim std::string m_value; 350320543Sdim }; 351320543Sdim 352320543Sdim class Dictionary : public Object { 353320543Sdim public: 354320543Sdim Dictionary() : Object(lldb::eStructuredDataTypeDictionary), m_dict() {} 355320543Sdim 356320543Sdim ~Dictionary() override = default; 357320543Sdim 358320543Sdim size_t GetSize() const { return m_dict.size(); } 359320543Sdim 360320543Sdim void ForEach(std::function<bool(ConstString key, Object *object)> const 361320543Sdim &callback) const { 362320543Sdim for (const auto &pair : m_dict) { 363344779Sdim if (!callback(pair.first, pair.second.get())) 364320543Sdim break; 365320543Sdim } 366320543Sdim } 367320543Sdim 368320543Sdim ObjectSP GetKeys() const { 369320543Sdim auto object_sp = std::make_shared<Array>(); 370320543Sdim collection::const_iterator iter; 371320543Sdim for (iter = m_dict.begin(); iter != m_dict.end(); ++iter) { 372320543Sdim auto key_object_sp = std::make_shared<String>(); 373320543Sdim key_object_sp->SetValue(iter->first.AsCString()); 374320543Sdim object_sp->Push(key_object_sp); 375320543Sdim } 376320543Sdim return object_sp; 377320543Sdim } 378320543Sdim 379320543Sdim ObjectSP GetValueForKey(llvm::StringRef key) const { 380320543Sdim ObjectSP value_sp; 381320543Sdim if (!key.empty()) { 382320543Sdim ConstString key_cs(key); 383320543Sdim collection::const_iterator iter = m_dict.find(key_cs); 384320543Sdim if (iter != m_dict.end()) 385320543Sdim value_sp = iter->second; 386320543Sdim } 387320543Sdim return value_sp; 388320543Sdim } 389320543Sdim 390320543Sdim bool GetValueForKeyAsBoolean(llvm::StringRef key, bool &result) const { 391320543Sdim bool success = false; 392320543Sdim ObjectSP value_sp = GetValueForKey(key); 393320543Sdim if (value_sp.get()) { 394320543Sdim Boolean *result_ptr = value_sp->GetAsBoolean(); 395320543Sdim if (result_ptr) { 396320543Sdim result = result_ptr->GetValue(); 397320543Sdim success = true; 398320543Sdim } 399320543Sdim } 400320543Sdim return success; 401320543Sdim } 402320543Sdim template <class IntType> 403320543Sdim bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result) const { 404320543Sdim ObjectSP value_sp = GetValueForKey(key); 405320543Sdim if (value_sp) { 406320543Sdim if (auto int_value = value_sp->GetAsInteger()) { 407320543Sdim result = static_cast<IntType>(int_value->GetValue()); 408320543Sdim return true; 409320543Sdim } 410320543Sdim } 411320543Sdim return false; 412320543Sdim } 413320543Sdim 414320543Sdim template <class IntType> 415320543Sdim bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result, 416320543Sdim IntType default_val) const { 417320543Sdim bool success = GetValueForKeyAsInteger<IntType>(key, result); 418320543Sdim if (!success) 419320543Sdim result = default_val; 420320543Sdim return success; 421320543Sdim } 422320543Sdim 423320543Sdim bool GetValueForKeyAsString(llvm::StringRef key, 424320543Sdim llvm::StringRef &result) const { 425320543Sdim ObjectSP value_sp = GetValueForKey(key); 426320543Sdim if (value_sp.get()) { 427320543Sdim if (auto string_value = value_sp->GetAsString()) { 428320543Sdim result = string_value->GetValue(); 429320543Sdim return true; 430320543Sdim } 431320543Sdim } 432320543Sdim return false; 433320543Sdim } 434320543Sdim 435320543Sdim bool GetValueForKeyAsString(llvm::StringRef key, llvm::StringRef &result, 436320543Sdim const char *default_val) const { 437320543Sdim bool success = GetValueForKeyAsString(key, result); 438320543Sdim if (!success) { 439320543Sdim if (default_val) 440320543Sdim result = default_val; 441320543Sdim else 442320543Sdim result = llvm::StringRef(); 443320543Sdim } 444320543Sdim return success; 445320543Sdim } 446320543Sdim 447320543Sdim bool GetValueForKeyAsString(llvm::StringRef key, 448320543Sdim ConstString &result) const { 449320543Sdim ObjectSP value_sp = GetValueForKey(key); 450320543Sdim if (value_sp.get()) { 451320543Sdim if (auto string_value = value_sp->GetAsString()) { 452320543Sdim result = ConstString(string_value->GetValue()); 453320543Sdim return true; 454320543Sdim } 455320543Sdim } 456320543Sdim return false; 457320543Sdim } 458320543Sdim 459320543Sdim bool GetValueForKeyAsString(llvm::StringRef key, ConstString &result, 460320543Sdim const char *default_val) const { 461320543Sdim bool success = GetValueForKeyAsString(key, result); 462320543Sdim if (!success) 463320543Sdim result.SetCString(default_val); 464320543Sdim return success; 465320543Sdim } 466320543Sdim 467320543Sdim bool GetValueForKeyAsDictionary(llvm::StringRef key, 468320543Sdim Dictionary *&result) const { 469320543Sdim result = nullptr; 470320543Sdim ObjectSP value_sp = GetValueForKey(key); 471320543Sdim if (value_sp.get()) { 472320543Sdim result = value_sp->GetAsDictionary(); 473320543Sdim return (result != nullptr); 474320543Sdim } 475320543Sdim return false; 476320543Sdim } 477320543Sdim 478320543Sdim bool GetValueForKeyAsArray(llvm::StringRef key, Array *&result) const { 479320543Sdim result = nullptr; 480320543Sdim ObjectSP value_sp = GetValueForKey(key); 481320543Sdim if (value_sp.get()) { 482320543Sdim result = value_sp->GetAsArray(); 483320543Sdim return (result != nullptr); 484320543Sdim } 485320543Sdim return false; 486320543Sdim } 487320543Sdim 488320543Sdim bool HasKey(llvm::StringRef key) const { 489320543Sdim ConstString key_cs(key); 490320543Sdim collection::const_iterator search = m_dict.find(key_cs); 491320543Sdim return search != m_dict.end(); 492320543Sdim } 493320543Sdim 494320543Sdim void AddItem(llvm::StringRef key, ObjectSP value_sp) { 495320543Sdim ConstString key_cs(key); 496320543Sdim m_dict[key_cs] = value_sp; 497320543Sdim } 498320543Sdim 499320543Sdim void AddIntegerItem(llvm::StringRef key, uint64_t value) { 500320543Sdim AddItem(key, std::make_shared<Integer>(value)); 501320543Sdim } 502320543Sdim 503320543Sdim void AddFloatItem(llvm::StringRef key, double value) { 504320543Sdim AddItem(key, std::make_shared<Float>(value)); 505320543Sdim } 506320543Sdim 507320543Sdim void AddStringItem(llvm::StringRef key, llvm::StringRef value) { 508320543Sdim AddItem(key, std::make_shared<String>(std::move(value))); 509320543Sdim } 510320543Sdim 511320543Sdim void AddBooleanItem(llvm::StringRef key, bool value) { 512320543Sdim AddItem(key, std::make_shared<Boolean>(value)); 513320543Sdim } 514320543Sdim 515360784Sdim void Serialize(llvm::json::OStream &s) const override; 516320543Sdim 517320543Sdim protected: 518320543Sdim typedef std::map<ConstString, ObjectSP> collection; 519320543Sdim collection m_dict; 520320543Sdim }; 521320543Sdim 522320543Sdim class Null : public Object { 523320543Sdim public: 524320543Sdim Null() : Object(lldb::eStructuredDataTypeNull) {} 525320543Sdim 526320543Sdim ~Null() override = default; 527320543Sdim 528320543Sdim bool IsValid() const override { return false; } 529320543Sdim 530360784Sdim void Serialize(llvm::json::OStream &s) const override; 531320543Sdim }; 532320543Sdim 533320543Sdim class Generic : public Object { 534320543Sdim public: 535320543Sdim explicit Generic(void *object = nullptr) 536320543Sdim : Object(lldb::eStructuredDataTypeGeneric), m_object(object) {} 537320543Sdim 538320543Sdim void SetValue(void *value) { m_object = value; } 539320543Sdim 540320543Sdim void *GetValue() const { return m_object; } 541320543Sdim 542320543Sdim bool IsValid() const override { return m_object != nullptr; } 543320543Sdim 544360784Sdim void Serialize(llvm::json::OStream &s) const override; 545320543Sdim 546320543Sdim private: 547320543Sdim void *m_object; 548320543Sdim }; 549320543Sdim 550320543Sdim static ObjectSP ParseJSON(std::string json_text); 551320543Sdim static ObjectSP ParseJSONFromFile(const FileSpec &file, Status &error); 552320543Sdim}; 553320543Sdim 554320543Sdim} // namespace lldb_private 555320543Sdim 556320543Sdim#endif // liblldb_StructuredData_h_ 557