1 //===---------------------StructuredData.cpp ---------------------*- 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Utility/StructuredData.h" 10 #include "lldb/Utility/DataBuffer.h" 11 #include "lldb/Utility/FileSpec.h" 12 #include "lldb/Utility/Status.h" 13 #include "lldb/Utility/StreamString.h" 14 #include "llvm/ADT/STLExtras.h" 15 #include "llvm/Support/MemoryBuffer.h" 16 #include <cerrno> 17 #include <cstdlib> 18 #include <inttypes.h> 19 #include <limits> 20 21 using namespace lldb_private; 22 using namespace llvm; 23 24 static StructuredData::ObjectSP ParseJSONValue(json::Value &value); 25 static StructuredData::ObjectSP ParseJSONObject(json::Object *object); 26 static StructuredData::ObjectSP ParseJSONArray(json::Array *array); 27 28 StructuredData::ObjectSP StructuredData::ParseJSON(std::string json_text) { 29 llvm::Expected<json::Value> value = json::parse(json_text); 30 if (!value) { 31 llvm::consumeError(value.takeError()); 32 return nullptr; 33 } 34 return ParseJSONValue(*value); 35 } 36 37 StructuredData::ObjectSP 38 StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Status &error) { 39 StructuredData::ObjectSP return_sp; 40 41 auto buffer_or_error = llvm::MemoryBuffer::getFile(input_spec.GetPath()); 42 if (!buffer_or_error) { 43 error.SetErrorStringWithFormatv("could not open input file: {0} - {1}.", 44 input_spec.GetPath(), 45 buffer_or_error.getError().message()); 46 return return_sp; 47 } 48 return ParseJSON(buffer_or_error.get()->getBuffer().str()); 49 } 50 51 static StructuredData::ObjectSP ParseJSONValue(json::Value &value) { 52 if (json::Object *O = value.getAsObject()) 53 return ParseJSONObject(O); 54 55 if (json::Array *A = value.getAsArray()) 56 return ParseJSONArray(A); 57 58 std::string s; 59 if (json::fromJSON(value, s)) 60 return std::make_shared<StructuredData::String>(s); 61 62 bool b; 63 if (json::fromJSON(value, b)) 64 return std::make_shared<StructuredData::Boolean>(b); 65 66 int64_t i; 67 if (json::fromJSON(value, i)) 68 return std::make_shared<StructuredData::Integer>(i); 69 70 double d; 71 if (json::fromJSON(value, d)) 72 return std::make_shared<StructuredData::Float>(d); 73 74 return StructuredData::ObjectSP(); 75 } 76 77 static StructuredData::ObjectSP ParseJSONObject(json::Object *object) { 78 auto dict_up = std::make_unique<StructuredData::Dictionary>(); 79 for (auto &KV : *object) { 80 StringRef key = KV.first; 81 json::Value value = KV.second; 82 if (StructuredData::ObjectSP value_sp = ParseJSONValue(value)) 83 dict_up->AddItem(key, value_sp); 84 } 85 return dict_up; 86 } 87 88 static StructuredData::ObjectSP ParseJSONArray(json::Array *array) { 89 auto array_up = std::make_unique<StructuredData::Array>(); 90 for (json::Value &value : *array) { 91 if (StructuredData::ObjectSP value_sp = ParseJSONValue(value)) 92 array_up->AddItem(value_sp); 93 } 94 return array_up; 95 } 96 97 StructuredData::ObjectSP 98 StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) { 99 if (this->GetType() == lldb::eStructuredDataTypeDictionary) { 100 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.'); 101 std::string key = match.first.str(); 102 ObjectSP value = this->GetAsDictionary()->GetValueForKey(key); 103 if (value.get()) { 104 // Do we have additional words to descend? If not, return the value 105 // we're at right now. 106 if (match.second.empty()) { 107 return value; 108 } else { 109 return value->GetObjectForDotSeparatedPath(match.second); 110 } 111 } 112 return ObjectSP(); 113 } 114 115 if (this->GetType() == lldb::eStructuredDataTypeArray) { 116 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('['); 117 if (match.second.empty()) { 118 return this->shared_from_this(); 119 } 120 errno = 0; 121 uint64_t val = strtoul(match.second.str().c_str(), nullptr, 10); 122 if (errno == 0) { 123 return this->GetAsArray()->GetItemAtIndex(val); 124 } 125 return ObjectSP(); 126 } 127 128 return this->shared_from_this(); 129 } 130 131 void StructuredData::Object::DumpToStdout(bool pretty_print) const { 132 json::OStream stream(llvm::outs(), pretty_print ? 2 : 0); 133 Serialize(stream); 134 } 135 136 void StructuredData::Array::Serialize(json::OStream &s) const { 137 s.arrayBegin(); 138 for (const auto &item_sp : m_items) { 139 item_sp->Serialize(s); 140 } 141 s.arrayEnd(); 142 } 143 144 void StructuredData::Integer::Serialize(json::OStream &s) const { 145 s.value(static_cast<int64_t>(m_value)); 146 } 147 148 void StructuredData::Float::Serialize(json::OStream &s) const { 149 s.value(m_value); 150 } 151 152 void StructuredData::Boolean::Serialize(json::OStream &s) const { 153 s.value(m_value); 154 } 155 156 void StructuredData::String::Serialize(json::OStream &s) const { 157 s.value(m_value); 158 } 159 160 void StructuredData::Dictionary::Serialize(json::OStream &s) const { 161 s.objectBegin(); 162 for (const auto &pair : m_dict) { 163 s.attributeBegin(pair.first.AsCString()); 164 pair.second->Serialize(s); 165 s.attributeEnd(); 166 } 167 s.objectEnd(); 168 } 169 170 void StructuredData::Null::Serialize(json::OStream &s) const { 171 s.value(nullptr); 172 } 173 174 void StructuredData::Generic::Serialize(json::OStream &s) const { 175 s.value(llvm::formatv("{0:X}", m_object)); 176 } 177