brintos

brintos / llvm-project-archived public Read only

0
0
Text · 13.8 KiB · f480ef3 Raw
520 lines · cpp
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-exception6//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-- XMLDocument18 19XMLDocument::XMLDocument() = default;20 21XMLDocument::~XMLDocument() { Clear(); }22 23void XMLDocument::Clear() {24#if LLDB_ENABLE_LIBXML225  if (m_document) {26    xmlDocPtr doc = m_document;27    m_document = nullptr;28    xmlFreeDoc(doc);29  }30#endif31}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_LIBXML246  Clear();47  xmlSetGenericErrorFunc((void *)this, XMLDocument::ErrorCallback);48  m_document = xmlParseFile(path);49  xmlSetGenericErrorFunc(nullptr, nullptr);50#endif51  return IsValid();52}53 54bool XMLDocument::ParseMemory(const char *xml, size_t xml_length,55                              const char *url) {56#if LLDB_ENABLE_LIBXML257  Clear();58  xmlSetGenericErrorFunc((void *)this, XMLDocument::ErrorCallback);59  m_document = xmlReadMemory(xml, (int)xml_length, url, nullptr, 0);60  xmlSetGenericErrorFunc(nullptr, nullptr);61#endif62  return IsValid();63}64 65XMLNode XMLDocument::GetRootElement(const char *required_name) {66#if LLDB_ENABLE_LIBXML267  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#endif78  return XMLNode();79}80 81llvm::StringRef XMLDocument::GetErrors() const { return m_errors.GetString(); }82 83bool XMLDocument::XMLEnabled() {84#if LLDB_ENABLE_LIBXML285  return true;86#else87  return false;88#endif89}90 91#pragma mark-- XMLNode92 93XMLNode::XMLNode() = default;94 95XMLNode::XMLNode(XMLNodeImpl node) : m_node(node) {}96 97XMLNode::~XMLNode() = default;98 99void XMLNode::Clear() { m_node = nullptr; }100 101XMLNode XMLNode::GetParent() const {102#if LLDB_ENABLE_LIBXML2103  if (IsValid())104    return XMLNode(m_node->parent);105  else106    return XMLNode();107#else108  return XMLNode();109#endif110}111 112XMLNode XMLNode::GetSibling() const {113#if LLDB_ENABLE_LIBXML2114  if (IsValid())115    return XMLNode(m_node->next);116  else117    return XMLNode();118#else119  return XMLNode();120#endif121}122 123XMLNode XMLNode::GetChild() const {124#if LLDB_ENABLE_LIBXML2125 126  if (IsValid())127    return XMLNode(m_node->children);128  else129    return XMLNode();130#else131  return XMLNode();132#endif133}134 135std::string XMLNode::GetAttributeValue(const char *name,136                                       const char *fail_value) const {137  std::string attr_value;138#if LLDB_ENABLE_LIBXML2139  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#else150  if (fail_value)151    attr_value = fail_value;152#endif153  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_LIBXML2164  if (IsValid())165    GetChild().ForEachSiblingNode(callback);166#endif167}168 169void XMLNode::ForEachChildElement(NodeCallback const &callback) const {170#if LLDB_ENABLE_LIBXML2171  XMLNode child = GetChild();172  if (child)173    child.ForEachSiblingElement(callback);174#endif175}176 177void XMLNode::ForEachChildElementWithName(const char *name,178                                          NodeCallback const &callback) const {179#if LLDB_ENABLE_LIBXML2180  XMLNode child = GetChild();181  if (child)182    child.ForEachSiblingElementWithName(name, callback);183#endif184}185 186void XMLNode::ForEachAttribute(AttributeCallback const &callback) const {187#if LLDB_ENABLE_LIBXML2188 189  if (IsValid()) {190    for (xmlAttrPtr attr = m_node->properties; attr != nullptr;191         attr = attr->next) {192      // check if name matches193      if (attr->name) {194        // check child is a text node195        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#endif207}208 209void XMLNode::ForEachSiblingNode(NodeCallback const &callback) const {210#if LLDB_ENABLE_LIBXML2211 212  if (IsValid()) {213    // iterate through all siblings214    for (xmlNodePtr node = m_node; node; node = node->next) {215      if (!callback(XMLNode(node)))216        return;217    }218  }219#endif220}221 222void XMLNode::ForEachSiblingElement(NodeCallback const &callback) const {223#if LLDB_ENABLE_LIBXML2224 225  if (IsValid()) {226    // iterate through all siblings227    for (xmlNodePtr node = m_node; node; node = node->next) {228      // we are looking for element nodes only229      if (node->type != XML_ELEMENT_NODE)230        continue;231 232      if (!callback(XMLNode(node)))233        return;234    }235  }236#endif237}238 239void XMLNode::ForEachSiblingElementWithName(240    const char *name, NodeCallback const &callback) const {241#if LLDB_ENABLE_LIBXML2242 243  if (IsValid()) {244    // iterate through all siblings245    for (xmlNodePtr node = m_node; node; node = node->next) {246      // we are looking for element nodes only247      if (node->type != XML_ELEMENT_NODE)248        continue;249 250      // If name is nullptr, we take all nodes of type "t", else just the ones251      // whose name matches252      if (name) {253        if (strcmp((const char *)node->name, name) != 0)254          continue; // Name mismatch, ignore this one255      } else {256        if (node->name)257          continue; // nullptr name specified and this element has a name,258                    // ignore this one259      }260 261      if (!callback(XMLNode(node)))262        return;263    }264  }265#endif266}267 268llvm::StringRef XMLNode::GetName() const {269#if LLDB_ENABLE_LIBXML2270  if (IsValid()) {271    if (m_node->name)272      return llvm::StringRef((const char *)m_node->name);273  }274#endif275  return llvm::StringRef();276}277 278bool XMLNode::GetElementText(std::string &text) const {279  text.clear();280#if LLDB_ENABLE_LIBXML2281  if (IsValid()) {282    bool success = false;283    if (m_node->type == XML_ELEMENT_NODE) {284      // check child is a text node285      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#endif296  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_LIBXML2316 317  if (IsValid()) {318    // In case we are looking for a nullptr name or an exact pointer match319    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#endif325  return false;326}327 328XMLNode XMLNode::FindFirstChildElementWithName(const char *name) const {329  XMLNode result_node;330 331#if LLDB_ENABLE_LIBXML2332  ForEachChildElementWithName(333      name, [&result_node](const XMLNode &node) -> bool {334        result_node = node;335        // Stop iterating, we found the node we wanted336        return false;337      });338#endif339 340  return result_node;341}342 343bool XMLNode::IsValid() const { return m_node != nullptr; }344 345bool XMLNode::IsElement() const {346#if LLDB_ENABLE_LIBXML2347  if (IsValid())348    return m_node->type == XML_ELEMENT_NODE;349#endif350  return false;351}352 353XMLNode XMLNode::GetElementForPath(const NamePath &path) {354#if LLDB_ENABLE_LIBXML2355 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#endif368 369  return XMLNode();370}371 372#pragma mark-- ApplePropertyList373 374ApplePropertyList::ApplePropertyList() : m_xml_doc(), m_dict_node() {}375 376ApplePropertyList::ApplePropertyList(const char *path)377    : m_xml_doc(), m_dict_node() {378  ParseFile(path);379}380 381ApplePropertyList::~ApplePropertyList() = default;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 iterating395                                        });396      return (bool)m_dict_node;397    }398  }399  return false;400}401 402bool ApplePropertyList::IsValid() const { return (bool)m_dict_node; }403 404bool 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 412XMLNode ApplePropertyList::GetValueNode(const char *key) const {413  XMLNode value_node;414#if LLDB_ENABLE_LIBXML2415 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 iterating426            }427          }428          return true; // Keep iterating429        });430  }431#endif432  return value_node;433}434 435bool ApplePropertyList::ExtractStringFromValueNode(const XMLNode &node,436                                                   std::string &value) {437  value.clear();438#if LLDB_ENABLE_LIBXML2439  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 fail447    else448      return node.GetElementText(value);449  }450#endif451  return false;452}453 454#if LLDB_ENABLE_LIBXML2455 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(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 array464    });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 node474            key_node = node;475          } else {476            // This is a value node477            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 the485                       // dictionary486        });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#endif510 511StructuredData::ObjectSP ApplePropertyList::GetStructuredData() {512  StructuredData::ObjectSP root_sp;513#if LLDB_ENABLE_LIBXML2514  if (IsValid()) {515    return CreatePlistValue(m_dict_node);516  }517#endif518  return root_sp;519}520