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