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