15ffd83dbSDimitry Andric //===-- XML.cpp -----------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
9480093f4SDimitry Andric #include "lldb/Host/Config.h"
100b57cec5SDimitry Andric #include "lldb/Host/XML.h"
110b57cec5SDimitry Andric
12*06c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h"
13*06c3fb27SDimitry Andric
140b57cec5SDimitry Andric using namespace lldb;
150b57cec5SDimitry Andric using namespace lldb_private;
160b57cec5SDimitry Andric
170b57cec5SDimitry Andric #pragma mark-- XMLDocument
180b57cec5SDimitry Andric
19fe6060f1SDimitry Andric XMLDocument::XMLDocument() = default;
200b57cec5SDimitry Andric
~XMLDocument()210b57cec5SDimitry Andric XMLDocument::~XMLDocument() { Clear(); }
220b57cec5SDimitry Andric
Clear()230b57cec5SDimitry Andric void XMLDocument::Clear() {
24480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
250b57cec5SDimitry Andric if (m_document) {
260b57cec5SDimitry Andric xmlDocPtr doc = m_document;
270b57cec5SDimitry Andric m_document = nullptr;
280b57cec5SDimitry Andric xmlFreeDoc(doc);
290b57cec5SDimitry Andric }
300b57cec5SDimitry Andric #endif
310b57cec5SDimitry Andric }
320b57cec5SDimitry Andric
IsValid() const330b57cec5SDimitry Andric bool XMLDocument::IsValid() const { return m_document != nullptr; }
340b57cec5SDimitry Andric
ErrorCallback(void * ctx,const char * format,...)350b57cec5SDimitry Andric void XMLDocument::ErrorCallback(void *ctx, const char *format, ...) {
360b57cec5SDimitry Andric XMLDocument *document = (XMLDocument *)ctx;
370b57cec5SDimitry Andric va_list args;
380b57cec5SDimitry Andric va_start(args, format);
390b57cec5SDimitry Andric document->m_errors.PrintfVarArg(format, args);
400b57cec5SDimitry Andric document->m_errors.EOL();
410b57cec5SDimitry Andric va_end(args);
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric
ParseFile(const char * path)440b57cec5SDimitry Andric bool XMLDocument::ParseFile(const char *path) {
45480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
460b57cec5SDimitry Andric Clear();
470b57cec5SDimitry Andric xmlSetGenericErrorFunc((void *)this, XMLDocument::ErrorCallback);
480b57cec5SDimitry Andric m_document = xmlParseFile(path);
490b57cec5SDimitry Andric xmlSetGenericErrorFunc(nullptr, nullptr);
500b57cec5SDimitry Andric #endif
510b57cec5SDimitry Andric return IsValid();
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric
ParseMemory(const char * xml,size_t xml_length,const char * url)540b57cec5SDimitry Andric bool XMLDocument::ParseMemory(const char *xml, size_t xml_length,
550b57cec5SDimitry Andric const char *url) {
56480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
570b57cec5SDimitry Andric Clear();
580b57cec5SDimitry Andric xmlSetGenericErrorFunc((void *)this, XMLDocument::ErrorCallback);
590b57cec5SDimitry Andric m_document = xmlReadMemory(xml, (int)xml_length, url, nullptr, 0);
600b57cec5SDimitry Andric xmlSetGenericErrorFunc(nullptr, nullptr);
610b57cec5SDimitry Andric #endif
620b57cec5SDimitry Andric return IsValid();
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric
GetRootElement(const char * required_name)650b57cec5SDimitry Andric XMLNode XMLDocument::GetRootElement(const char *required_name) {
66480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
670b57cec5SDimitry Andric if (IsValid()) {
680b57cec5SDimitry Andric XMLNode root_node(xmlDocGetRootElement(m_document));
690b57cec5SDimitry Andric if (required_name) {
700b57cec5SDimitry Andric llvm::StringRef actual_name = root_node.GetName();
710b57cec5SDimitry Andric if (actual_name == required_name)
720b57cec5SDimitry Andric return root_node;
730b57cec5SDimitry Andric } else {
740b57cec5SDimitry Andric return root_node;
750b57cec5SDimitry Andric }
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric #endif
780b57cec5SDimitry Andric return XMLNode();
790b57cec5SDimitry Andric }
800b57cec5SDimitry Andric
GetErrors() const810b57cec5SDimitry Andric llvm::StringRef XMLDocument::GetErrors() const { return m_errors.GetString(); }
820b57cec5SDimitry Andric
XMLEnabled()830b57cec5SDimitry Andric bool XMLDocument::XMLEnabled() {
84480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
850b57cec5SDimitry Andric return true;
860b57cec5SDimitry Andric #else
870b57cec5SDimitry Andric return false;
880b57cec5SDimitry Andric #endif
890b57cec5SDimitry Andric }
900b57cec5SDimitry Andric
910b57cec5SDimitry Andric #pragma mark-- XMLNode
920b57cec5SDimitry Andric
93fe6060f1SDimitry Andric XMLNode::XMLNode() = default;
940b57cec5SDimitry Andric
XMLNode(XMLNodeImpl node)950b57cec5SDimitry Andric XMLNode::XMLNode(XMLNodeImpl node) : m_node(node) {}
960b57cec5SDimitry Andric
97fe6060f1SDimitry Andric XMLNode::~XMLNode() = default;
980b57cec5SDimitry Andric
Clear()990b57cec5SDimitry Andric void XMLNode::Clear() { m_node = nullptr; }
1000b57cec5SDimitry Andric
GetParent() const1010b57cec5SDimitry Andric XMLNode XMLNode::GetParent() const {
102480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
1030b57cec5SDimitry Andric if (IsValid())
1040b57cec5SDimitry Andric return XMLNode(m_node->parent);
1050b57cec5SDimitry Andric else
1060b57cec5SDimitry Andric return XMLNode();
1070b57cec5SDimitry Andric #else
1080b57cec5SDimitry Andric return XMLNode();
1090b57cec5SDimitry Andric #endif
1100b57cec5SDimitry Andric }
1110b57cec5SDimitry Andric
GetSibling() const1120b57cec5SDimitry Andric XMLNode XMLNode::GetSibling() const {
113480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
1140b57cec5SDimitry Andric if (IsValid())
1150b57cec5SDimitry Andric return XMLNode(m_node->next);
1160b57cec5SDimitry Andric else
1170b57cec5SDimitry Andric return XMLNode();
1180b57cec5SDimitry Andric #else
1190b57cec5SDimitry Andric return XMLNode();
1200b57cec5SDimitry Andric #endif
1210b57cec5SDimitry Andric }
1220b57cec5SDimitry Andric
GetChild() const1230b57cec5SDimitry Andric XMLNode XMLNode::GetChild() const {
124480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
1250b57cec5SDimitry Andric
1260b57cec5SDimitry Andric if (IsValid())
1270b57cec5SDimitry Andric return XMLNode(m_node->children);
1280b57cec5SDimitry Andric else
1290b57cec5SDimitry Andric return XMLNode();
1300b57cec5SDimitry Andric #else
1310b57cec5SDimitry Andric return XMLNode();
1320b57cec5SDimitry Andric #endif
1330b57cec5SDimitry Andric }
1340b57cec5SDimitry Andric
GetAttributeValue(const char * name,const char * fail_value) const13504eeddc0SDimitry Andric std::string XMLNode::GetAttributeValue(const char *name,
1360b57cec5SDimitry Andric const char *fail_value) const {
13704eeddc0SDimitry Andric std::string attr_value;
138480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
13904eeddc0SDimitry Andric if (IsValid()) {
14004eeddc0SDimitry Andric xmlChar *value = xmlGetProp(m_node, (const xmlChar *)name);
14104eeddc0SDimitry Andric if (value) {
14204eeddc0SDimitry Andric attr_value = (const char *)value;
14304eeddc0SDimitry Andric xmlFree(value);
14404eeddc0SDimitry Andric }
14504eeddc0SDimitry Andric } else {
14604eeddc0SDimitry Andric if (fail_value)
1470b57cec5SDimitry Andric attr_value = fail_value;
14804eeddc0SDimitry Andric }
1490b57cec5SDimitry Andric #else
15004eeddc0SDimitry Andric if (fail_value)
1510b57cec5SDimitry Andric attr_value = fail_value;
1520b57cec5SDimitry Andric #endif
15304eeddc0SDimitry Andric return attr_value;
1540b57cec5SDimitry Andric }
1550b57cec5SDimitry Andric
GetAttributeValueAsUnsigned(const char * name,uint64_t & value,uint64_t fail_value,int base) const1560b57cec5SDimitry Andric bool XMLNode::GetAttributeValueAsUnsigned(const char *name, uint64_t &value,
1570b57cec5SDimitry Andric uint64_t fail_value, int base) const {
158349cc55cSDimitry Andric value = fail_value;
159349cc55cSDimitry Andric return llvm::to_integer(GetAttributeValue(name, ""), value, base);
1600b57cec5SDimitry Andric }
1610b57cec5SDimitry Andric
ForEachChildNode(NodeCallback const & callback) const1620b57cec5SDimitry Andric void XMLNode::ForEachChildNode(NodeCallback const &callback) const {
163480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
1640b57cec5SDimitry Andric if (IsValid())
1650b57cec5SDimitry Andric GetChild().ForEachSiblingNode(callback);
1660b57cec5SDimitry Andric #endif
1670b57cec5SDimitry Andric }
1680b57cec5SDimitry Andric
ForEachChildElement(NodeCallback const & callback) const1690b57cec5SDimitry Andric void XMLNode::ForEachChildElement(NodeCallback const &callback) const {
170480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
1710b57cec5SDimitry Andric XMLNode child = GetChild();
1720b57cec5SDimitry Andric if (child)
1730b57cec5SDimitry Andric child.ForEachSiblingElement(callback);
1740b57cec5SDimitry Andric #endif
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric
ForEachChildElementWithName(const char * name,NodeCallback const & callback) const1770b57cec5SDimitry Andric void XMLNode::ForEachChildElementWithName(const char *name,
1780b57cec5SDimitry Andric NodeCallback const &callback) const {
179480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
1800b57cec5SDimitry Andric XMLNode child = GetChild();
1810b57cec5SDimitry Andric if (child)
1820b57cec5SDimitry Andric child.ForEachSiblingElementWithName(name, callback);
1830b57cec5SDimitry Andric #endif
1840b57cec5SDimitry Andric }
1850b57cec5SDimitry Andric
ForEachAttribute(AttributeCallback const & callback) const1860b57cec5SDimitry Andric void XMLNode::ForEachAttribute(AttributeCallback const &callback) const {
187480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
1880b57cec5SDimitry Andric
1890b57cec5SDimitry Andric if (IsValid()) {
1900b57cec5SDimitry Andric for (xmlAttrPtr attr = m_node->properties; attr != nullptr;
1910b57cec5SDimitry Andric attr = attr->next) {
1920b57cec5SDimitry Andric // check if name matches
1930b57cec5SDimitry Andric if (attr->name) {
1940b57cec5SDimitry Andric // check child is a text node
1950b57cec5SDimitry Andric xmlNodePtr child = attr->children;
1960b57cec5SDimitry Andric if (child->type == XML_TEXT_NODE) {
1970b57cec5SDimitry Andric llvm::StringRef attr_value;
1980b57cec5SDimitry Andric if (child->content)
1990b57cec5SDimitry Andric attr_value = llvm::StringRef((const char *)child->content);
2000b57cec5SDimitry Andric if (!callback(llvm::StringRef((const char *)attr->name), attr_value))
2010b57cec5SDimitry Andric return;
2020b57cec5SDimitry Andric }
2030b57cec5SDimitry Andric }
2040b57cec5SDimitry Andric }
2050b57cec5SDimitry Andric }
2060b57cec5SDimitry Andric #endif
2070b57cec5SDimitry Andric }
2080b57cec5SDimitry Andric
ForEachSiblingNode(NodeCallback const & callback) const2090b57cec5SDimitry Andric void XMLNode::ForEachSiblingNode(NodeCallback const &callback) const {
210480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
2110b57cec5SDimitry Andric
2120b57cec5SDimitry Andric if (IsValid()) {
2130b57cec5SDimitry Andric // iterate through all siblings
2140b57cec5SDimitry Andric for (xmlNodePtr node = m_node; node; node = node->next) {
2150b57cec5SDimitry Andric if (!callback(XMLNode(node)))
2160b57cec5SDimitry Andric return;
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric }
2190b57cec5SDimitry Andric #endif
2200b57cec5SDimitry Andric }
2210b57cec5SDimitry Andric
ForEachSiblingElement(NodeCallback const & callback) const2220b57cec5SDimitry Andric void XMLNode::ForEachSiblingElement(NodeCallback const &callback) const {
223480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
2240b57cec5SDimitry Andric
2250b57cec5SDimitry Andric if (IsValid()) {
2260b57cec5SDimitry Andric // iterate through all siblings
2270b57cec5SDimitry Andric for (xmlNodePtr node = m_node; node; node = node->next) {
2280b57cec5SDimitry Andric // we are looking for element nodes only
2290b57cec5SDimitry Andric if (node->type != XML_ELEMENT_NODE)
2300b57cec5SDimitry Andric continue;
2310b57cec5SDimitry Andric
2320b57cec5SDimitry Andric if (!callback(XMLNode(node)))
2330b57cec5SDimitry Andric return;
2340b57cec5SDimitry Andric }
2350b57cec5SDimitry Andric }
2360b57cec5SDimitry Andric #endif
2370b57cec5SDimitry Andric }
2380b57cec5SDimitry Andric
ForEachSiblingElementWithName(const char * name,NodeCallback const & callback) const2390b57cec5SDimitry Andric void XMLNode::ForEachSiblingElementWithName(
2400b57cec5SDimitry Andric const char *name, NodeCallback const &callback) const {
241480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
2420b57cec5SDimitry Andric
2430b57cec5SDimitry Andric if (IsValid()) {
2440b57cec5SDimitry Andric // iterate through all siblings
2450b57cec5SDimitry Andric for (xmlNodePtr node = m_node; node; node = node->next) {
2460b57cec5SDimitry Andric // we are looking for element nodes only
2470b57cec5SDimitry Andric if (node->type != XML_ELEMENT_NODE)
2480b57cec5SDimitry Andric continue;
2490b57cec5SDimitry Andric
2500b57cec5SDimitry Andric // If name is nullptr, we take all nodes of type "t", else just the ones
2510b57cec5SDimitry Andric // whose name matches
2520b57cec5SDimitry Andric if (name) {
2530b57cec5SDimitry Andric if (strcmp((const char *)node->name, name) != 0)
2540b57cec5SDimitry Andric continue; // Name mismatch, ignore this one
2550b57cec5SDimitry Andric } else {
2560b57cec5SDimitry Andric if (node->name)
2570b57cec5SDimitry Andric continue; // nullptr name specified and this element has a name,
2580b57cec5SDimitry Andric // ignore this one
2590b57cec5SDimitry Andric }
2600b57cec5SDimitry Andric
2610b57cec5SDimitry Andric if (!callback(XMLNode(node)))
2620b57cec5SDimitry Andric return;
2630b57cec5SDimitry Andric }
2640b57cec5SDimitry Andric }
2650b57cec5SDimitry Andric #endif
2660b57cec5SDimitry Andric }
2670b57cec5SDimitry Andric
GetName() const2680b57cec5SDimitry Andric llvm::StringRef XMLNode::GetName() const {
269480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
2700b57cec5SDimitry Andric if (IsValid()) {
2710b57cec5SDimitry Andric if (m_node->name)
2720b57cec5SDimitry Andric return llvm::StringRef((const char *)m_node->name);
2730b57cec5SDimitry Andric }
2740b57cec5SDimitry Andric #endif
2750b57cec5SDimitry Andric return llvm::StringRef();
2760b57cec5SDimitry Andric }
2770b57cec5SDimitry Andric
GetElementText(std::string & text) const2780b57cec5SDimitry Andric bool XMLNode::GetElementText(std::string &text) const {
2790b57cec5SDimitry Andric text.clear();
280480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
2810b57cec5SDimitry Andric if (IsValid()) {
2820b57cec5SDimitry Andric bool success = false;
2830b57cec5SDimitry Andric if (m_node->type == XML_ELEMENT_NODE) {
2840b57cec5SDimitry Andric // check child is a text node
2850b57cec5SDimitry Andric for (xmlNodePtr node = m_node->children; node != nullptr;
2860b57cec5SDimitry Andric node = node->next) {
2870b57cec5SDimitry Andric if (node->type == XML_TEXT_NODE) {
2880b57cec5SDimitry Andric text.append((const char *)node->content);
2890b57cec5SDimitry Andric success = true;
2900b57cec5SDimitry Andric }
2910b57cec5SDimitry Andric }
2920b57cec5SDimitry Andric }
2930b57cec5SDimitry Andric return success;
2940b57cec5SDimitry Andric }
2950b57cec5SDimitry Andric #endif
2960b57cec5SDimitry Andric return false;
2970b57cec5SDimitry Andric }
2980b57cec5SDimitry Andric
GetElementTextAsUnsigned(uint64_t & value,uint64_t fail_value,int base) const2990b57cec5SDimitry Andric bool XMLNode::GetElementTextAsUnsigned(uint64_t &value, uint64_t fail_value,
3000b57cec5SDimitry Andric int base) const {
3010b57cec5SDimitry Andric std::string text;
302349cc55cSDimitry Andric
3030b57cec5SDimitry Andric value = fail_value;
304349cc55cSDimitry Andric return GetElementText(text) && llvm::to_integer(text, value, base);
3050b57cec5SDimitry Andric }
3060b57cec5SDimitry Andric
GetElementTextAsFloat(double & value,double fail_value) const3070b57cec5SDimitry Andric bool XMLNode::GetElementTextAsFloat(double &value, double fail_value) const {
3080b57cec5SDimitry Andric std::string text;
309349cc55cSDimitry Andric
3100b57cec5SDimitry Andric value = fail_value;
311349cc55cSDimitry Andric return GetElementText(text) && llvm::to_float(text, value);
3120b57cec5SDimitry Andric }
3130b57cec5SDimitry Andric
NameIs(const char * name) const3140b57cec5SDimitry Andric bool XMLNode::NameIs(const char *name) const {
315480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
3160b57cec5SDimitry Andric
3170b57cec5SDimitry Andric if (IsValid()) {
3180b57cec5SDimitry Andric // In case we are looking for a nullptr name or an exact pointer match
3190b57cec5SDimitry Andric if (m_node->name == (const xmlChar *)name)
3200b57cec5SDimitry Andric return true;
3210b57cec5SDimitry Andric if (m_node->name)
3220b57cec5SDimitry Andric return strcmp((const char *)m_node->name, name) == 0;
3230b57cec5SDimitry Andric }
3240b57cec5SDimitry Andric #endif
3250b57cec5SDimitry Andric return false;
3260b57cec5SDimitry Andric }
3270b57cec5SDimitry Andric
FindFirstChildElementWithName(const char * name) const3280b57cec5SDimitry Andric XMLNode XMLNode::FindFirstChildElementWithName(const char *name) const {
3290b57cec5SDimitry Andric XMLNode result_node;
3300b57cec5SDimitry Andric
331480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
3320b57cec5SDimitry Andric ForEachChildElementWithName(
3330b57cec5SDimitry Andric name, [&result_node](const XMLNode &node) -> bool {
3340b57cec5SDimitry Andric result_node = node;
3350b57cec5SDimitry Andric // Stop iterating, we found the node we wanted
3360b57cec5SDimitry Andric return false;
3370b57cec5SDimitry Andric });
3380b57cec5SDimitry Andric #endif
3390b57cec5SDimitry Andric
3400b57cec5SDimitry Andric return result_node;
3410b57cec5SDimitry Andric }
3420b57cec5SDimitry Andric
IsValid() const3430b57cec5SDimitry Andric bool XMLNode::IsValid() const { return m_node != nullptr; }
3440b57cec5SDimitry Andric
IsElement() const3450b57cec5SDimitry Andric bool XMLNode::IsElement() const {
346480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
3470b57cec5SDimitry Andric if (IsValid())
3480b57cec5SDimitry Andric return m_node->type == XML_ELEMENT_NODE;
3490b57cec5SDimitry Andric #endif
3500b57cec5SDimitry Andric return false;
3510b57cec5SDimitry Andric }
3520b57cec5SDimitry Andric
GetElementForPath(const NamePath & path)3530b57cec5SDimitry Andric XMLNode XMLNode::GetElementForPath(const NamePath &path) {
354480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
3550b57cec5SDimitry Andric
3560b57cec5SDimitry Andric if (IsValid()) {
3570b57cec5SDimitry Andric if (path.empty())
3580b57cec5SDimitry Andric return *this;
3590b57cec5SDimitry Andric else {
3600b57cec5SDimitry Andric XMLNode node = FindFirstChildElementWithName(path[0].c_str());
3610b57cec5SDimitry Andric const size_t n = path.size();
3620b57cec5SDimitry Andric for (size_t i = 1; node && i < n; ++i)
3630b57cec5SDimitry Andric node = node.FindFirstChildElementWithName(path[i].c_str());
3640b57cec5SDimitry Andric return node;
3650b57cec5SDimitry Andric }
3660b57cec5SDimitry Andric }
3670b57cec5SDimitry Andric #endif
3680b57cec5SDimitry Andric
3690b57cec5SDimitry Andric return XMLNode();
3700b57cec5SDimitry Andric }
3710b57cec5SDimitry Andric
3720b57cec5SDimitry Andric #pragma mark-- ApplePropertyList
3730b57cec5SDimitry Andric
ApplePropertyList()3740b57cec5SDimitry Andric ApplePropertyList::ApplePropertyList() : m_xml_doc(), m_dict_node() {}
3750b57cec5SDimitry Andric
ApplePropertyList(const char * path)3760b57cec5SDimitry Andric ApplePropertyList::ApplePropertyList(const char *path)
3770b57cec5SDimitry Andric : m_xml_doc(), m_dict_node() {
3780b57cec5SDimitry Andric ParseFile(path);
3790b57cec5SDimitry Andric }
3800b57cec5SDimitry Andric
381fe6060f1SDimitry Andric ApplePropertyList::~ApplePropertyList() = default;
3820b57cec5SDimitry Andric
GetErrors() const3830b57cec5SDimitry Andric llvm::StringRef ApplePropertyList::GetErrors() const {
3840b57cec5SDimitry Andric return m_xml_doc.GetErrors();
3850b57cec5SDimitry Andric }
3860b57cec5SDimitry Andric
ParseFile(const char * path)3870b57cec5SDimitry Andric bool ApplePropertyList::ParseFile(const char *path) {
3880b57cec5SDimitry Andric if (m_xml_doc.ParseFile(path)) {
3890b57cec5SDimitry Andric XMLNode plist = m_xml_doc.GetRootElement("plist");
3900b57cec5SDimitry Andric if (plist) {
3910b57cec5SDimitry Andric plist.ForEachChildElementWithName("dict",
3920b57cec5SDimitry Andric [this](const XMLNode &dict) -> bool {
3930b57cec5SDimitry Andric this->m_dict_node = dict;
3940b57cec5SDimitry Andric return false; // Stop iterating
3950b57cec5SDimitry Andric });
3960b57cec5SDimitry Andric return (bool)m_dict_node;
3970b57cec5SDimitry Andric }
3980b57cec5SDimitry Andric }
3990b57cec5SDimitry Andric return false;
4000b57cec5SDimitry Andric }
4010b57cec5SDimitry Andric
IsValid() const4020b57cec5SDimitry Andric bool ApplePropertyList::IsValid() const { return (bool)m_dict_node; }
4030b57cec5SDimitry Andric
GetValueAsString(const char * key,std::string & value) const4040b57cec5SDimitry Andric bool ApplePropertyList::GetValueAsString(const char *key,
4050b57cec5SDimitry Andric std::string &value) const {
4060b57cec5SDimitry Andric XMLNode value_node = GetValueNode(key);
4070b57cec5SDimitry Andric if (value_node)
4080b57cec5SDimitry Andric return ApplePropertyList::ExtractStringFromValueNode(value_node, value);
4090b57cec5SDimitry Andric return false;
4100b57cec5SDimitry Andric }
4110b57cec5SDimitry Andric
GetValueNode(const char * key) const4120b57cec5SDimitry Andric XMLNode ApplePropertyList::GetValueNode(const char *key) const {
4130b57cec5SDimitry Andric XMLNode value_node;
414480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
4150b57cec5SDimitry Andric
4160b57cec5SDimitry Andric if (IsValid()) {
4170b57cec5SDimitry Andric m_dict_node.ForEachChildElementWithName(
4180b57cec5SDimitry Andric "key", [key, &value_node](const XMLNode &key_node) -> bool {
4190b57cec5SDimitry Andric std::string key_name;
4200b57cec5SDimitry Andric if (key_node.GetElementText(key_name)) {
4210b57cec5SDimitry Andric if (key_name == key) {
4220b57cec5SDimitry Andric value_node = key_node.GetSibling();
4230b57cec5SDimitry Andric while (value_node && !value_node.IsElement())
4240b57cec5SDimitry Andric value_node = value_node.GetSibling();
4250b57cec5SDimitry Andric return false; // Stop iterating
4260b57cec5SDimitry Andric }
4270b57cec5SDimitry Andric }
4280b57cec5SDimitry Andric return true; // Keep iterating
4290b57cec5SDimitry Andric });
4300b57cec5SDimitry Andric }
4310b57cec5SDimitry Andric #endif
4320b57cec5SDimitry Andric return value_node;
4330b57cec5SDimitry Andric }
4340b57cec5SDimitry Andric
ExtractStringFromValueNode(const XMLNode & node,std::string & value)4350b57cec5SDimitry Andric bool ApplePropertyList::ExtractStringFromValueNode(const XMLNode &node,
4360b57cec5SDimitry Andric std::string &value) {
4370b57cec5SDimitry Andric value.clear();
438480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
4390b57cec5SDimitry Andric if (node.IsValid()) {
4400b57cec5SDimitry Andric llvm::StringRef element_name = node.GetName();
4410b57cec5SDimitry Andric if (element_name == "true" || element_name == "false") {
4420b57cec5SDimitry Andric // The text value _is_ the element name itself...
4430b57cec5SDimitry Andric value = element_name.str();
4440b57cec5SDimitry Andric return true;
4450b57cec5SDimitry Andric } else if (element_name == "dict" || element_name == "array")
4460b57cec5SDimitry Andric return false; // dictionaries and arrays have no text value, so we fail
4470b57cec5SDimitry Andric else
4480b57cec5SDimitry Andric return node.GetElementText(value);
4490b57cec5SDimitry Andric }
4500b57cec5SDimitry Andric #endif
4510b57cec5SDimitry Andric return false;
4520b57cec5SDimitry Andric }
4530b57cec5SDimitry Andric
454480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
4550b57cec5SDimitry Andric
CreatePlistValue(XMLNode node)456349cc55cSDimitry Andric static StructuredData::ObjectSP CreatePlistValue(XMLNode node) {
4570b57cec5SDimitry Andric llvm::StringRef element_name = node.GetName();
4580b57cec5SDimitry Andric if (element_name == "array") {
4590b57cec5SDimitry Andric std::shared_ptr<StructuredData::Array> array_sp(
4600b57cec5SDimitry Andric new StructuredData::Array());
4610b57cec5SDimitry Andric node.ForEachChildElement([&array_sp](const XMLNode &node) -> bool {
4620b57cec5SDimitry Andric array_sp->AddItem(CreatePlistValue(node));
4630b57cec5SDimitry Andric return true; // Keep iterating through all child elements of the array
4640b57cec5SDimitry Andric });
4650b57cec5SDimitry Andric return array_sp;
4660b57cec5SDimitry Andric } else if (element_name == "dict") {
4670b57cec5SDimitry Andric XMLNode key_node;
4680b57cec5SDimitry Andric std::shared_ptr<StructuredData::Dictionary> dict_sp(
4690b57cec5SDimitry Andric new StructuredData::Dictionary());
4700b57cec5SDimitry Andric node.ForEachChildElement(
4710b57cec5SDimitry Andric [&key_node, &dict_sp](const XMLNode &node) -> bool {
4720b57cec5SDimitry Andric if (node.NameIs("key")) {
4730b57cec5SDimitry Andric // This is a "key" element node
4740b57cec5SDimitry Andric key_node = node;
4750b57cec5SDimitry Andric } else {
4760b57cec5SDimitry Andric // This is a value node
4770b57cec5SDimitry Andric if (key_node) {
4780b57cec5SDimitry Andric std::string key_name;
4790b57cec5SDimitry Andric key_node.GetElementText(key_name);
4800b57cec5SDimitry Andric dict_sp->AddItem(key_name, CreatePlistValue(node));
4810b57cec5SDimitry Andric key_node.Clear();
4820b57cec5SDimitry Andric }
4830b57cec5SDimitry Andric }
4840b57cec5SDimitry Andric return true; // Keep iterating through all child elements of the
4850b57cec5SDimitry Andric // dictionary
4860b57cec5SDimitry Andric });
4870b57cec5SDimitry Andric return dict_sp;
4880b57cec5SDimitry Andric } else if (element_name == "real") {
4890b57cec5SDimitry Andric double value = 0.0;
4900b57cec5SDimitry Andric node.GetElementTextAsFloat(value);
4910b57cec5SDimitry Andric return StructuredData::ObjectSP(new StructuredData::Float(value));
4920b57cec5SDimitry Andric } else if (element_name == "integer") {
4930b57cec5SDimitry Andric uint64_t value = 0;
4940b57cec5SDimitry Andric node.GetElementTextAsUnsigned(value, 0, 0);
495*06c3fb27SDimitry Andric return StructuredData::ObjectSP(new StructuredData::UnsignedInteger(value));
4960b57cec5SDimitry Andric } else if ((element_name == "string") || (element_name == "data") ||
4970b57cec5SDimitry Andric (element_name == "date")) {
4980b57cec5SDimitry Andric std::string text;
4990b57cec5SDimitry Andric node.GetElementText(text);
5000b57cec5SDimitry Andric return StructuredData::ObjectSP(
5010b57cec5SDimitry Andric new StructuredData::String(std::move(text)));
5020b57cec5SDimitry Andric } else if (element_name == "true") {
5030b57cec5SDimitry Andric return StructuredData::ObjectSP(new StructuredData::Boolean(true));
5040b57cec5SDimitry Andric } else if (element_name == "false") {
5050b57cec5SDimitry Andric return StructuredData::ObjectSP(new StructuredData::Boolean(false));
5060b57cec5SDimitry Andric }
5070b57cec5SDimitry Andric return StructuredData::ObjectSP(new StructuredData::Null());
5080b57cec5SDimitry Andric }
5090b57cec5SDimitry Andric #endif
5100b57cec5SDimitry Andric
GetStructuredData()5110b57cec5SDimitry Andric StructuredData::ObjectSP ApplePropertyList::GetStructuredData() {
5120b57cec5SDimitry Andric StructuredData::ObjectSP root_sp;
513480093f4SDimitry Andric #if LLDB_ENABLE_LIBXML2
5140b57cec5SDimitry Andric if (IsValid()) {
5150b57cec5SDimitry Andric return CreatePlistValue(m_dict_node);
5160b57cec5SDimitry Andric }
5170b57cec5SDimitry Andric #endif
5180b57cec5SDimitry Andric return root_sp;
5190b57cec5SDimitry Andric }
520