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