180814287SRaphael Isemann //===-- XML.cpp -----------------------------------------------------------===//
2d04f0edaSGreg Clayton //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d04f0edaSGreg Clayton //
7d04f0edaSGreg Clayton //===----------------------------------------------------------------------===//
8d04f0edaSGreg Clayton
9bf68bcb9SJonas Devlieghere #include "lldb/Host/Config.h"
10b9c1b51eSKate Stone #include "lldb/Host/XML.h"
11d04f0edaSGreg Clayton
12d04f0edaSGreg Clayton using namespace lldb;
13d04f0edaSGreg Clayton using namespace lldb_private;
14d04f0edaSGreg Clayton
15d04f0edaSGreg Clayton #pragma mark-- XMLDocument
16d04f0edaSGreg Clayton
17fd2433e1SJonas Devlieghere XMLDocument::XMLDocument() = default;
18d04f0edaSGreg Clayton
~XMLDocument()19b9c1b51eSKate Stone XMLDocument::~XMLDocument() { Clear(); }
20d04f0edaSGreg Clayton
Clear()21b9c1b51eSKate Stone void XMLDocument::Clear() {
224b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
23b9c1b51eSKate Stone if (m_document) {
24d04f0edaSGreg Clayton xmlDocPtr doc = m_document;
25d04f0edaSGreg Clayton m_document = nullptr;
26d04f0edaSGreg Clayton xmlFreeDoc(doc);
27d04f0edaSGreg Clayton }
28d04f0edaSGreg Clayton #endif
29d04f0edaSGreg Clayton }
30d04f0edaSGreg Clayton
IsValid() const31b9c1b51eSKate Stone bool XMLDocument::IsValid() const { return m_document != nullptr; }
32d04f0edaSGreg Clayton
ErrorCallback(void * ctx,const char * format,...)33b9c1b51eSKate Stone void XMLDocument::ErrorCallback(void *ctx, const char *format, ...) {
34d04f0edaSGreg Clayton XMLDocument *document = (XMLDocument *)ctx;
35d04f0edaSGreg Clayton va_list args;
36d04f0edaSGreg Clayton va_start(args, format);
37d04f0edaSGreg Clayton document->m_errors.PrintfVarArg(format, args);
38d04f0edaSGreg Clayton document->m_errors.EOL();
39d04f0edaSGreg Clayton va_end(args);
40d04f0edaSGreg Clayton }
41d04f0edaSGreg Clayton
ParseFile(const char * path)42b9c1b51eSKate Stone bool XMLDocument::ParseFile(const char *path) {
434b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
44d04f0edaSGreg Clayton Clear();
45d04f0edaSGreg Clayton xmlSetGenericErrorFunc((void *)this, XMLDocument::ErrorCallback);
46d04f0edaSGreg Clayton m_document = xmlParseFile(path);
47d04f0edaSGreg Clayton xmlSetGenericErrorFunc(nullptr, nullptr);
48d04f0edaSGreg Clayton #endif
49d04f0edaSGreg Clayton return IsValid();
50d04f0edaSGreg Clayton }
51d04f0edaSGreg Clayton
ParseMemory(const char * xml,size_t xml_length,const char * url)52b9c1b51eSKate Stone bool XMLDocument::ParseMemory(const char *xml, size_t xml_length,
53b9c1b51eSKate Stone const char *url) {
544b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
55d04f0edaSGreg Clayton Clear();
56d04f0edaSGreg Clayton xmlSetGenericErrorFunc((void *)this, XMLDocument::ErrorCallback);
57d04f0edaSGreg Clayton m_document = xmlReadMemory(xml, (int)xml_length, url, nullptr, 0);
58d04f0edaSGreg Clayton xmlSetGenericErrorFunc(nullptr, nullptr);
59d04f0edaSGreg Clayton #endif
60d04f0edaSGreg Clayton return IsValid();
61d04f0edaSGreg Clayton }
62d04f0edaSGreg Clayton
GetRootElement(const char * required_name)63b9c1b51eSKate Stone XMLNode XMLDocument::GetRootElement(const char *required_name) {
644b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
65b9c1b51eSKate Stone if (IsValid()) {
66d04f0edaSGreg Clayton XMLNode root_node(xmlDocGetRootElement(m_document));
67b9c1b51eSKate Stone if (required_name) {
68d04f0edaSGreg Clayton llvm::StringRef actual_name = root_node.GetName();
69d04f0edaSGreg Clayton if (actual_name == required_name)
70d04f0edaSGreg Clayton return root_node;
71b9c1b51eSKate Stone } else {
72d04f0edaSGreg Clayton return root_node;
73d04f0edaSGreg Clayton }
74d04f0edaSGreg Clayton }
75d04f0edaSGreg Clayton #endif
76d04f0edaSGreg Clayton return XMLNode();
77d04f0edaSGreg Clayton }
78d04f0edaSGreg Clayton
GetErrors() const798927f23aSZachary Turner llvm::StringRef XMLDocument::GetErrors() const { return m_errors.GetString(); }
802a2949cfSGreg Clayton
XMLEnabled()81b9c1b51eSKate Stone bool XMLDocument::XMLEnabled() {
824b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
83d04f0edaSGreg Clayton return true;
84d04f0edaSGreg Clayton #else
85d04f0edaSGreg Clayton return false;
86d04f0edaSGreg Clayton #endif
87d04f0edaSGreg Clayton }
88d04f0edaSGreg Clayton
89d04f0edaSGreg Clayton #pragma mark-- XMLNode
90d04f0edaSGreg Clayton
91fd2433e1SJonas Devlieghere XMLNode::XMLNode() = default;
92d04f0edaSGreg Clayton
XMLNode(XMLNodeImpl node)93b9c1b51eSKate Stone XMLNode::XMLNode(XMLNodeImpl node) : m_node(node) {}
94d04f0edaSGreg Clayton
95fd2433e1SJonas Devlieghere XMLNode::~XMLNode() = default;
96d04f0edaSGreg Clayton
Clear()97b9c1b51eSKate Stone void XMLNode::Clear() { m_node = nullptr; }
98d04f0edaSGreg Clayton
GetParent() const99b9c1b51eSKate Stone XMLNode XMLNode::GetParent() const {
1004b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
101d04f0edaSGreg Clayton if (IsValid())
102d04f0edaSGreg Clayton return XMLNode(m_node->parent);
103d04f0edaSGreg Clayton else
104d04f0edaSGreg Clayton return XMLNode();
105d04f0edaSGreg Clayton #else
106d04f0edaSGreg Clayton return XMLNode();
107d04f0edaSGreg Clayton #endif
108d04f0edaSGreg Clayton }
109d04f0edaSGreg Clayton
GetSibling() const110b9c1b51eSKate Stone XMLNode XMLNode::GetSibling() const {
1114b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
112d04f0edaSGreg Clayton if (IsValid())
113d04f0edaSGreg Clayton return XMLNode(m_node->next);
114d04f0edaSGreg Clayton else
115d04f0edaSGreg Clayton return XMLNode();
116d04f0edaSGreg Clayton #else
117d04f0edaSGreg Clayton return XMLNode();
118d04f0edaSGreg Clayton #endif
119d04f0edaSGreg Clayton }
120d04f0edaSGreg Clayton
GetChild() const121b9c1b51eSKate Stone XMLNode XMLNode::GetChild() const {
1224b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
123d04f0edaSGreg Clayton
124d04f0edaSGreg Clayton if (IsValid())
125d04f0edaSGreg Clayton return XMLNode(m_node->children);
126d04f0edaSGreg Clayton else
127d04f0edaSGreg Clayton return XMLNode();
128d04f0edaSGreg Clayton #else
129d04f0edaSGreg Clayton return XMLNode();
130d04f0edaSGreg Clayton #endif
131d04f0edaSGreg Clayton }
132d04f0edaSGreg Clayton
GetAttributeValue(const char * name,const char * fail_value) const133*1267506eSLirong Yuan std::string XMLNode::GetAttributeValue(const char *name,
134b9c1b51eSKate Stone const char *fail_value) const {
135*1267506eSLirong Yuan std::string attr_value;
1364b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
137*1267506eSLirong Yuan if (IsValid()) {
138*1267506eSLirong Yuan xmlChar *value = xmlGetProp(m_node, (const xmlChar *)name);
139*1267506eSLirong Yuan if (value) {
140*1267506eSLirong Yuan attr_value = (const char *)value;
141*1267506eSLirong Yuan xmlFree(value);
142*1267506eSLirong Yuan }
143*1267506eSLirong Yuan } else {
144*1267506eSLirong Yuan if (fail_value)
145d04f0edaSGreg Clayton attr_value = fail_value;
146*1267506eSLirong Yuan }
147d04f0edaSGreg Clayton #else
148*1267506eSLirong Yuan if (fail_value)
149d04f0edaSGreg Clayton attr_value = fail_value;
150d04f0edaSGreg Clayton #endif
151*1267506eSLirong Yuan return attr_value;
152d04f0edaSGreg Clayton }
153d04f0edaSGreg Clayton
GetAttributeValueAsUnsigned(const char * name,uint64_t & value,uint64_t fail_value,int base) const15416064d35SPavel Labath bool XMLNode::GetAttributeValueAsUnsigned(const char *name, uint64_t &value,
15516064d35SPavel Labath uint64_t fail_value, int base) const {
15693b82f45SMichał Górny value = fail_value;
15793b82f45SMichał Górny return llvm::to_integer(GetAttributeValue(name, ""), value, base);
15816064d35SPavel Labath }
15916064d35SPavel Labath
ForEachChildNode(NodeCallback const & callback) const160b9c1b51eSKate Stone void XMLNode::ForEachChildNode(NodeCallback const &callback) const {
1614b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
162d04f0edaSGreg Clayton if (IsValid())
163d04f0edaSGreg Clayton GetChild().ForEachSiblingNode(callback);
164d04f0edaSGreg Clayton #endif
165d04f0edaSGreg Clayton }
166d04f0edaSGreg Clayton
ForEachChildElement(NodeCallback const & callback) const167b9c1b51eSKate Stone void XMLNode::ForEachChildElement(NodeCallback const &callback) const {
1684b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
169d04f0edaSGreg Clayton XMLNode child = GetChild();
170d04f0edaSGreg Clayton if (child)
171d04f0edaSGreg Clayton child.ForEachSiblingElement(callback);
172d04f0edaSGreg Clayton #endif
173d04f0edaSGreg Clayton }
174d04f0edaSGreg Clayton
ForEachChildElementWithName(const char * name,NodeCallback const & callback) const175b9c1b51eSKate Stone void XMLNode::ForEachChildElementWithName(const char *name,
176b9c1b51eSKate Stone NodeCallback const &callback) const {
1774b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
178d04f0edaSGreg Clayton XMLNode child = GetChild();
179d04f0edaSGreg Clayton if (child)
180d04f0edaSGreg Clayton child.ForEachSiblingElementWithName(name, callback);
181d04f0edaSGreg Clayton #endif
182d04f0edaSGreg Clayton }
183d04f0edaSGreg Clayton
ForEachAttribute(AttributeCallback const & callback) const184b9c1b51eSKate Stone void XMLNode::ForEachAttribute(AttributeCallback const &callback) const {
1854b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
186d04f0edaSGreg Clayton
187b9c1b51eSKate Stone if (IsValid()) {
188b9c1b51eSKate Stone for (xmlAttrPtr attr = m_node->properties; attr != nullptr;
189b9c1b51eSKate Stone attr = attr->next) {
190d04f0edaSGreg Clayton // check if name matches
191b9c1b51eSKate Stone if (attr->name) {
192d04f0edaSGreg Clayton // check child is a text node
193d04f0edaSGreg Clayton xmlNodePtr child = attr->children;
194b9c1b51eSKate Stone if (child->type == XML_TEXT_NODE) {
195d04f0edaSGreg Clayton llvm::StringRef attr_value;
196d04f0edaSGreg Clayton if (child->content)
197d04f0edaSGreg Clayton attr_value = llvm::StringRef((const char *)child->content);
198a6682a41SJonas Devlieghere if (!callback(llvm::StringRef((const char *)attr->name), attr_value))
199d04f0edaSGreg Clayton return;
200d04f0edaSGreg Clayton }
201d04f0edaSGreg Clayton }
202d04f0edaSGreg Clayton }
203d04f0edaSGreg Clayton }
204d04f0edaSGreg Clayton #endif
205d04f0edaSGreg Clayton }
206d04f0edaSGreg Clayton
ForEachSiblingNode(NodeCallback const & callback) const207b9c1b51eSKate Stone void XMLNode::ForEachSiblingNode(NodeCallback const &callback) const {
2084b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
209d04f0edaSGreg Clayton
210b9c1b51eSKate Stone if (IsValid()) {
211d04f0edaSGreg Clayton // iterate through all siblings
212b9c1b51eSKate Stone for (xmlNodePtr node = m_node; node; node = node->next) {
213a6682a41SJonas Devlieghere if (!callback(XMLNode(node)))
214d04f0edaSGreg Clayton return;
215d04f0edaSGreg Clayton }
216d04f0edaSGreg Clayton }
217d04f0edaSGreg Clayton #endif
218d04f0edaSGreg Clayton }
219d04f0edaSGreg Clayton
ForEachSiblingElement(NodeCallback const & callback) const220b9c1b51eSKate Stone void XMLNode::ForEachSiblingElement(NodeCallback const &callback) const {
2214b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
222d04f0edaSGreg Clayton
223b9c1b51eSKate Stone if (IsValid()) {
224d04f0edaSGreg Clayton // iterate through all siblings
225b9c1b51eSKate Stone for (xmlNodePtr node = m_node; node; node = node->next) {
226d04f0edaSGreg Clayton // we are looking for element nodes only
227d04f0edaSGreg Clayton if (node->type != XML_ELEMENT_NODE)
228d04f0edaSGreg Clayton continue;
229d04f0edaSGreg Clayton
230a6682a41SJonas Devlieghere if (!callback(XMLNode(node)))
231d04f0edaSGreg Clayton return;
232d04f0edaSGreg Clayton }
233d04f0edaSGreg Clayton }
234d04f0edaSGreg Clayton #endif
235d04f0edaSGreg Clayton }
236d04f0edaSGreg Clayton
ForEachSiblingElementWithName(const char * name,NodeCallback const & callback) const237b9c1b51eSKate Stone void XMLNode::ForEachSiblingElementWithName(
238b9c1b51eSKate Stone const char *name, NodeCallback const &callback) const {
2394b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
240d04f0edaSGreg Clayton
241b9c1b51eSKate Stone if (IsValid()) {
242d04f0edaSGreg Clayton // iterate through all siblings
243b9c1b51eSKate Stone for (xmlNodePtr node = m_node; node; node = node->next) {
244d04f0edaSGreg Clayton // we are looking for element nodes only
245d04f0edaSGreg Clayton if (node->type != XML_ELEMENT_NODE)
246d04f0edaSGreg Clayton continue;
247d04f0edaSGreg Clayton
24805097246SAdrian Prantl // If name is nullptr, we take all nodes of type "t", else just the ones
24905097246SAdrian Prantl // whose name matches
250b9c1b51eSKate Stone if (name) {
251d04f0edaSGreg Clayton if (strcmp((const char *)node->name, name) != 0)
252d04f0edaSGreg Clayton continue; // Name mismatch, ignore this one
253b9c1b51eSKate Stone } else {
254d04f0edaSGreg Clayton if (node->name)
255b9c1b51eSKate Stone continue; // nullptr name specified and this element has a name,
256b9c1b51eSKate Stone // ignore this one
257d04f0edaSGreg Clayton }
258d04f0edaSGreg Clayton
259a6682a41SJonas Devlieghere if (!callback(XMLNode(node)))
260d04f0edaSGreg Clayton return;
261d04f0edaSGreg Clayton }
262d04f0edaSGreg Clayton }
263d04f0edaSGreg Clayton #endif
264d04f0edaSGreg Clayton }
265d04f0edaSGreg Clayton
GetName() const266b9c1b51eSKate Stone llvm::StringRef XMLNode::GetName() const {
2674b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
268b9c1b51eSKate Stone if (IsValid()) {
269d04f0edaSGreg Clayton if (m_node->name)
270d04f0edaSGreg Clayton return llvm::StringRef((const char *)m_node->name);
271d04f0edaSGreg Clayton }
272d04f0edaSGreg Clayton #endif
273d04f0edaSGreg Clayton return llvm::StringRef();
274d04f0edaSGreg Clayton }
275d04f0edaSGreg Clayton
GetElementText(std::string & text) const276b9c1b51eSKate Stone bool XMLNode::GetElementText(std::string &text) const {
277d04f0edaSGreg Clayton text.clear();
2784b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
279b9c1b51eSKate Stone if (IsValid()) {
280d04f0edaSGreg Clayton bool success = false;
281b9c1b51eSKate Stone if (m_node->type == XML_ELEMENT_NODE) {
282d04f0edaSGreg Clayton // check child is a text node
283b9c1b51eSKate Stone for (xmlNodePtr node = m_node->children; node != nullptr;
284b9c1b51eSKate Stone node = node->next) {
285b9c1b51eSKate Stone if (node->type == XML_TEXT_NODE) {
286d04f0edaSGreg Clayton text.append((const char *)node->content);
287d04f0edaSGreg Clayton success = true;
288d04f0edaSGreg Clayton }
289d04f0edaSGreg Clayton }
290d04f0edaSGreg Clayton }
291d04f0edaSGreg Clayton return success;
292d04f0edaSGreg Clayton }
293d04f0edaSGreg Clayton #endif
294d04f0edaSGreg Clayton return false;
295d04f0edaSGreg Clayton }
296d04f0edaSGreg Clayton
GetElementTextAsUnsigned(uint64_t & value,uint64_t fail_value,int base) const297b9c1b51eSKate Stone bool XMLNode::GetElementTextAsUnsigned(uint64_t &value, uint64_t fail_value,
298b9c1b51eSKate Stone int base) const {
299ee8f9940SGreg Clayton std::string text;
30093b82f45SMichał Górny
301ee8f9940SGreg Clayton value = fail_value;
30293b82f45SMichał Górny return GetElementText(text) && llvm::to_integer(text, value, base);
303ee8f9940SGreg Clayton }
304ee8f9940SGreg Clayton
GetElementTextAsFloat(double & value,double fail_value) const305b9c1b51eSKate Stone bool XMLNode::GetElementTextAsFloat(double &value, double fail_value) const {
306ee8f9940SGreg Clayton std::string text;
30793b82f45SMichał Górny
308ee8f9940SGreg Clayton value = fail_value;
30993b82f45SMichał Górny return GetElementText(text) && llvm::to_float(text, value);
310ee8f9940SGreg Clayton }
311ee8f9940SGreg Clayton
NameIs(const char * name) const312b9c1b51eSKate Stone bool XMLNode::NameIs(const char *name) const {
3134b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
314d04f0edaSGreg Clayton
315b9c1b51eSKate Stone if (IsValid()) {
316d04f0edaSGreg Clayton // In case we are looking for a nullptr name or an exact pointer match
317d04f0edaSGreg Clayton if (m_node->name == (const xmlChar *)name)
318d04f0edaSGreg Clayton return true;
319d04f0edaSGreg Clayton if (m_node->name)
320d04f0edaSGreg Clayton return strcmp((const char *)m_node->name, name) == 0;
321d04f0edaSGreg Clayton }
322d04f0edaSGreg Clayton #endif
323d04f0edaSGreg Clayton return false;
324d04f0edaSGreg Clayton }
325d04f0edaSGreg Clayton
FindFirstChildElementWithName(const char * name) const326b9c1b51eSKate Stone XMLNode XMLNode::FindFirstChildElementWithName(const char *name) const {
327d04f0edaSGreg Clayton XMLNode result_node;
328d04f0edaSGreg Clayton
3294b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
330b9c1b51eSKate Stone ForEachChildElementWithName(
331014ef593SDavide Italiano name, [&result_node](const XMLNode &node) -> bool {
332d04f0edaSGreg Clayton result_node = node;
333d04f0edaSGreg Clayton // Stop iterating, we found the node we wanted
334d04f0edaSGreg Clayton return false;
335d04f0edaSGreg Clayton });
336d04f0edaSGreg Clayton #endif
337d04f0edaSGreg Clayton
338d04f0edaSGreg Clayton return result_node;
339d04f0edaSGreg Clayton }
340d04f0edaSGreg Clayton
IsValid() const341b9c1b51eSKate Stone bool XMLNode::IsValid() const { return m_node != nullptr; }
342d04f0edaSGreg Clayton
IsElement() const343b9c1b51eSKate Stone bool XMLNode::IsElement() const {
3444b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
345d04f0edaSGreg Clayton if (IsValid())
346d04f0edaSGreg Clayton return m_node->type == XML_ELEMENT_NODE;
347d04f0edaSGreg Clayton #endif
348d04f0edaSGreg Clayton return false;
349d04f0edaSGreg Clayton }
350d04f0edaSGreg Clayton
GetElementForPath(const NamePath & path)351b9c1b51eSKate Stone XMLNode XMLNode::GetElementForPath(const NamePath &path) {
3524b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
353d04f0edaSGreg Clayton
354b9c1b51eSKate Stone if (IsValid()) {
355d04f0edaSGreg Clayton if (path.empty())
356d04f0edaSGreg Clayton return *this;
357b9c1b51eSKate Stone else {
358d04f0edaSGreg Clayton XMLNode node = FindFirstChildElementWithName(path[0].c_str());
359d04f0edaSGreg Clayton const size_t n = path.size();
360d04f0edaSGreg Clayton for (size_t i = 1; node && i < n; ++i)
361d04f0edaSGreg Clayton node = node.FindFirstChildElementWithName(path[i].c_str());
362d04f0edaSGreg Clayton return node;
363d04f0edaSGreg Clayton }
364d04f0edaSGreg Clayton }
365d04f0edaSGreg Clayton #endif
366d04f0edaSGreg Clayton
367d04f0edaSGreg Clayton return XMLNode();
368d04f0edaSGreg Clayton }
369d04f0edaSGreg Clayton
370d04f0edaSGreg Clayton #pragma mark-- ApplePropertyList
371d04f0edaSGreg Clayton
ApplePropertyList()372b9c1b51eSKate Stone ApplePropertyList::ApplePropertyList() : m_xml_doc(), m_dict_node() {}
373d04f0edaSGreg Clayton
ApplePropertyList(const char * path)374b9c1b51eSKate Stone ApplePropertyList::ApplePropertyList(const char *path)
375b9c1b51eSKate Stone : m_xml_doc(), m_dict_node() {
376d04f0edaSGreg Clayton ParseFile(path);
377d04f0edaSGreg Clayton }
378d04f0edaSGreg Clayton
379fd2433e1SJonas Devlieghere ApplePropertyList::~ApplePropertyList() = default;
3802a2949cfSGreg Clayton
GetErrors() const3818927f23aSZachary Turner llvm::StringRef ApplePropertyList::GetErrors() const {
3822a2949cfSGreg Clayton return m_xml_doc.GetErrors();
3832a2949cfSGreg Clayton }
3842a2949cfSGreg Clayton
ParseFile(const char * path)385b9c1b51eSKate Stone bool ApplePropertyList::ParseFile(const char *path) {
386b9c1b51eSKate Stone if (m_xml_doc.ParseFile(path)) {
387d04f0edaSGreg Clayton XMLNode plist = m_xml_doc.GetRootElement("plist");
388b9c1b51eSKate Stone if (plist) {
389b9c1b51eSKate Stone plist.ForEachChildElementWithName("dict",
390b9c1b51eSKate Stone [this](const XMLNode &dict) -> bool {
391d04f0edaSGreg Clayton this->m_dict_node = dict;
392d04f0edaSGreg Clayton return false; // Stop iterating
393d04f0edaSGreg Clayton });
394d04f0edaSGreg Clayton return (bool)m_dict_node;
395d04f0edaSGreg Clayton }
396d04f0edaSGreg Clayton }
397d04f0edaSGreg Clayton return false;
398d04f0edaSGreg Clayton }
399d04f0edaSGreg Clayton
IsValid() const400b9c1b51eSKate Stone bool ApplePropertyList::IsValid() const { return (bool)m_dict_node; }
401d04f0edaSGreg Clayton
GetValueAsString(const char * key,std::string & value) const402b9c1b51eSKate Stone bool ApplePropertyList::GetValueAsString(const char *key,
403b9c1b51eSKate Stone std::string &value) const {
404d04f0edaSGreg Clayton XMLNode value_node = GetValueNode(key);
405d04f0edaSGreg Clayton if (value_node)
406d04f0edaSGreg Clayton return ApplePropertyList::ExtractStringFromValueNode(value_node, value);
407d04f0edaSGreg Clayton return false;
408d04f0edaSGreg Clayton }
409d04f0edaSGreg Clayton
GetValueNode(const char * key) const410b9c1b51eSKate Stone XMLNode ApplePropertyList::GetValueNode(const char *key) const {
411d04f0edaSGreg Clayton XMLNode value_node;
4124b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
413d04f0edaSGreg Clayton
414b9c1b51eSKate Stone if (IsValid()) {
415b9c1b51eSKate Stone m_dict_node.ForEachChildElementWithName(
416b9c1b51eSKate Stone "key", [key, &value_node](const XMLNode &key_node) -> bool {
417d04f0edaSGreg Clayton std::string key_name;
418b9c1b51eSKate Stone if (key_node.GetElementText(key_name)) {
4198d20cfdfSJonas Devlieghere if (key_name == key) {
420d04f0edaSGreg Clayton value_node = key_node.GetSibling();
421d04f0edaSGreg Clayton while (value_node && !value_node.IsElement())
422d04f0edaSGreg Clayton value_node = value_node.GetSibling();
423d04f0edaSGreg Clayton return false; // Stop iterating
424d04f0edaSGreg Clayton }
425d04f0edaSGreg Clayton }
426d04f0edaSGreg Clayton return true; // Keep iterating
427d04f0edaSGreg Clayton });
428d04f0edaSGreg Clayton }
429d04f0edaSGreg Clayton #endif
430d04f0edaSGreg Clayton return value_node;
431d04f0edaSGreg Clayton }
432d04f0edaSGreg Clayton
ExtractStringFromValueNode(const XMLNode & node,std::string & value)433b9c1b51eSKate Stone bool ApplePropertyList::ExtractStringFromValueNode(const XMLNode &node,
434b9c1b51eSKate Stone std::string &value) {
435d04f0edaSGreg Clayton value.clear();
4364b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
437b9c1b51eSKate Stone if (node.IsValid()) {
438d04f0edaSGreg Clayton llvm::StringRef element_name = node.GetName();
439b9c1b51eSKate Stone if (element_name == "true" || element_name == "false") {
440d04f0edaSGreg Clayton // The text value _is_ the element name itself...
4413a29f8b9SPavel Labath value = element_name.str();
442d04f0edaSGreg Clayton return true;
443b9c1b51eSKate Stone } else if (element_name == "dict" || element_name == "array")
444d04f0edaSGreg Clayton return false; // dictionaries and arrays have no text value, so we fail
445d04f0edaSGreg Clayton else
446d04f0edaSGreg Clayton return node.GetElementText(value);
447d04f0edaSGreg Clayton }
448d04f0edaSGreg Clayton #endif
449d04f0edaSGreg Clayton return false;
450d04f0edaSGreg Clayton }
451d04f0edaSGreg Clayton
4524b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
453ee8f9940SGreg Clayton
CreatePlistValue(XMLNode node)45493c1b3caSPavel Labath static StructuredData::ObjectSP CreatePlistValue(XMLNode node) {
455ee8f9940SGreg Clayton llvm::StringRef element_name = node.GetName();
456b9c1b51eSKate Stone if (element_name == "array") {
457b9c1b51eSKate Stone std::shared_ptr<StructuredData::Array> array_sp(
458b9c1b51eSKate Stone new StructuredData::Array());
459ee8f9940SGreg Clayton node.ForEachChildElement([&array_sp](const XMLNode &node) -> bool {
460ee8f9940SGreg Clayton array_sp->AddItem(CreatePlistValue(node));
461ee8f9940SGreg Clayton return true; // Keep iterating through all child elements of the array
462ee8f9940SGreg Clayton });
463ee8f9940SGreg Clayton return array_sp;
464b9c1b51eSKate Stone } else if (element_name == "dict") {
465ee8f9940SGreg Clayton XMLNode key_node;
466b9c1b51eSKate Stone std::shared_ptr<StructuredData::Dictionary> dict_sp(
467b9c1b51eSKate Stone new StructuredData::Dictionary());
468b9c1b51eSKate Stone node.ForEachChildElement(
469b9c1b51eSKate Stone [&key_node, &dict_sp](const XMLNode &node) -> bool {
470b9c1b51eSKate Stone if (node.NameIs("key")) {
471ee8f9940SGreg Clayton // This is a "key" element node
472ee8f9940SGreg Clayton key_node = node;
473b9c1b51eSKate Stone } else {
474ee8f9940SGreg Clayton // This is a value node
475b9c1b51eSKate Stone if (key_node) {
4762a2949cfSGreg Clayton std::string key_name;
4772a2949cfSGreg Clayton key_node.GetElementText(key_name);
4782a2949cfSGreg Clayton dict_sp->AddItem(key_name, CreatePlistValue(node));
479ee8f9940SGreg Clayton key_node.Clear();
480ee8f9940SGreg Clayton }
481ee8f9940SGreg Clayton }
482b9c1b51eSKate Stone return true; // Keep iterating through all child elements of the
483b9c1b51eSKate Stone // dictionary
484ee8f9940SGreg Clayton });
485ee8f9940SGreg Clayton return dict_sp;
486b9c1b51eSKate Stone } else if (element_name == "real") {
487ee8f9940SGreg Clayton double value = 0.0;
488ee8f9940SGreg Clayton node.GetElementTextAsFloat(value);
489ee8f9940SGreg Clayton return StructuredData::ObjectSP(new StructuredData::Float(value));
490b9c1b51eSKate Stone } else if (element_name == "integer") {
491ee8f9940SGreg Clayton uint64_t value = 0;
492ee8f9940SGreg Clayton node.GetElementTextAsUnsigned(value, 0, 0);
493ee8f9940SGreg Clayton return StructuredData::ObjectSP(new StructuredData::Integer(value));
494b9c1b51eSKate Stone } else if ((element_name == "string") || (element_name == "data") ||
495b9c1b51eSKate Stone (element_name == "date")) {
496ee8f9940SGreg Clayton std::string text;
497ee8f9940SGreg Clayton node.GetElementText(text);
498b9c1b51eSKate Stone return StructuredData::ObjectSP(
499b9c1b51eSKate Stone new StructuredData::String(std::move(text)));
500b9c1b51eSKate Stone } else if (element_name == "true") {
501ee8f9940SGreg Clayton return StructuredData::ObjectSP(new StructuredData::Boolean(true));
502b9c1b51eSKate Stone } else if (element_name == "false") {
503ee8f9940SGreg Clayton return StructuredData::ObjectSP(new StructuredData::Boolean(false));
504ee8f9940SGreg Clayton }
505ee8f9940SGreg Clayton return StructuredData::ObjectSP(new StructuredData::Null());
506ee8f9940SGreg Clayton }
507ee8f9940SGreg Clayton #endif
508ee8f9940SGreg Clayton
GetStructuredData()509b9c1b51eSKate Stone StructuredData::ObjectSP ApplePropertyList::GetStructuredData() {
510ee8f9940SGreg Clayton StructuredData::ObjectSP root_sp;
5114b15c6e2SJonas Devlieghere #if LLDB_ENABLE_LIBXML2
512b9c1b51eSKate Stone if (IsValid()) {
513ee8f9940SGreg Clayton return CreatePlistValue(m_dict_node);
514ee8f9940SGreg Clayton }
515ee8f9940SGreg Clayton #endif
516ee8f9940SGreg Clayton return root_sp;
517ee8f9940SGreg Clayton }
518