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