1*f2a8bccfSPavel Labath //===---------------------StructuredData.cpp ---------------------*- C++-*-===// 2*f2a8bccfSPavel Labath // 3*f2a8bccfSPavel Labath // The LLVM Compiler Infrastructure 4*f2a8bccfSPavel Labath // 5*f2a8bccfSPavel Labath // This file is distributed under the University of Illinois Open Source 6*f2a8bccfSPavel Labath // License. See LICENSE.TXT for details. 7*f2a8bccfSPavel Labath // 8*f2a8bccfSPavel Labath //===----------------------------------------------------------------------===// 9*f2a8bccfSPavel Labath 10*f2a8bccfSPavel Labath #include "lldb/Utility/StructuredData.h" 11*f2a8bccfSPavel Labath #include "lldb/Utility/DataBuffer.h" 12*f2a8bccfSPavel Labath #include "lldb/Utility/FileSpec.h" 13*f2a8bccfSPavel Labath #include "lldb/Utility/JSON.h" 14*f2a8bccfSPavel Labath #include "lldb/Utility/Status.h" 15*f2a8bccfSPavel Labath #include "lldb/Utility/Stream.h" // for Stream 16*f2a8bccfSPavel Labath #include "lldb/Utility/StreamString.h" 17*f2a8bccfSPavel Labath #include "llvm/ADT/STLExtras.h" // for make_unique 18*f2a8bccfSPavel Labath #include <cerrno> 19*f2a8bccfSPavel Labath #include <cstdlib> 20*f2a8bccfSPavel Labath #include <inttypes.h> 21*f2a8bccfSPavel Labath #include <limits> // for numeric_limits 22*f2a8bccfSPavel Labath 23*f2a8bccfSPavel Labath using namespace lldb_private; 24*f2a8bccfSPavel Labath 25*f2a8bccfSPavel Labath //---------------------------------------------------------------------- 26*f2a8bccfSPavel Labath // Functions that use a JSONParser to parse JSON into StructuredData 27*f2a8bccfSPavel Labath //---------------------------------------------------------------------- 28*f2a8bccfSPavel Labath static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser); 29*f2a8bccfSPavel Labath static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser); 30*f2a8bccfSPavel Labath static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser); 31*f2a8bccfSPavel Labath 32*f2a8bccfSPavel Labath StructuredData::ObjectSP 33*f2a8bccfSPavel Labath StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Status &error) { 34*f2a8bccfSPavel Labath StructuredData::ObjectSP return_sp; 35*f2a8bccfSPavel Labath if (!input_spec.Exists()) { 36*f2a8bccfSPavel Labath error.SetErrorStringWithFormatv("input file {0} does not exist.", 37*f2a8bccfSPavel Labath input_spec); 38*f2a8bccfSPavel Labath return return_sp; 39*f2a8bccfSPavel Labath } 40*f2a8bccfSPavel Labath 41*f2a8bccfSPavel Labath auto buffer_or_error = llvm::MemoryBuffer::getFile(input_spec.GetPath()); 42*f2a8bccfSPavel Labath if (!buffer_or_error) { 43*f2a8bccfSPavel Labath error.SetErrorStringWithFormatv("could not open input file: {0} - {1}.", 44*f2a8bccfSPavel Labath input_spec.GetPath(), 45*f2a8bccfSPavel Labath buffer_or_error.getError().message()); 46*f2a8bccfSPavel Labath return return_sp; 47*f2a8bccfSPavel Labath } 48*f2a8bccfSPavel Labath 49*f2a8bccfSPavel Labath JSONParser json_parser(buffer_or_error.get()->getBuffer()); 50*f2a8bccfSPavel Labath return_sp = ParseJSONValue(json_parser); 51*f2a8bccfSPavel Labath return return_sp; 52*f2a8bccfSPavel Labath } 53*f2a8bccfSPavel Labath 54*f2a8bccfSPavel Labath static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser) { 55*f2a8bccfSPavel Labath // The "JSONParser::Token::ObjectStart" token should have already been 56*f2a8bccfSPavel Labath // consumed by the time this function is called 57*f2a8bccfSPavel Labath auto dict_up = llvm::make_unique<StructuredData::Dictionary>(); 58*f2a8bccfSPavel Labath 59*f2a8bccfSPavel Labath std::string value; 60*f2a8bccfSPavel Labath std::string key; 61*f2a8bccfSPavel Labath while (1) { 62*f2a8bccfSPavel Labath JSONParser::Token token = json_parser.GetToken(value); 63*f2a8bccfSPavel Labath 64*f2a8bccfSPavel Labath if (token == JSONParser::Token::String) { 65*f2a8bccfSPavel Labath key.swap(value); 66*f2a8bccfSPavel Labath token = json_parser.GetToken(value); 67*f2a8bccfSPavel Labath if (token == JSONParser::Token::Colon) { 68*f2a8bccfSPavel Labath StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser); 69*f2a8bccfSPavel Labath if (value_sp) 70*f2a8bccfSPavel Labath dict_up->AddItem(key, value_sp); 71*f2a8bccfSPavel Labath else 72*f2a8bccfSPavel Labath break; 73*f2a8bccfSPavel Labath } 74*f2a8bccfSPavel Labath } else if (token == JSONParser::Token::ObjectEnd) { 75*f2a8bccfSPavel Labath return StructuredData::ObjectSP(dict_up.release()); 76*f2a8bccfSPavel Labath } else if (token == JSONParser::Token::Comma) { 77*f2a8bccfSPavel Labath continue; 78*f2a8bccfSPavel Labath } else { 79*f2a8bccfSPavel Labath break; 80*f2a8bccfSPavel Labath } 81*f2a8bccfSPavel Labath } 82*f2a8bccfSPavel Labath return StructuredData::ObjectSP(); 83*f2a8bccfSPavel Labath } 84*f2a8bccfSPavel Labath 85*f2a8bccfSPavel Labath static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser) { 86*f2a8bccfSPavel Labath // The "JSONParser::Token::ObjectStart" token should have already been 87*f2a8bccfSPavel Labath // consumed 88*f2a8bccfSPavel Labath // by the time this function is called 89*f2a8bccfSPavel Labath auto array_up = llvm::make_unique<StructuredData::Array>(); 90*f2a8bccfSPavel Labath 91*f2a8bccfSPavel Labath std::string value; 92*f2a8bccfSPavel Labath std::string key; 93*f2a8bccfSPavel Labath while (1) { 94*f2a8bccfSPavel Labath StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser); 95*f2a8bccfSPavel Labath if (value_sp) 96*f2a8bccfSPavel Labath array_up->AddItem(value_sp); 97*f2a8bccfSPavel Labath else 98*f2a8bccfSPavel Labath break; 99*f2a8bccfSPavel Labath 100*f2a8bccfSPavel Labath JSONParser::Token token = json_parser.GetToken(value); 101*f2a8bccfSPavel Labath if (token == JSONParser::Token::Comma) { 102*f2a8bccfSPavel Labath continue; 103*f2a8bccfSPavel Labath } else if (token == JSONParser::Token::ArrayEnd) { 104*f2a8bccfSPavel Labath return StructuredData::ObjectSP(array_up.release()); 105*f2a8bccfSPavel Labath } else { 106*f2a8bccfSPavel Labath break; 107*f2a8bccfSPavel Labath } 108*f2a8bccfSPavel Labath } 109*f2a8bccfSPavel Labath return StructuredData::ObjectSP(); 110*f2a8bccfSPavel Labath } 111*f2a8bccfSPavel Labath 112*f2a8bccfSPavel Labath static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser) { 113*f2a8bccfSPavel Labath std::string value; 114*f2a8bccfSPavel Labath const JSONParser::Token token = json_parser.GetToken(value); 115*f2a8bccfSPavel Labath switch (token) { 116*f2a8bccfSPavel Labath case JSONParser::Token::ObjectStart: 117*f2a8bccfSPavel Labath return ParseJSONObject(json_parser); 118*f2a8bccfSPavel Labath 119*f2a8bccfSPavel Labath case JSONParser::Token::ArrayStart: 120*f2a8bccfSPavel Labath return ParseJSONArray(json_parser); 121*f2a8bccfSPavel Labath 122*f2a8bccfSPavel Labath case JSONParser::Token::Integer: { 123*f2a8bccfSPavel Labath uint64_t uval; 124*f2a8bccfSPavel Labath if (llvm::to_integer(value, uval, 0)) 125*f2a8bccfSPavel Labath return std::make_shared<StructuredData::Integer>(uval); 126*f2a8bccfSPavel Labath } break; 127*f2a8bccfSPavel Labath 128*f2a8bccfSPavel Labath case JSONParser::Token::Float: { 129*f2a8bccfSPavel Labath double val; 130*f2a8bccfSPavel Labath if (llvm::to_float(value, val)) 131*f2a8bccfSPavel Labath return std::make_shared<StructuredData::Float>(val); 132*f2a8bccfSPavel Labath } break; 133*f2a8bccfSPavel Labath 134*f2a8bccfSPavel Labath case JSONParser::Token::String: 135*f2a8bccfSPavel Labath return std::make_shared<StructuredData::String>(value); 136*f2a8bccfSPavel Labath 137*f2a8bccfSPavel Labath case JSONParser::Token::True: 138*f2a8bccfSPavel Labath case JSONParser::Token::False: 139*f2a8bccfSPavel Labath return std::make_shared<StructuredData::Boolean>(token == 140*f2a8bccfSPavel Labath JSONParser::Token::True); 141*f2a8bccfSPavel Labath 142*f2a8bccfSPavel Labath case JSONParser::Token::Null: 143*f2a8bccfSPavel Labath return std::make_shared<StructuredData::Null>(); 144*f2a8bccfSPavel Labath 145*f2a8bccfSPavel Labath default: 146*f2a8bccfSPavel Labath break; 147*f2a8bccfSPavel Labath } 148*f2a8bccfSPavel Labath return StructuredData::ObjectSP(); 149*f2a8bccfSPavel Labath } 150*f2a8bccfSPavel Labath 151*f2a8bccfSPavel Labath StructuredData::ObjectSP StructuredData::ParseJSON(std::string json_text) { 152*f2a8bccfSPavel Labath JSONParser json_parser(json_text.c_str()); 153*f2a8bccfSPavel Labath StructuredData::ObjectSP object_sp = ParseJSONValue(json_parser); 154*f2a8bccfSPavel Labath return object_sp; 155*f2a8bccfSPavel Labath } 156*f2a8bccfSPavel Labath 157*f2a8bccfSPavel Labath StructuredData::ObjectSP 158*f2a8bccfSPavel Labath StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) { 159*f2a8bccfSPavel Labath if (this->GetType() == lldb::eStructuredDataTypeDictionary) { 160*f2a8bccfSPavel Labath std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.'); 161*f2a8bccfSPavel Labath std::string key = match.first.str(); 162*f2a8bccfSPavel Labath ObjectSP value = this->GetAsDictionary()->GetValueForKey(key); 163*f2a8bccfSPavel Labath if (value.get()) { 164*f2a8bccfSPavel Labath // Do we have additional words to descend? If not, return the 165*f2a8bccfSPavel Labath // value we're at right now. 166*f2a8bccfSPavel Labath if (match.second.empty()) { 167*f2a8bccfSPavel Labath return value; 168*f2a8bccfSPavel Labath } else { 169*f2a8bccfSPavel Labath return value->GetObjectForDotSeparatedPath(match.second); 170*f2a8bccfSPavel Labath } 171*f2a8bccfSPavel Labath } 172*f2a8bccfSPavel Labath return ObjectSP(); 173*f2a8bccfSPavel Labath } 174*f2a8bccfSPavel Labath 175*f2a8bccfSPavel Labath if (this->GetType() == lldb::eStructuredDataTypeArray) { 176*f2a8bccfSPavel Labath std::pair<llvm::StringRef, llvm::StringRef> match = path.split('['); 177*f2a8bccfSPavel Labath if (match.second.size() == 0) { 178*f2a8bccfSPavel Labath return this->shared_from_this(); 179*f2a8bccfSPavel Labath } 180*f2a8bccfSPavel Labath errno = 0; 181*f2a8bccfSPavel Labath uint64_t val = strtoul(match.second.str().c_str(), NULL, 10); 182*f2a8bccfSPavel Labath if (errno == 0) { 183*f2a8bccfSPavel Labath return this->GetAsArray()->GetItemAtIndex(val); 184*f2a8bccfSPavel Labath } 185*f2a8bccfSPavel Labath return ObjectSP(); 186*f2a8bccfSPavel Labath } 187*f2a8bccfSPavel Labath 188*f2a8bccfSPavel Labath return this->shared_from_this(); 189*f2a8bccfSPavel Labath } 190*f2a8bccfSPavel Labath 191*f2a8bccfSPavel Labath void StructuredData::Object::DumpToStdout(bool pretty_print) const { 192*f2a8bccfSPavel Labath StreamString stream; 193*f2a8bccfSPavel Labath Dump(stream, pretty_print); 194*f2a8bccfSPavel Labath llvm::outs() << stream.GetString(); 195*f2a8bccfSPavel Labath } 196*f2a8bccfSPavel Labath 197*f2a8bccfSPavel Labath void StructuredData::Array::Dump(Stream &s, bool pretty_print) const { 198*f2a8bccfSPavel Labath bool first = true; 199*f2a8bccfSPavel Labath s << "["; 200*f2a8bccfSPavel Labath if (pretty_print) { 201*f2a8bccfSPavel Labath s << "\n"; 202*f2a8bccfSPavel Labath s.IndentMore(); 203*f2a8bccfSPavel Labath } 204*f2a8bccfSPavel Labath for (const auto &item_sp : m_items) { 205*f2a8bccfSPavel Labath if (first) { 206*f2a8bccfSPavel Labath first = false; 207*f2a8bccfSPavel Labath } else { 208*f2a8bccfSPavel Labath s << ","; 209*f2a8bccfSPavel Labath if (pretty_print) 210*f2a8bccfSPavel Labath s << "\n"; 211*f2a8bccfSPavel Labath } 212*f2a8bccfSPavel Labath 213*f2a8bccfSPavel Labath if (pretty_print) 214*f2a8bccfSPavel Labath s.Indent(); 215*f2a8bccfSPavel Labath item_sp->Dump(s, pretty_print); 216*f2a8bccfSPavel Labath } 217*f2a8bccfSPavel Labath if (pretty_print) { 218*f2a8bccfSPavel Labath s.IndentLess(); 219*f2a8bccfSPavel Labath s.EOL(); 220*f2a8bccfSPavel Labath s.Indent(); 221*f2a8bccfSPavel Labath } 222*f2a8bccfSPavel Labath s << "]"; 223*f2a8bccfSPavel Labath } 224*f2a8bccfSPavel Labath 225*f2a8bccfSPavel Labath void StructuredData::Integer::Dump(Stream &s, bool pretty_print) const { 226*f2a8bccfSPavel Labath s.Printf("%" PRIu64, m_value); 227*f2a8bccfSPavel Labath } 228*f2a8bccfSPavel Labath 229*f2a8bccfSPavel Labath void StructuredData::Float::Dump(Stream &s, bool pretty_print) const { 230*f2a8bccfSPavel Labath s.Printf("%lg", m_value); 231*f2a8bccfSPavel Labath } 232*f2a8bccfSPavel Labath 233*f2a8bccfSPavel Labath void StructuredData::Boolean::Dump(Stream &s, bool pretty_print) const { 234*f2a8bccfSPavel Labath if (m_value == true) 235*f2a8bccfSPavel Labath s.PutCString("true"); 236*f2a8bccfSPavel Labath else 237*f2a8bccfSPavel Labath s.PutCString("false"); 238*f2a8bccfSPavel Labath } 239*f2a8bccfSPavel Labath 240*f2a8bccfSPavel Labath void StructuredData::String::Dump(Stream &s, bool pretty_print) const { 241*f2a8bccfSPavel Labath std::string quoted; 242*f2a8bccfSPavel Labath const size_t strsize = m_value.size(); 243*f2a8bccfSPavel Labath for (size_t i = 0; i < strsize; ++i) { 244*f2a8bccfSPavel Labath char ch = m_value[i]; 245*f2a8bccfSPavel Labath if (ch == '"' || ch == '\\') 246*f2a8bccfSPavel Labath quoted.push_back('\\'); 247*f2a8bccfSPavel Labath quoted.push_back(ch); 248*f2a8bccfSPavel Labath } 249*f2a8bccfSPavel Labath s.Printf("\"%s\"", quoted.c_str()); 250*f2a8bccfSPavel Labath } 251*f2a8bccfSPavel Labath 252*f2a8bccfSPavel Labath void StructuredData::Dictionary::Dump(Stream &s, bool pretty_print) const { 253*f2a8bccfSPavel Labath bool first = true; 254*f2a8bccfSPavel Labath s << "{"; 255*f2a8bccfSPavel Labath if (pretty_print) { 256*f2a8bccfSPavel Labath s << "\n"; 257*f2a8bccfSPavel Labath s.IndentMore(); 258*f2a8bccfSPavel Labath } 259*f2a8bccfSPavel Labath for (const auto &pair : m_dict) { 260*f2a8bccfSPavel Labath if (first) 261*f2a8bccfSPavel Labath first = false; 262*f2a8bccfSPavel Labath else { 263*f2a8bccfSPavel Labath s << ","; 264*f2a8bccfSPavel Labath if (pretty_print) 265*f2a8bccfSPavel Labath s << "\n"; 266*f2a8bccfSPavel Labath } 267*f2a8bccfSPavel Labath if (pretty_print) 268*f2a8bccfSPavel Labath s.Indent(); 269*f2a8bccfSPavel Labath s << "\"" << pair.first.AsCString() << "\" : "; 270*f2a8bccfSPavel Labath pair.second->Dump(s, pretty_print); 271*f2a8bccfSPavel Labath } 272*f2a8bccfSPavel Labath if (pretty_print) { 273*f2a8bccfSPavel Labath s.IndentLess(); 274*f2a8bccfSPavel Labath s.EOL(); 275*f2a8bccfSPavel Labath s.Indent(); 276*f2a8bccfSPavel Labath } 277*f2a8bccfSPavel Labath s << "}"; 278*f2a8bccfSPavel Labath } 279*f2a8bccfSPavel Labath 280*f2a8bccfSPavel Labath void StructuredData::Null::Dump(Stream &s, bool pretty_print) const { 281*f2a8bccfSPavel Labath s << "null"; 282*f2a8bccfSPavel Labath } 283*f2a8bccfSPavel Labath 284*f2a8bccfSPavel Labath void StructuredData::Generic::Dump(Stream &s, bool pretty_print) const { 285*f2a8bccfSPavel Labath s << "0x" << m_object; 286*f2a8bccfSPavel Labath } 287