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