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