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 
133 llvm::StringRef XMLNode::GetAttributeValue(const char *name,
134  const char *fail_value) const {
135  const char *attr_value = nullptr;
136 #if LLDB_ENABLE_LIBXML2
137 
138  if (IsValid())
139  attr_value = (const char *)xmlGetProp(m_node, (const xmlChar *)name);
140  else
141  attr_value = fail_value;
142 #else
143  attr_value = fail_value;
144 #endif
145  if (attr_value)
146  return llvm::StringRef(attr_value);
147  else
148  return llvm::StringRef();
149 }
150 
151 bool XMLNode::GetAttributeValueAsUnsigned(const char *name, uint64_t &value,
152  uint64_t fail_value, int base) const {
153  value = fail_value;
154  return llvm::to_integer(GetAttributeValue(name, ""), value, base);
155 }
156 
157 void XMLNode::ForEachChildNode(NodeCallback const &callback) const {
158 #if LLDB_ENABLE_LIBXML2
159  if (IsValid())
160  GetChild().ForEachSiblingNode(callback);
161 #endif
162 }
163 
164 void XMLNode::ForEachChildElement(NodeCallback const &callback) const {
165 #if LLDB_ENABLE_LIBXML2
166  XMLNode child = GetChild();
167  if (child)
168  child.ForEachSiblingElement(callback);
169 #endif
170 }
171 
173  NodeCallback const &callback) const {
174 #if LLDB_ENABLE_LIBXML2
175  XMLNode child = GetChild();
176  if (child)
177  child.ForEachSiblingElementWithName(name, callback);
178 #endif
179 }
180 
181 void XMLNode::ForEachAttribute(AttributeCallback const &callback) const {
182 #if LLDB_ENABLE_LIBXML2
183 
184  if (IsValid()) {
185  for (xmlAttrPtr attr = m_node->properties; attr != nullptr;
186  attr = attr->next) {
187  // check if name matches
188  if (attr->name) {
189  // check child is a text node
190  xmlNodePtr child = attr->children;
191  if (child->type == XML_TEXT_NODE) {
192  llvm::StringRef attr_value;
193  if (child->content)
194  attr_value = llvm::StringRef((const char *)child->content);
195  if (!callback(llvm::StringRef((const char *)attr->name), attr_value))
196  return;
197  }
198  }
199  }
200  }
201 #endif
202 }
203 
204 void XMLNode::ForEachSiblingNode(NodeCallback const &callback) const {
205 #if LLDB_ENABLE_LIBXML2
206 
207  if (IsValid()) {
208  // iterate through all siblings
209  for (xmlNodePtr node = m_node; node; node = node->next) {
210  if (!callback(XMLNode(node)))
211  return;
212  }
213  }
214 #endif
215 }
216 
217 void XMLNode::ForEachSiblingElement(NodeCallback const &callback) const {
218 #if LLDB_ENABLE_LIBXML2
219 
220  if (IsValid()) {
221  // iterate through all siblings
222  for (xmlNodePtr node = m_node; node; node = node->next) {
223  // we are looking for element nodes only
224  if (node->type != XML_ELEMENT_NODE)
225  continue;
226 
227  if (!callback(XMLNode(node)))
228  return;
229  }
230  }
231 #endif
232 }
233 
235  const char *name, NodeCallback const &callback) const {
236 #if LLDB_ENABLE_LIBXML2
237 
238  if (IsValid()) {
239  // iterate through all siblings
240  for (xmlNodePtr node = m_node; node; node = node->next) {
241  // we are looking for element nodes only
242  if (node->type != XML_ELEMENT_NODE)
243  continue;
244 
245  // If name is nullptr, we take all nodes of type "t", else just the ones
246  // whose name matches
247  if (name) {
248  if (strcmp((const char *)node->name, name) != 0)
249  continue; // Name mismatch, ignore this one
250  } else {
251  if (node->name)
252  continue; // nullptr name specified and this element has a name,
253  // ignore this one
254  }
255 
256  if (!callback(XMLNode(node)))
257  return;
258  }
259  }
260 #endif
261 }
262 
263 llvm::StringRef XMLNode::GetName() const {
264 #if LLDB_ENABLE_LIBXML2
265  if (IsValid()) {
266  if (m_node->name)
267  return llvm::StringRef((const char *)m_node->name);
268  }
269 #endif
270  return llvm::StringRef();
271 }
272 
274  text.clear();
275 #if LLDB_ENABLE_LIBXML2
276  if (IsValid()) {
277  bool success = false;
278  if (m_node->type == XML_ELEMENT_NODE) {
279  // check child is a text node
280  for (xmlNodePtr node = m_node->children; node != nullptr;
281  node = node->next) {
282  if (node->type == XML_TEXT_NODE) {
283  text.append((const char *)node->content);
284  success = true;
285  }
286  }
287  }
288  return success;
289  }
290 #endif
291  return false;
292 }
293 
294 bool XMLNode::GetElementTextAsUnsigned(uint64_t &value, uint64_t fail_value,
295  int base) const {
296  std::string text;
297 
298  value = fail_value;
299  return GetElementText(text) && llvm::to_integer(text, value, base);
300 }
301 
302 bool XMLNode::GetElementTextAsFloat(double &value, double fail_value) const {
303  std::string text;
304 
305  value = fail_value;
306  return GetElementText(text) && llvm::to_float(text, value);
307 }
308 
309 bool XMLNode::NameIs(const char *name) const {
310 #if LLDB_ENABLE_LIBXML2
311 
312  if (IsValid()) {
313  // In case we are looking for a nullptr name or an exact pointer match
314  if (m_node->name == (const xmlChar *)name)
315  return true;
316  if (m_node->name)
317  return strcmp((const char *)m_node->name, name) == 0;
318  }
319 #endif
320  return false;
321 }
322 
324  XMLNode result_node;
325 
326 #if LLDB_ENABLE_LIBXML2
328  name, [&result_node](const XMLNode &node) -> bool {
329  result_node = node;
330  // Stop iterating, we found the node we wanted
331  return false;
332  });
333 #endif
334 
335  return result_node;
336 }
337 
338 bool XMLNode::IsValid() const { return m_node != nullptr; }
339 
340 bool XMLNode::IsElement() const {
341 #if LLDB_ENABLE_LIBXML2
342  if (IsValid())
343  return m_node->type == XML_ELEMENT_NODE;
344 #endif
345  return false;
346 }
347 
349 #if LLDB_ENABLE_LIBXML2
350 
351  if (IsValid()) {
352  if (path.empty())
353  return *this;
354  else {
355  XMLNode node = FindFirstChildElementWithName(path[0].c_str());
356  const size_t n = path.size();
357  for (size_t i = 1; node && i < n; ++i)
358  node = node.FindFirstChildElementWithName(path[i].c_str());
359  return node;
360  }
361  }
362 #endif
363 
364  return XMLNode();
365 }
366 
367 #pragma mark-- ApplePropertyList
368 
369 ApplePropertyList::ApplePropertyList() : m_xml_doc(), m_dict_node() {}
370 
372  : m_xml_doc(), m_dict_node() {
373  ParseFile(path);
374 }
375 
377 
378 llvm::StringRef ApplePropertyList::GetErrors() const {
379  return m_xml_doc.GetErrors();
380 }
381 
382 bool ApplePropertyList::ParseFile(const char *path) {
383  if (m_xml_doc.ParseFile(path)) {
384  XMLNode plist = m_xml_doc.GetRootElement("plist");
385  if (plist) {
386  plist.ForEachChildElementWithName("dict",
387  [this](const XMLNode &dict) -> bool {
388  this->m_dict_node = dict;
389  return false; // Stop iterating
390  });
391  return (bool)m_dict_node;
392  }
393  }
394  return false;
395 }
396 
397 bool ApplePropertyList::IsValid() const { return (bool)m_dict_node; }
398 
400  std::string &value) const {
401  XMLNode value_node = GetValueNode(key);
402  if (value_node)
403  return ApplePropertyList::ExtractStringFromValueNode(value_node, value);
404  return false;
405 }
406 
407 XMLNode ApplePropertyList::GetValueNode(const char *key) const {
408  XMLNode value_node;
409 #if LLDB_ENABLE_LIBXML2
410 
411  if (IsValid()) {
413  "key", [key, &value_node](const XMLNode &key_node) -> bool {
414  std::string key_name;
415  if (key_node.GetElementText(key_name)) {
416  if (key_name == key) {
417  value_node = key_node.GetSibling();
418  while (value_node && !value_node.IsElement())
419  value_node = value_node.GetSibling();
420  return false; // Stop iterating
421  }
422  }
423  return true; // Keep iterating
424  });
425  }
426 #endif
427  return value_node;
428 }
429 
430 bool ApplePropertyList::ExtractStringFromValueNode(const XMLNode &node,
431  std::string &value) {
432  value.clear();
433 #if LLDB_ENABLE_LIBXML2
434  if (node.IsValid()) {
435  llvm::StringRef element_name = node.GetName();
436  if (element_name == "true" || element_name == "false") {
437  // The text value _is_ the element name itself...
438  value = element_name.str();
439  return true;
440  } else if (element_name == "dict" || element_name == "array")
441  return false; // dictionaries and arrays have no text value, so we fail
442  else
443  return node.GetElementText(value);
444  }
445 #endif
446  return false;
447 }
448 
449 #if LLDB_ENABLE_LIBXML2
450 
451 static StructuredData::ObjectSP CreatePlistValue(XMLNode node) {
452  llvm::StringRef element_name = node.GetName();
453  if (element_name == "array") {
454  std::shared_ptr<StructuredData::Array> array_sp(
455  new StructuredData::Array());
456  node.ForEachChildElement([&array_sp](const XMLNode &node) -> bool {
457  array_sp->AddItem(CreatePlistValue(node));
458  return true; // Keep iterating through all child elements of the array
459  });
460  return array_sp;
461  } else if (element_name == "dict") {
462  XMLNode key_node;
463  std::shared_ptr<StructuredData::Dictionary> dict_sp(
465  node.ForEachChildElement(
466  [&key_node, &dict_sp](const XMLNode &node) -> bool {
467  if (node.NameIs("key")) {
468  // This is a "key" element node
469  key_node = node;
470  } else {
471  // This is a value node
472  if (key_node) {
473  std::string key_name;
474  key_node.GetElementText(key_name);
475  dict_sp->AddItem(key_name, CreatePlistValue(node));
476  key_node.Clear();
477  }
478  }
479  return true; // Keep iterating through all child elements of the
480  // dictionary
481  });
482  return dict_sp;
483  } else if (element_name == "real") {
484  double value = 0.0;
485  node.GetElementTextAsFloat(value);
487  } else if (element_name == "integer") {
488  uint64_t value = 0;
489  node.GetElementTextAsUnsigned(value, 0, 0);
491  } else if ((element_name == "string") || (element_name == "data") ||
492  (element_name == "date")) {
493  std::string text;
494  node.GetElementText(text);
496  new StructuredData::String(std::move(text)));
497  } else if (element_name == "true") {
499  } else if (element_name == "false") {
501  }
503 }
504 #endif
505 
506 StructuredData::ObjectSP ApplePropertyList::GetStructuredData() {
507  StructuredData::ObjectSP root_sp;
508 #if LLDB_ENABLE_LIBXML2
509  if (IsValid()) {
510  return CreatePlistValue(m_dict_node);
511  }
512 #endif
513  return root_sp;
514 }
lldb_private::XMLNode::XMLNode
XMLNode()
lldb_private::XMLNode::IsElement
bool IsElement() const
Definition: XML.cpp:340
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:302
lldb_private::ApplePropertyList::ParseFile
bool ParseFile(const char *path)
Definition: XML.cpp:382
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:172
lldb_private::XMLNode::ForEachChildNode
void ForEachChildNode(NodeCallback const &callback) const
Definition: XML.cpp:157
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:273
lldb_private::XMLNode::GetName
llvm::StringRef GetName() const
Definition: XML.cpp:263
lldb_private::XMLNode::GetChild
XMLNode GetChild() const
Definition: XML.cpp:121
lldb_private::XMLNode::NameIs
bool NameIs(const char *name) const
Definition: XML.cpp:309
lldb_private::XMLNode::ForEachSiblingElement
void ForEachSiblingElement(NodeCallback const &callback) const
Definition: XML.cpp:217
lldb_private::XMLDocument::m_errors
StreamString m_errors
Definition: XML.h:142
lldb_private::ApplePropertyList::IsValid
bool IsValid() const
Definition: XML.cpp:397
lldb_private::ApplePropertyList::GetValueAsString
bool GetValueAsString(const char *key, std::string &value) const
Definition: XML.cpp:399
lldb_private::StructuredData::Boolean
Definition: StructuredData.h:319
lldb_private::XMLNode::ForEachAttribute
void ForEachAttribute(AttributeCallback const &callback) const
Definition: XML.cpp:181
lldb_private::XMLNode::GetElementForPath
XMLNode GetElementForPath(const NamePath &path)
Definition: XML.cpp:348
lldb_private::StructuredData::String
Definition: StructuredData.h:336
lldb_private::StructuredData::Null
Definition: StructuredData.h:522
lldb_private::XMLDocument::GetRootElement
XMLNode GetRootElement(const char *required_name=nullptr)
Definition: XML.cpp:63
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:151
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::GetAttributeValue
llvm::StringRef GetAttributeValue(const char *name, const char *fail_value=nullptr) const
Definition: XML.cpp:133
lldb_private::XMLNode::ForEachChildElement
void ForEachChildElement(NodeCallback const &callback) const
Definition: XML.cpp:164
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:294
string
string(SUBSTRING ${p} 10 -1 pStripped) if($
Definition: Plugins/CMakeLists.txt:40
lldb_private::ApplePropertyList::GetErrors
llvm::StringRef GetErrors() const
Definition: XML.cpp:378
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:234
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:430
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:323
lldb_private::ApplePropertyList::GetValueNode
XMLNode GetValueNode(const char *key) const
Definition: XML.cpp:407
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:369
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:338
lldb_private::XMLNode::ForEachSiblingNode
void ForEachSiblingNode(NodeCallback const &callback) const
Definition: XML.cpp:204
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