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