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