Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Host/common/XML.cpp
39606 views
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
14
using namespace lldb;
15
using namespace lldb_private;
16
17
#pragma mark-- XMLDocument
18
19
XMLDocument::XMLDocument() = default;
20
21
XMLDocument::~XMLDocument() { Clear(); }
22
23
void XMLDocument::Clear() {
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
33
bool XMLDocument::IsValid() const { return m_document != nullptr; }
34
35
void 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
44
bool 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
54
bool 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
65
XMLNode 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
81
llvm::StringRef XMLDocument::GetErrors() const { return m_errors.GetString(); }
82
83
bool XMLDocument::XMLEnabled() {
84
#if LLDB_ENABLE_LIBXML2
85
return true;
86
#else
87
return false;
88
#endif
89
}
90
91
#pragma mark-- XMLNode
92
93
XMLNode::XMLNode() = default;
94
95
XMLNode::XMLNode(XMLNodeImpl node) : m_node(node) {}
96
97
XMLNode::~XMLNode() = default;
98
99
void XMLNode::Clear() { m_node = nullptr; }
100
101
XMLNode XMLNode::GetParent() const {
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
112
XMLNode XMLNode::GetSibling() const {
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
123
XMLNode XMLNode::GetChild() const {
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
135
std::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
156
bool 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
162
void XMLNode::ForEachChildNode(NodeCallback const &callback) const {
163
#if LLDB_ENABLE_LIBXML2
164
if (IsValid())
165
GetChild().ForEachSiblingNode(callback);
166
#endif
167
}
168
169
void 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
177
void XMLNode::ForEachChildElementWithName(const char *name,
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
186
void 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
209
void 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
222
void 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
239
void XMLNode::ForEachSiblingElementWithName(
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
268
llvm::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
278
bool 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
299
bool 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
307
bool 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
314
bool 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
328
XMLNode XMLNode::FindFirstChildElementWithName(const char *name) const {
329
XMLNode result_node;
330
331
#if LLDB_ENABLE_LIBXML2
332
ForEachChildElementWithName(
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
343
bool XMLNode::IsValid() const { return m_node != nullptr; }
344
345
bool 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
353
XMLNode XMLNode::GetElementForPath(const NamePath &path) {
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
374
ApplePropertyList::ApplePropertyList() : m_xml_doc(), m_dict_node() {}
375
376
ApplePropertyList::ApplePropertyList(const char *path)
377
: m_xml_doc(), m_dict_node() {
378
ParseFile(path);
379
}
380
381
ApplePropertyList::~ApplePropertyList() = default;
382
383
llvm::StringRef ApplePropertyList::GetErrors() const {
384
return m_xml_doc.GetErrors();
385
}
386
387
bool 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
402
bool ApplePropertyList::IsValid() const { return (bool)m_dict_node; }
403
404
bool ApplePropertyList::GetValueAsString(const char *key,
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
412
XMLNode ApplePropertyList::GetValueNode(const char *key) const {
413
XMLNode value_node;
414
#if LLDB_ENABLE_LIBXML2
415
416
if (IsValid()) {
417
m_dict_node.ForEachChildElementWithName(
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
435
bool ApplePropertyList::ExtractStringFromValueNode(const XMLNode &node,
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
456
static 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(
460
new StructuredData::Array());
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(
469
new StructuredData::Dictionary());
470
node.ForEachChildElement(
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);
491
return StructuredData::ObjectSP(new StructuredData::Float(value));
492
} else if (element_name == "integer") {
493
uint64_t value = 0;
494
node.GetElementTextAsUnsigned(value, 0, 0);
495
return StructuredData::ObjectSP(new StructuredData::UnsignedInteger(value));
496
} else if ((element_name == "string") || (element_name == "data") ||
497
(element_name == "date")) {
498
std::string text;
499
node.GetElementText(text);
500
return StructuredData::ObjectSP(
501
new StructuredData::String(std::move(text)));
502
} else if (element_name == "true") {
503
return StructuredData::ObjectSP(new StructuredData::Boolean(true));
504
} else if (element_name == "false") {
505
return StructuredData::ObjectSP(new StructuredData::Boolean(false));
506
}
507
return StructuredData::ObjectSP(new StructuredData::Null());
508
}
509
#endif
510
511
StructuredData::ObjectSP ApplePropertyList::GetStructuredData() {
512
StructuredData::ObjectSP root_sp;
513
#if LLDB_ENABLE_LIBXML2
514
if (IsValid()) {
515
return CreatePlistValue(m_dict_node);
516
}
517
#endif
518
return root_sp;
519
}
520
521