1 //===-- XML.cpp -------------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include <stdlib.h> /* atof */
12 #include "lldb/Host/StringConvert.h"
13 #include "lldb/Host/XML.h"
16 using namespace lldb_private;
18 #pragma mark-- XMLDocument
20 XMLDocument::XMLDocument() : m_document(nullptr) {}
22 XMLDocument::~XMLDocument() { Clear(); }
24 void XMLDocument::Clear() {
25 #if defined(LIBXML2_DEFINED)
27 xmlDocPtr doc = m_document;
34 bool XMLDocument::IsValid() const { return m_document != nullptr; }
36 void XMLDocument::ErrorCallback(void *ctx, const char *format, ...) {
37 XMLDocument *document = (XMLDocument *)ctx;
39 va_start(args, format);
40 document->m_errors.PrintfVarArg(format, args);
41 document->m_errors.EOL();
45 bool XMLDocument::ParseFile(const char *path) {
46 #if defined(LIBXML2_DEFINED)
48 xmlSetGenericErrorFunc((void *)this, XMLDocument::ErrorCallback);
49 m_document = xmlParseFile(path);
50 xmlSetGenericErrorFunc(nullptr, nullptr);
55 bool XMLDocument::ParseMemory(const char *xml, size_t xml_length,
57 #if defined(LIBXML2_DEFINED)
59 xmlSetGenericErrorFunc((void *)this, XMLDocument::ErrorCallback);
60 m_document = xmlReadMemory(xml, (int)xml_length, url, nullptr, 0);
61 xmlSetGenericErrorFunc(nullptr, nullptr);
66 XMLNode XMLDocument::GetRootElement(const char *required_name) {
67 #if defined(LIBXML2_DEFINED)
69 XMLNode root_node(xmlDocGetRootElement(m_document));
71 llvm::StringRef actual_name = root_node.GetName();
72 if (actual_name == required_name)
82 llvm::StringRef XMLDocument::GetErrors() const { return m_errors.GetString(); }
84 bool XMLDocument::XMLEnabled() {
85 #if defined(LIBXML2_DEFINED)
92 #pragma mark-- XMLNode
94 XMLNode::XMLNode() : m_node(nullptr) {}
96 XMLNode::XMLNode(XMLNodeImpl node) : m_node(node) {}
98 XMLNode::~XMLNode() {}
100 void XMLNode::Clear() { m_node = nullptr; }
102 XMLNode XMLNode::GetParent() const {
103 #if defined(LIBXML2_DEFINED)
105 return XMLNode(m_node->parent);
113 XMLNode XMLNode::GetSibling() const {
114 #if defined(LIBXML2_DEFINED)
116 return XMLNode(m_node->next);
124 XMLNode XMLNode::GetChild() const {
125 #if defined(LIBXML2_DEFINED)
128 return XMLNode(m_node->children);
136 llvm::StringRef XMLNode::GetAttributeValue(const char *name,
137 const char *fail_value) const {
138 const char *attr_value = NULL;
139 #if defined(LIBXML2_DEFINED)
142 attr_value = (const char *)xmlGetProp(m_node, (const xmlChar *)name);
144 attr_value = fail_value;
146 attr_value = fail_value;
149 return llvm::StringRef(attr_value);
151 return llvm::StringRef();
154 void XMLNode::ForEachChildNode(NodeCallback const &callback) const {
155 #if defined(LIBXML2_DEFINED)
157 GetChild().ForEachSiblingNode(callback);
161 void XMLNode::ForEachChildElement(NodeCallback const &callback) const {
162 #if defined(LIBXML2_DEFINED)
163 XMLNode child = GetChild();
165 child.ForEachSiblingElement(callback);
169 void XMLNode::ForEachChildElementWithName(const char *name,
170 NodeCallback const &callback) const {
171 #if defined(LIBXML2_DEFINED)
172 XMLNode child = GetChild();
174 child.ForEachSiblingElementWithName(name, callback);
178 void XMLNode::ForEachAttribute(AttributeCallback const &callback) const {
179 #if defined(LIBXML2_DEFINED)
182 for (xmlAttrPtr attr = m_node->properties; attr != nullptr;
184 // check if name matches
186 // check child is a text node
187 xmlNodePtr child = attr->children;
188 if (child->type == XML_TEXT_NODE) {
189 llvm::StringRef attr_value;
191 attr_value = llvm::StringRef((const char *)child->content);
192 if (callback(llvm::StringRef((const char *)attr->name), attr_value) ==
202 void XMLNode::ForEachSiblingNode(NodeCallback const &callback) const {
203 #if defined(LIBXML2_DEFINED)
206 // iterate through all siblings
207 for (xmlNodePtr node = m_node; node; node = node->next) {
208 if (callback(XMLNode(node)) == false)
215 void XMLNode::ForEachSiblingElement(NodeCallback const &callback) const {
216 #if defined(LIBXML2_DEFINED)
219 // iterate through all siblings
220 for (xmlNodePtr node = m_node; node; node = node->next) {
221 // we are looking for element nodes only
222 if (node->type != XML_ELEMENT_NODE)
225 if (callback(XMLNode(node)) == false)
232 void XMLNode::ForEachSiblingElementWithName(
233 const char *name, NodeCallback const &callback) const {
234 #if defined(LIBXML2_DEFINED)
237 // iterate through all siblings
238 for (xmlNodePtr node = m_node; node; node = node->next) {
239 // we are looking for element nodes only
240 if (node->type != XML_ELEMENT_NODE)
243 // If name is nullptr, we take all nodes of type "t", else
244 // just the ones whose name matches
246 if (strcmp((const char *)node->name, name) != 0)
247 continue; // Name mismatch, ignore this one
250 continue; // nullptr name specified and this element has a name,
254 if (callback(XMLNode(node)) == false)
261 llvm::StringRef XMLNode::GetName() const {
262 #if defined(LIBXML2_DEFINED)
265 return llvm::StringRef((const char *)m_node->name);
268 return llvm::StringRef();
271 bool XMLNode::GetElementText(std::string &text) const {
273 #if defined(LIBXML2_DEFINED)
275 bool success = false;
276 if (m_node->type == XML_ELEMENT_NODE) {
277 // check child is a text node
278 for (xmlNodePtr node = m_node->children; node != nullptr;
280 if (node->type == XML_TEXT_NODE) {
281 text.append((const char *)node->content);
292 bool XMLNode::GetElementTextAsUnsigned(uint64_t &value, uint64_t fail_value,
294 bool success = false;
295 #if defined(LIBXML2_DEFINED)
298 if (GetElementText(text))
299 value = StringConvert::ToUInt64(text.c_str(), fail_value, base, &success);
307 bool XMLNode::GetElementTextAsFloat(double &value, double fail_value) const {
308 bool success = false;
309 #if defined(LIBXML2_DEFINED)
312 if (GetElementText(text)) {
313 value = atof(text.c_str());
323 bool XMLNode::NameIs(const char *name) const {
324 #if defined(LIBXML2_DEFINED)
327 // In case we are looking for a nullptr name or an exact pointer match
328 if (m_node->name == (const xmlChar *)name)
331 return strcmp((const char *)m_node->name, name) == 0;
337 XMLNode XMLNode::FindFirstChildElementWithName(const char *name) const {
340 #if defined(LIBXML2_DEFINED)
341 ForEachChildElementWithName(
342 name, [&result_node, name](const XMLNode &node) -> bool {
344 // Stop iterating, we found the node we wanted
352 bool XMLNode::IsValid() const { return m_node != nullptr; }
354 bool XMLNode::IsElement() const {
355 #if defined(LIBXML2_DEFINED)
357 return m_node->type == XML_ELEMENT_NODE;
362 XMLNode XMLNode::GetElementForPath(const NamePath &path) {
363 #if defined(LIBXML2_DEFINED)
369 XMLNode node = FindFirstChildElementWithName(path[0].c_str());
370 const size_t n = path.size();
371 for (size_t i = 1; node && i < n; ++i)
372 node = node.FindFirstChildElementWithName(path[i].c_str());
381 #pragma mark-- ApplePropertyList
383 ApplePropertyList::ApplePropertyList() : m_xml_doc(), m_dict_node() {}
385 ApplePropertyList::ApplePropertyList(const char *path)
386 : m_xml_doc(), m_dict_node() {
390 ApplePropertyList::~ApplePropertyList() {}
392 llvm::StringRef ApplePropertyList::GetErrors() const {
393 return m_xml_doc.GetErrors();
396 bool ApplePropertyList::ParseFile(const char *path) {
397 if (m_xml_doc.ParseFile(path)) {
398 XMLNode plist = m_xml_doc.GetRootElement("plist");
400 plist.ForEachChildElementWithName("dict",
401 [this](const XMLNode &dict) -> bool {
402 this->m_dict_node = dict;
403 return false; // Stop iterating
405 return (bool)m_dict_node;
411 bool ApplePropertyList::IsValid() const { return (bool)m_dict_node; }
413 bool ApplePropertyList::GetValueAsString(const char *key,
414 std::string &value) const {
415 XMLNode value_node = GetValueNode(key);
417 return ApplePropertyList::ExtractStringFromValueNode(value_node, value);
421 XMLNode ApplePropertyList::GetValueNode(const char *key) const {
423 #if defined(LIBXML2_DEFINED)
426 m_dict_node.ForEachChildElementWithName(
427 "key", [key, &value_node](const XMLNode &key_node) -> bool {
428 std::string key_name;
429 if (key_node.GetElementText(key_name)) {
430 if (key_name.compare(key) == 0) {
431 value_node = key_node.GetSibling();
432 while (value_node && !value_node.IsElement())
433 value_node = value_node.GetSibling();
434 return false; // Stop iterating
437 return true; // Keep iterating
444 bool ApplePropertyList::ExtractStringFromValueNode(const XMLNode &node,
445 std::string &value) {
447 #if defined(LIBXML2_DEFINED)
448 if (node.IsValid()) {
449 llvm::StringRef element_name = node.GetName();
450 if (element_name == "true" || element_name == "false") {
451 // The text value _is_ the element name itself...
452 value = element_name.str();
454 } else if (element_name == "dict" || element_name == "array")
455 return false; // dictionaries and arrays have no text value, so we fail
457 return node.GetElementText(value);
463 #if defined(LIBXML2_DEFINED)
467 StructuredData::ObjectSP CreatePlistValue(XMLNode node) {
468 llvm::StringRef element_name = node.GetName();
469 if (element_name == "array") {
470 std::shared_ptr<StructuredData::Array> array_sp(
471 new StructuredData::Array());
472 node.ForEachChildElement([&array_sp](const XMLNode &node) -> bool {
473 array_sp->AddItem(CreatePlistValue(node));
474 return true; // Keep iterating through all child elements of the array
477 } else if (element_name == "dict") {
479 std::shared_ptr<StructuredData::Dictionary> dict_sp(
480 new StructuredData::Dictionary());
481 node.ForEachChildElement(
482 [&key_node, &dict_sp](const XMLNode &node) -> bool {
483 if (node.NameIs("key")) {
484 // This is a "key" element node
487 // This is a value node
489 std::string key_name;
490 key_node.GetElementText(key_name);
491 dict_sp->AddItem(key_name, CreatePlistValue(node));
495 return true; // Keep iterating through all child elements of the
499 } else if (element_name == "real") {
501 node.GetElementTextAsFloat(value);
502 return StructuredData::ObjectSP(new StructuredData::Float(value));
503 } else if (element_name == "integer") {
505 node.GetElementTextAsUnsigned(value, 0, 0);
506 return StructuredData::ObjectSP(new StructuredData::Integer(value));
507 } else if ((element_name == "string") || (element_name == "data") ||
508 (element_name == "date")) {
510 node.GetElementText(text);
511 return StructuredData::ObjectSP(
512 new StructuredData::String(std::move(text)));
513 } else if (element_name == "true") {
514 return StructuredData::ObjectSP(new StructuredData::Boolean(true));
515 } else if (element_name == "false") {
516 return StructuredData::ObjectSP(new StructuredData::Boolean(false));
518 return StructuredData::ObjectSP(new StructuredData::Null());
523 StructuredData::ObjectSP ApplePropertyList::GetStructuredData() {
524 StructuredData::ObjectSP root_sp;
525 #if defined(LIBXML2_DEFINED)
527 return CreatePlistValue(m_dict_node);