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