LLDB  mainline
XML.cpp
Go to the documentation of this file.
1 //===-- XML.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/Host/Config.h"
10 #include "lldb/Host/XML.h"
11 
12 using namespace lldb;
13 using namespace lldb_private;
14 
15 #pragma mark-- XMLDocument
16 
17 XMLDocument::XMLDocument() = default;
18 
19 XMLDocument::~XMLDocument() { Clear(); }
20 
21 void XMLDocument::Clear() {
22 #if LLDB_ENABLE_LIBXML2
23  if (m_document) {
24  xmlDocPtr doc = m_document;
25  m_document = nullptr;
26  xmlFreeDoc(doc);
27  }
28 #endif
29 }
30 
31 bool XMLDocument::IsValid() const { return m_document != nullptr; }
32 
33 void XMLDocument::ErrorCallback(void *ctx, const char *format, ...) {
34  XMLDocument *document = (XMLDocument *)ctx;
35  va_list args;
36  va_start(args, format);
37  document->m_errors.PrintfVarArg(format, args);
38  document->m_errors.EOL();
39  va_end(args);
40 }
41 
42 bool XMLDocument::ParseFile(const char *path) {
43 #if LLDB_ENABLE_LIBXML2
44  Clear();
45  xmlSetGenericErrorFunc((void *)this, XMLDocument::ErrorCallback);
46  m_document = xmlParseFile(path);
47  xmlSetGenericErrorFunc(nullptr, nullptr);
48 #endif
49  return IsValid();
50 }
51 
52 bool XMLDocument::ParseMemory(const char *xml, size_t xml_length,
53  const char *url) {
54 #if LLDB_ENABLE_LIBXML2
55  Clear();
56  xmlSetGenericErrorFunc((void *)this, XMLDocument::ErrorCallback);
57  m_document = xmlReadMemory(xml, (int)xml_length, url, nullptr, 0);
58  xmlSetGenericErrorFunc(nullptr, nullptr);
59 #endif
60  return IsValid();
61 }
62 
63 XMLNode XMLDocument::GetRootElement(const char *required_name) {
64 #if LLDB_ENABLE_LIBXML2
65  if (IsValid()) {
66  XMLNode root_node(xmlDocGetRootElement(m_document));
67  if (required_name) {
68  llvm::StringRef actual_name = root_node.GetName();
69  if (actual_name == required_name)
70  return root_node;
71  } else {
72  return root_node;
73  }
74  }
75 #endif
76  return XMLNode();
77 }
78 
79 llvm::StringRef XMLDocument::GetErrors() const { return m_errors.GetString(); }
80 
81 bool XMLDocument::XMLEnabled() {
82 #if LLDB_ENABLE_LIBXML2
83  return true;
84 #else
85  return false;
86 #endif
87 }
88 
89 #pragma mark-- XMLNode
90 
91 XMLNode::XMLNode() = default;
92 
93 XMLNode::XMLNode(XMLNodeImpl node) : m_node(node) {}
94 
95 XMLNode::~XMLNode() = default;
96 
97 void XMLNode::Clear() { m_node = nullptr; }
98 
100 #if LLDB_ENABLE_LIBXML2
101  if (IsValid())
102  return XMLNode(m_node->parent);
103  else
104  return XMLNode();
105 #else
106  return XMLNode();
107 #endif
108 }
109 
111 #if LLDB_ENABLE_LIBXML2
112  if (IsValid())
113  return XMLNode(m_node->next);
114  else
115  return XMLNode();
116 #else
117  return XMLNode();
118 #endif
119 }
120 
122 #if LLDB_ENABLE_LIBXML2
123 
124  if (IsValid())
125  return XMLNode(m_node->children);
126  else
127  return XMLNode();
128 #else
129  return XMLNode();
130 #endif
131 }
132 
134  const char *fail_value) const {
135  std::string attr_value;
136 #if LLDB_ENABLE_LIBXML2
137  if (IsValid()) {
138  xmlChar *value = xmlGetProp(m_node, (const xmlChar *)name);
139  if (value) {
140  attr_value = (const char *)value;
141  xmlFree(value);
142  }
143  } else {
144  if (fail_value)
145  attr_value = fail_value;
146  }
147 #else
148  if (fail_value)
149  attr_value = fail_value;
150 #endif
151  return attr_value;
152 }
153 
154 bool XMLNode::GetAttributeValueAsUnsigned(const char *name, uint64_t &value,
155  uint64_t fail_value, int base) const {
156  value = fail_value;
157  return llvm::to_integer(GetAttributeValue(name, ""), value, base);
158 }
159 
160 void XMLNode::ForEachChildNode(NodeCallback const &callback) const {
161 #if LLDB_ENABLE_LIBXML2
162  if (IsValid())
163  GetChild().ForEachSiblingNode(callback);
164 #endif
165 }
166 
167 void XMLNode::ForEachChildElement(NodeCallback const &callback) const {
168 #if LLDB_ENABLE_LIBXML2
169  XMLNode child = GetChild();
170  if (child)
171  child.ForEachSiblingElement(callback);
172 #endif
173 }
174 
176  NodeCallback const &callback) const {
177 #if LLDB_ENABLE_LIBXML2
178  XMLNode child = GetChild();
179  if (child)
180  child.ForEachSiblingElementWithName(name, callback);
181 #endif
182 }
183 
184 void XMLNode::ForEachAttribute(AttributeCallback const &callback) const {
185 #if LLDB_ENABLE_LIBXML2
186 
187  if (IsValid()) {
188  for (xmlAttrPtr attr = m_node->properties; attr != nullptr;
189  attr = attr->next) {
190  // check if name matches
191  if (attr->name) {
192  // check child is a text node
193  xmlNodePtr child = attr->children;
194  if (child->type == XML_TEXT_NODE) {
195  llvm::StringRef attr_value;
196  if (child->content)
197  attr_value = llvm::StringRef((const char *)child->content);
198  if (!callback(llvm::StringRef((const char *)attr->name), attr_value))
199  return;
200  }
201  }
202  }
203  }
204 #endif
205 }
206 
207 void XMLNode::ForEachSiblingNode(NodeCallback const &callback) const {
208 #if LLDB_ENABLE_LIBXML2
209 
210  if (IsValid()) {
211  // iterate through all siblings
212  for (xmlNodePtr node = m_node; node; node = node->next) {
213  if (!callback(XMLNode(node)))
214  return;
215  }
216  }
217 #endif
218 }
219 
220 void XMLNode::ForEachSiblingElement(NodeCallback const &callback) const {
221 #if LLDB_ENABLE_LIBXML2
222 
223  if (IsValid()) {
224  // iterate through all siblings
225  for (xmlNodePtr node = m_node; node; node = node->next) {
226  // we are looking for element nodes only
227  if (node->type != XML_ELEMENT_NODE)
228  continue;
229 
230  if (!callback(XMLNode(node)))
231  return;
232  }
233  }
234 #endif
235 }
236 
238  const char *name, NodeCallback const &callback) const {
239 #if LLDB_ENABLE_LIBXML2
240 
241  if (IsValid()) {
242  // iterate through all siblings
243  for (xmlNodePtr node = m_node; node; node = node->next) {
244  // we are looking for element nodes only
245  if (node->type != XML_ELEMENT_NODE)
246  continue;
247 
248  // If name is nullptr, we take all nodes of type "t", else just the ones
249  // whose name matches
250  if (name) {
251  if (strcmp((const char *)node->name, name) != 0)
252  continue; // Name mismatch, ignore this one
253  } else {
254  if (node->name)
255  continue; // nullptr name specified and this element has a name,
256  // ignore this one
257  }
258 
259  if (!callback(XMLNode(node)))
260  return;
261  }
262  }
263 #endif
264 }
265 
266 llvm::StringRef XMLNode::GetName() const {
267 #if LLDB_ENABLE_LIBXML2
268  if (IsValid()) {
269  if (m_node->name)
270  return llvm::StringRef((const char *)m_node->name);
271  }
272 #endif
273  return llvm::StringRef();
274 }
275 
277  text.clear();
278 #if LLDB_ENABLE_LIBXML2
279  if (IsValid()) {
280  bool success = false;
281  if (m_node->type == XML_ELEMENT_NODE) {
282  // check child is a text node
283  for (xmlNodePtr node = m_node->children; node != nullptr;
284  node = node->next) {
285  if (node->type == XML_TEXT_NODE) {
286  text.append((const char *)node->content);
287  success = true;
288  }
289  }
290  }
291  return success;
292  }
293 #endif
294  return false;
295 }
296 
297 bool XMLNode::GetElementTextAsUnsigned(uint64_t &value, uint64_t fail_value,
298  int base) const {
299  std::string text;
300 
301  value = fail_value;
302  return GetElementText(text) && llvm::to_integer(text, value, base);
303 }
304 
305 bool XMLNode::GetElementTextAsFloat(double &value, double fail_value) const {
306  std::string text;
307 
308  value = fail_value;
309  return GetElementText(text) && llvm::to_float(text, value);
310 }
311 
312 bool XMLNode::NameIs(const char *name) const {
313 #if LLDB_ENABLE_LIBXML2
314 
315  if (IsValid()) {
316  // In case we are looking for a nullptr name or an exact pointer match
317  if (m_node->name == (const xmlChar *)name)
318  return true;
319  if (m_node->name)
320  return strcmp((const char *)m_node->name, name) == 0;
321  }
322 #endif
323  return false;
324 }
325 
327  XMLNode result_node;
328 
329 #if LLDB_ENABLE_LIBXML2
331  name, [&result_node](const XMLNode &node) -> bool {
332  result_node = node;
333  // Stop iterating, we found the node we wanted
334  return false;
335  });
336 #endif
337 
338  return result_node;
339 }
340 
341 bool XMLNode::IsValid() const { return m_node != nullptr; }
342 
343 bool XMLNode::IsElement() const {
344 #if LLDB_ENABLE_LIBXML2
345  if (IsValid())
346  return m_node->type == XML_ELEMENT_NODE;
347 #endif
348  return false;
349 }
350 
352 #if LLDB_ENABLE_LIBXML2
353 
354  if (IsValid()) {
355  if (path.empty())
356  return *this;
357  else {
358  XMLNode node = FindFirstChildElementWithName(path[0].c_str());
359  const size_t n = path.size();
360  for (size_t i = 1; node && i < n; ++i)
361  node = node.FindFirstChildElementWithName(path[i].c_str());
362  return node;
363  }
364  }
365 #endif
366 
367  return XMLNode();
368 }
369 
370 #pragma mark-- ApplePropertyList
371 
372 ApplePropertyList::ApplePropertyList() : m_xml_doc(), m_dict_node() {}
373 
375  : m_xml_doc(), m_dict_node() {
376  ParseFile(path);
377 }
378 
380 
381 llvm::StringRef ApplePropertyList::GetErrors() const {
382  return m_xml_doc.GetErrors();
383 }
384 
385 bool ApplePropertyList::ParseFile(const char *path) {
386  if (m_xml_doc.ParseFile(path)) {
387  XMLNode plist = m_xml_doc.GetRootElement("plist");
388  if (plist) {
389  plist.ForEachChildElementWithName("dict",
390  [this](const XMLNode &dict) -> bool {
391  this->m_dict_node = dict;
392  return false; // Stop iterating
393  });
394  return (bool)m_dict_node;
395  }
396  }
397  return false;
398 }
399 
400 bool ApplePropertyList::IsValid() const { return (bool)m_dict_node; }
401 
403  std::string &value) const {
404  XMLNode value_node = GetValueNode(key);
405  if (value_node)
406  return ApplePropertyList::ExtractStringFromValueNode(value_node, value);
407  return false;
408 }
409 
410 XMLNode ApplePropertyList::GetValueNode(const char *key) const {
411  XMLNode value_node;
412 #if LLDB_ENABLE_LIBXML2
413 
414  if (IsValid()) {
416  "key", [key, &value_node](const XMLNode &key_node) -> bool {
417  std::string key_name;
418  if (key_node.GetElementText(key_name)) {
419  if (key_name == key) {
420  value_node = key_node.GetSibling();
421  while (value_node && !value_node.IsElement())
422  value_node = value_node.GetSibling();
423  return false; // Stop iterating
424  }
425  }
426  return true; // Keep iterating
427  });
428  }
429 #endif
430  return value_node;
431 }
432 
433 bool ApplePropertyList::ExtractStringFromValueNode(const XMLNode &node,
434  std::string &value) {
435  value.clear();
436 #if LLDB_ENABLE_LIBXML2
437  if (node.IsValid()) {
438  llvm::StringRef element_name = node.GetName();
439  if (element_name == "true" || element_name == "false") {
440  // The text value _is_ the element name itself...
441  value = element_name.str();
442  return true;
443  } else if (element_name == "dict" || element_name == "array")
444  return false; // dictionaries and arrays have no text value, so we fail
445  else
446  return node.GetElementText(value);
447  }
448 #endif
449  return false;
450 }
451 
452 #if LLDB_ENABLE_LIBXML2
453 
454 static StructuredData::ObjectSP CreatePlistValue(XMLNode node) {
455  llvm::StringRef element_name = node.GetName();
456  if (element_name == "array") {
457  std::shared_ptr<StructuredData::Array> array_sp(
458  new StructuredData::Array());
459  node.ForEachChildElement([&array_sp](const XMLNode &node) -> bool {
460  array_sp->AddItem(CreatePlistValue(node));
461  return true; // Keep iterating through all child elements of the array
462  });
463  return array_sp;
464  } else if (element_name == "dict") {
465  XMLNode key_node;
466  std::shared_ptr<StructuredData::Dictionary> dict_sp(
468  node.ForEachChildElement(
469  [&key_node, &dict_sp](const XMLNode &node) -> bool {
470  if (node.NameIs("key")) {
471  // This is a "key" element node
472  key_node = node;
473  } else {
474  // This is a value node
475  if (key_node) {
476  std::string key_name;
477  key_node.GetElementText(key_name);
478  dict_sp->AddItem(key_name, CreatePlistValue(node));
479  key_node.Clear();
480  }
481  }
482  return true; // Keep iterating through all child elements of the
483  // dictionary
484  });
485  return dict_sp;
486  } else if (element_name == "real") {
487  double value = 0.0;
488  node.GetElementTextAsFloat(value);
490  } else if (element_name == "integer") {
491  uint64_t value = 0;
492  node.GetElementTextAsUnsigned(value, 0, 0);
494  } else if ((element_name == "string") || (element_name == "data") ||
495  (element_name == "date")) {
496  std::string text;
497  node.GetElementText(text);
499  new StructuredData::String(std::move(text)));
500  } else if (element_name == "true") {
502  } else if (element_name == "false") {
504  }
506 }
507 #endif
508 
509 StructuredData::ObjectSP ApplePropertyList::GetStructuredData() {
510  StructuredData::ObjectSP root_sp;
511 #if LLDB_ENABLE_LIBXML2
512  if (IsValid()) {
513  return CreatePlistValue(m_dict_node);
514  }
515 #endif
516  return root_sp;
517 }
lldb_private::XMLNode::XMLNode
XMLNode()
lldb_private::XMLNode::IsElement
bool IsElement() const
Definition: XML.cpp:343
lldb_private::StructuredData::Dictionary
Definition: StructuredData.h:352
lldb_private::XMLNode::GetElementTextAsFloat
bool GetElementTextAsFloat(double &value, double fail_value=0.0) const
Definition: XML.cpp:305
lldb_private::ApplePropertyList::ParseFile
bool ParseFile(const char *path)
Definition: XML.cpp:385
lldb_private::StructuredData::Array
Definition: StructuredData.h:165
lldb_private::ApplePropertyList::m_dict_node
XMLNode m_dict_node
Definition: XML.h:177
lldb_private::NamePath
std::vector< std::string > NamePath
Definition: XML.h:38
lldb_private::StructuredData::Integer
Definition: StructuredData.h:285
lldb_private::XMLDocument
Definition: XML.h:113
lldb_private::XMLNode::ForEachChildElementWithName
void ForEachChildElementWithName(const char *name, NodeCallback const &callback) const
Definition: XML.cpp:175
lldb_private::XMLNode::ForEachChildNode
void ForEachChildNode(NodeCallback const &callback) const
Definition: XML.cpp:160
lldb_private::XMLNode
Definition: XML.h:46
lldb_private::XMLDocument::ParseFile
bool ParseFile(const char *path)
Definition: XML.cpp:42
lldb_private::XMLNode::GetElementText
bool GetElementText(std::string &text) const
Definition: XML.cpp:276
lldb_private::XMLNode::GetName
llvm::StringRef GetName() const
Definition: XML.cpp:266
lldb_private::XMLNode::GetChild
XMLNode GetChild() const
Definition: XML.cpp:121
lldb_private::XMLNode::NameIs
bool NameIs(const char *name) const
Definition: XML.cpp:312
lldb_private::XMLNode::ForEachSiblingElement
void ForEachSiblingElement(NodeCallback const &callback) const
Definition: XML.cpp:220
lldb_private::XMLDocument::m_errors
StreamString m_errors
Definition: XML.h:142
lldb_private::ApplePropertyList::IsValid
bool IsValid() const
Definition: XML.cpp:400
lldb_private::ApplePropertyList::GetValueAsString
bool GetValueAsString(const char *key, std::string &value) const
Definition: XML.cpp:402
lldb_private::StructuredData::Boolean
Definition: StructuredData.h:319
lldb_private::XMLNode::ForEachAttribute
void ForEachAttribute(AttributeCallback const &callback) const
Definition: XML.cpp:184
lldb_private::XMLNode::GetElementForPath
XMLNode GetElementForPath(const NamePath &path)
Definition: XML.cpp:351
lldb_private::StructuredData::String
Definition: StructuredData.h:336
lldb_private::StructuredData::Null
Definition: StructuredData.h:532
lldb_private::XMLDocument::GetRootElement
XMLNode GetRootElement(const char *required_name=nullptr)
Definition: XML.cpp:63
lldb_private::XMLNode::GetAttributeValue
std::string GetAttributeValue(const char *name, const char *fail_value=nullptr) const
Definition: XML.cpp:133
lldb_private::AttributeCallback
std::function< bool(const llvm::StringRef &name, const llvm::StringRef &value)> AttributeCallback
Definition: XML.h:44
lldb_private::XMLNode::GetAttributeValueAsUnsigned
bool GetAttributeValueAsUnsigned(const char *name, uint64_t &value, uint64_t fail_value=0, int base=0) const
Definition: XML.cpp:154
lldb_private::XMLNode::Clear
void Clear()
Definition: XML.cpp:97
lldb_private::StructuredData::ObjectSP
std::shared_ptr< Object > ObjectSP
Definition: StructuredData.h:59
lldb_private::XMLNode::ForEachChildElement
void ForEachChildElement(NodeCallback const &callback) const
Definition: XML.cpp:167
lldb_private::Stream::PrintfVarArg
size_t size_t PrintfVarArg(const char *format, va_list args)
Definition: Stream.cpp:116
lldb_private::XMLNode::GetElementTextAsUnsigned
bool GetElementTextAsUnsigned(uint64_t &value, uint64_t fail_value=0, int base=0) const
Definition: XML.cpp:297
string
string(SUBSTRING ${p} 10 -1 pStripped) if($
Definition: Plugins/CMakeLists.txt:40
lldb_private::ApplePropertyList::GetErrors
llvm::StringRef GetErrors() const
Definition: XML.cpp:381
lldb_private::NodeCallback
std::function< bool(const XMLNode &node)> NodeCallback
Definition: XML.h:41
lldb_private::XMLNode::ForEachSiblingElementWithName
void ForEachSiblingElementWithName(const char *name, NodeCallback const &callback) const
Definition: XML.cpp:237
lldb_private::StructuredData::Float
Definition: StructuredData.h:302
lldb_private::Stream::EOL
size_t EOL()
Output and End of Line character to the stream.
Definition: Stream.cpp:128
lldb_private::ApplePropertyList::~ApplePropertyList
~ApplePropertyList()
XML.h
lldb_private::ApplePropertyList::m_xml_doc
XMLDocument m_xml_doc
Definition: XML.h:176
lldb_private::ApplePropertyList::ExtractStringFromValueNode
static bool ExtractStringFromValueNode(const XMLNode &node, std::string &value)
Definition: XML.cpp:433
lldb_private::XMLNode::GetParent
XMLNode GetParent() const
Definition: XML.cpp:99
lldb_private::XMLNodeImpl
void * XMLNodeImpl
Definition: XML.h:34
lldb_private::XMLNode::FindFirstChildElementWithName
XMLNode FindFirstChildElementWithName(const char *name) const
Definition: XML.cpp:326
lldb_private::ApplePropertyList::GetValueNode
XMLNode GetValueNode(const char *key) const
Definition: XML.cpp:410
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
lldb_private::ApplePropertyList::ApplePropertyList
ApplePropertyList()
Definition: XML.cpp:372
lldb_private::XMLNode::m_node
XMLNodeImpl m_node
Definition: XML.h:110
lldb
Definition: SBAddress.h:15
lldb_private::XMLNode::IsValid
bool IsValid() const
Definition: XML.cpp:341
lldb_private::XMLNode::ForEachSiblingNode
void ForEachSiblingNode(NodeCallback const &callback) const
Definition: XML.cpp:207
lldb_private::XMLDocument::GetErrors
llvm::StringRef GetErrors() const
Definition: XML.cpp:79
lldb_private::XMLNode::~XMLNode
~XMLNode()
lldb_private::XMLNode::GetSibling
XMLNode GetSibling() const
Definition: XML.cpp:110