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