]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Host/common/XML.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[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 bool XMLNode::GetAttributeValueAsUnsigned(const char *name, uint64_t &value,
155                                           uint64_t fail_value, int base) const {
156 #if defined(LIBXML2_DEFINED)
157   llvm::StringRef str_value = GetAttributeValue(name, "");
158 #else
159   llvm::StringRef str_value;
160 #endif
161   bool success = false;
162   value = StringConvert::ToUInt64(str_value.data(), fail_value, base, &success);
163   return success;
164 }
165
166 void XMLNode::ForEachChildNode(NodeCallback const &callback) const {
167 #if defined(LIBXML2_DEFINED)
168   if (IsValid())
169     GetChild().ForEachSiblingNode(callback);
170 #endif
171 }
172
173 void XMLNode::ForEachChildElement(NodeCallback const &callback) const {
174 #if defined(LIBXML2_DEFINED)
175   XMLNode child = GetChild();
176   if (child)
177     child.ForEachSiblingElement(callback);
178 #endif
179 }
180
181 void XMLNode::ForEachChildElementWithName(const char *name,
182                                           NodeCallback const &callback) const {
183 #if defined(LIBXML2_DEFINED)
184   XMLNode child = GetChild();
185   if (child)
186     child.ForEachSiblingElementWithName(name, callback);
187 #endif
188 }
189
190 void XMLNode::ForEachAttribute(AttributeCallback const &callback) const {
191 #if defined(LIBXML2_DEFINED)
192
193   if (IsValid()) {
194     for (xmlAttrPtr attr = m_node->properties; attr != nullptr;
195          attr = attr->next) {
196       // check if name matches
197       if (attr->name) {
198         // check child is a text node
199         xmlNodePtr child = attr->children;
200         if (child->type == XML_TEXT_NODE) {
201           llvm::StringRef attr_value;
202           if (child->content)
203             attr_value = llvm::StringRef((const char *)child->content);
204           if (!callback(llvm::StringRef((const char *)attr->name), attr_value))
205             return;
206         }
207       }
208     }
209   }
210 #endif
211 }
212
213 void XMLNode::ForEachSiblingNode(NodeCallback const &callback) const {
214 #if defined(LIBXML2_DEFINED)
215
216   if (IsValid()) {
217     // iterate through all siblings
218     for (xmlNodePtr node = m_node; node; node = node->next) {
219       if (!callback(XMLNode(node)))
220         return;
221     }
222   }
223 #endif
224 }
225
226 void XMLNode::ForEachSiblingElement(NodeCallback const &callback) const {
227 #if defined(LIBXML2_DEFINED)
228
229   if (IsValid()) {
230     // iterate through all siblings
231     for (xmlNodePtr node = m_node; node; node = node->next) {
232       // we are looking for element nodes only
233       if (node->type != XML_ELEMENT_NODE)
234         continue;
235
236       if (!callback(XMLNode(node)))
237         return;
238     }
239   }
240 #endif
241 }
242
243 void XMLNode::ForEachSiblingElementWithName(
244     const char *name, NodeCallback const &callback) const {
245 #if defined(LIBXML2_DEFINED)
246
247   if (IsValid()) {
248     // iterate through all siblings
249     for (xmlNodePtr node = m_node; node; node = node->next) {
250       // we are looking for element nodes only
251       if (node->type != XML_ELEMENT_NODE)
252         continue;
253
254       // If name is nullptr, we take all nodes of type "t", else just the ones
255       // whose name matches
256       if (name) {
257         if (strcmp((const char *)node->name, name) != 0)
258           continue; // Name mismatch, ignore this one
259       } else {
260         if (node->name)
261           continue; // nullptr name specified and this element has a name,
262                     // ignore this one
263       }
264
265       if (!callback(XMLNode(node)))
266         return;
267     }
268   }
269 #endif
270 }
271
272 llvm::StringRef XMLNode::GetName() const {
273 #if defined(LIBXML2_DEFINED)
274   if (IsValid()) {
275     if (m_node->name)
276       return llvm::StringRef((const char *)m_node->name);
277   }
278 #endif
279   return llvm::StringRef();
280 }
281
282 bool XMLNode::GetElementText(std::string &text) const {
283   text.clear();
284 #if defined(LIBXML2_DEFINED)
285   if (IsValid()) {
286     bool success = false;
287     if (m_node->type == XML_ELEMENT_NODE) {
288       // check child is a text node
289       for (xmlNodePtr node = m_node->children; node != nullptr;
290            node = node->next) {
291         if (node->type == XML_TEXT_NODE) {
292           text.append((const char *)node->content);
293           success = true;
294         }
295       }
296     }
297     return success;
298   }
299 #endif
300   return false;
301 }
302
303 bool XMLNode::GetElementTextAsUnsigned(uint64_t &value, uint64_t fail_value,
304                                        int base) const {
305   bool success = false;
306 #if defined(LIBXML2_DEFINED)
307   if (IsValid()) {
308     std::string text;
309     if (GetElementText(text))
310       value = StringConvert::ToUInt64(text.c_str(), fail_value, base, &success);
311   }
312 #endif
313   if (!success)
314     value = fail_value;
315   return success;
316 }
317
318 bool XMLNode::GetElementTextAsFloat(double &value, double fail_value) const {
319   bool success = false;
320 #if defined(LIBXML2_DEFINED)
321   if (IsValid()) {
322     std::string text;
323     if (GetElementText(text)) {
324       value = atof(text.c_str());
325       success = true;
326     }
327   }
328 #endif
329   if (!success)
330     value = fail_value;
331   return success;
332 }
333
334 bool XMLNode::NameIs(const char *name) const {
335 #if defined(LIBXML2_DEFINED)
336
337   if (IsValid()) {
338     // In case we are looking for a nullptr name or an exact pointer match
339     if (m_node->name == (const xmlChar *)name)
340       return true;
341     if (m_node->name)
342       return strcmp((const char *)m_node->name, name) == 0;
343   }
344 #endif
345   return false;
346 }
347
348 XMLNode XMLNode::FindFirstChildElementWithName(const char *name) const {
349   XMLNode result_node;
350
351 #if defined(LIBXML2_DEFINED)
352   ForEachChildElementWithName(
353       name, [&result_node](const XMLNode &node) -> bool {
354         result_node = node;
355         // Stop iterating, we found the node we wanted
356         return false;
357       });
358 #endif
359
360   return result_node;
361 }
362
363 bool XMLNode::IsValid() const { return m_node != nullptr; }
364
365 bool XMLNode::IsElement() const {
366 #if defined(LIBXML2_DEFINED)
367   if (IsValid())
368     return m_node->type == XML_ELEMENT_NODE;
369 #endif
370   return false;
371 }
372
373 XMLNode XMLNode::GetElementForPath(const NamePath &path) {
374 #if defined(LIBXML2_DEFINED)
375
376   if (IsValid()) {
377     if (path.empty())
378       return *this;
379     else {
380       XMLNode node = FindFirstChildElementWithName(path[0].c_str());
381       const size_t n = path.size();
382       for (size_t i = 1; node && i < n; ++i)
383         node = node.FindFirstChildElementWithName(path[i].c_str());
384       return node;
385     }
386   }
387 #endif
388
389   return XMLNode();
390 }
391
392 #pragma mark-- ApplePropertyList
393
394 ApplePropertyList::ApplePropertyList() : m_xml_doc(), m_dict_node() {}
395
396 ApplePropertyList::ApplePropertyList(const char *path)
397     : m_xml_doc(), m_dict_node() {
398   ParseFile(path);
399 }
400
401 ApplePropertyList::~ApplePropertyList() {}
402
403 llvm::StringRef ApplePropertyList::GetErrors() const {
404   return m_xml_doc.GetErrors();
405 }
406
407 bool ApplePropertyList::ParseFile(const char *path) {
408   if (m_xml_doc.ParseFile(path)) {
409     XMLNode plist = m_xml_doc.GetRootElement("plist");
410     if (plist) {
411       plist.ForEachChildElementWithName("dict",
412                                         [this](const XMLNode &dict) -> bool {
413                                           this->m_dict_node = dict;
414                                           return false; // Stop iterating
415                                         });
416       return (bool)m_dict_node;
417     }
418   }
419   return false;
420 }
421
422 bool ApplePropertyList::IsValid() const { return (bool)m_dict_node; }
423
424 bool ApplePropertyList::GetValueAsString(const char *key,
425                                          std::string &value) const {
426   XMLNode value_node = GetValueNode(key);
427   if (value_node)
428     return ApplePropertyList::ExtractStringFromValueNode(value_node, value);
429   return false;
430 }
431
432 XMLNode ApplePropertyList::GetValueNode(const char *key) const {
433   XMLNode value_node;
434 #if defined(LIBXML2_DEFINED)
435
436   if (IsValid()) {
437     m_dict_node.ForEachChildElementWithName(
438         "key", [key, &value_node](const XMLNode &key_node) -> bool {
439           std::string key_name;
440           if (key_node.GetElementText(key_name)) {
441             if (key_name == key) {
442               value_node = key_node.GetSibling();
443               while (value_node && !value_node.IsElement())
444                 value_node = value_node.GetSibling();
445               return false; // Stop iterating
446             }
447           }
448           return true; // Keep iterating
449         });
450   }
451 #endif
452   return value_node;
453 }
454
455 bool ApplePropertyList::ExtractStringFromValueNode(const XMLNode &node,
456                                                    std::string &value) {
457   value.clear();
458 #if defined(LIBXML2_DEFINED)
459   if (node.IsValid()) {
460     llvm::StringRef element_name = node.GetName();
461     if (element_name == "true" || element_name == "false") {
462       // The text value _is_ the element name itself...
463       value = element_name.str();
464       return true;
465     } else if (element_name == "dict" || element_name == "array")
466       return false; // dictionaries and arrays have no text value, so we fail
467     else
468       return node.GetElementText(value);
469   }
470 #endif
471   return false;
472 }
473
474 #if defined(LIBXML2_DEFINED)
475
476 namespace {
477
478 StructuredData::ObjectSP CreatePlistValue(XMLNode node) {
479   llvm::StringRef element_name = node.GetName();
480   if (element_name == "array") {
481     std::shared_ptr<StructuredData::Array> array_sp(
482         new StructuredData::Array());
483     node.ForEachChildElement([&array_sp](const XMLNode &node) -> bool {
484       array_sp->AddItem(CreatePlistValue(node));
485       return true; // Keep iterating through all child elements of the array
486     });
487     return array_sp;
488   } else if (element_name == "dict") {
489     XMLNode key_node;
490     std::shared_ptr<StructuredData::Dictionary> dict_sp(
491         new StructuredData::Dictionary());
492     node.ForEachChildElement(
493         [&key_node, &dict_sp](const XMLNode &node) -> bool {
494           if (node.NameIs("key")) {
495             // This is a "key" element node
496             key_node = node;
497           } else {
498             // This is a value node
499             if (key_node) {
500               std::string key_name;
501               key_node.GetElementText(key_name);
502               dict_sp->AddItem(key_name, CreatePlistValue(node));
503               key_node.Clear();
504             }
505           }
506           return true; // Keep iterating through all child elements of the
507                        // dictionary
508         });
509     return dict_sp;
510   } else if (element_name == "real") {
511     double value = 0.0;
512     node.GetElementTextAsFloat(value);
513     return StructuredData::ObjectSP(new StructuredData::Float(value));
514   } else if (element_name == "integer") {
515     uint64_t value = 0;
516     node.GetElementTextAsUnsigned(value, 0, 0);
517     return StructuredData::ObjectSP(new StructuredData::Integer(value));
518   } else if ((element_name == "string") || (element_name == "data") ||
519              (element_name == "date")) {
520     std::string text;
521     node.GetElementText(text);
522     return StructuredData::ObjectSP(
523         new StructuredData::String(std::move(text)));
524   } else if (element_name == "true") {
525     return StructuredData::ObjectSP(new StructuredData::Boolean(true));
526   } else if (element_name == "false") {
527     return StructuredData::ObjectSP(new StructuredData::Boolean(false));
528   }
529   return StructuredData::ObjectSP(new StructuredData::Null());
530 }
531 }
532 #endif
533
534 StructuredData::ObjectSP ApplePropertyList::GetStructuredData() {
535   StructuredData::ObjectSP root_sp;
536 #if defined(LIBXML2_DEFINED)
537   if (IsValid()) {
538     return CreatePlistValue(m_dict_node);
539   }
540 #endif
541   return root_sp;
542 }