You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

IXMLNode.cpp 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. #include "IXMLNode.h"
  2. #include <string>
  3. #include <cstring>
  4. #include <stdexcept>
  5. #include <vector>
  6. #include <map>
  7. //This is to remove the warning on windows about strdup
  8. #if defined TARGET_OS_Windows
  9. #define strdup _strdup
  10. #endif
  11. namespace XML {
  12. class IXMLNodeImpl final : public IXMLNode
  13. {
  14. public:
  15. explicit IXMLNodeImpl(const char* name) : m_name(name) {}
  16. const char* getName() const override { return m_name.c_str(); }
  17. void release() override { delete this; }
  18. //Attribute
  19. bool addAttribute(const char* name, const char* value) override;
  20. bool hasAttribute(const char* name) const override { return m_attibutes.count(name) != 0; }
  21. const char* getAttribute(const char* name) const override;
  22. //PCDATA
  23. void setPCData(const char* data) override;
  24. void appendPCData(const char* data) override;
  25. const char* getPCData() const override { return m_pcData.c_str(); }
  26. //Child
  27. void addChild(IXMLNode* node) override { m_nodes.push_back(node); }
  28. IXMLNode* getChild(const size_t index) const override { return m_nodes[index]; }
  29. IXMLNode* getChildByName(const char* name) const override;
  30. size_t getChildCount() const override;
  31. //XMl generation
  32. char* getXML(const size_t depth = 0) const override;
  33. protected:
  34. ~IXMLNodeImpl() override { for (size_t i = 0; i < getChildCount(); ++i) { getChild(i)->release(); } }
  35. private:
  36. static std::string sanitize(const std::string& str);
  37. static void applyIndentation(std::string& str, const size_t depth);
  38. std::vector<IXMLNode*> m_nodes;
  39. std::map<std::string, std::string> m_attibutes;
  40. std::string m_name = "";
  41. std::string m_pcData = "";
  42. bool m_hasPCData = false;
  43. };
  44. bool IXMLNodeImpl::addAttribute(const char* name, const char* value)
  45. {
  46. m_attibutes[name] = value;
  47. return true;
  48. }
  49. const char* IXMLNodeImpl::getAttribute(const char* name) const
  50. {
  51. const char* res = nullptr;
  52. const std::string str(name);
  53. const auto it = m_attibutes.find(str);
  54. if (it != m_attibutes.end()) { res = (*it).second.c_str(); }
  55. return res;
  56. }
  57. void IXMLNodeImpl::setPCData(const char* data)
  58. {
  59. m_pcData = data;
  60. m_hasPCData = true;
  61. }
  62. void IXMLNodeImpl::appendPCData(const char* data)
  63. {
  64. m_pcData += data;
  65. m_hasPCData = true;
  66. }
  67. IXMLNode* IXMLNodeImpl::getChildByName(const char* name) const
  68. {
  69. for (auto it = m_nodes.begin(); it != m_nodes.end(); ++it)
  70. {
  71. IXMLNode* node = static_cast<IXMLNode*>(*it);
  72. if (strcmp(node->getName(), name) == 0) { return node; }
  73. }
  74. return nullptr;
  75. }
  76. size_t IXMLNodeImpl::getChildCount() const { return m_nodes.size(); }
  77. std::string IXMLNodeImpl::sanitize(const std::string& str)
  78. {
  79. std::string::size_type i;
  80. std::string res(str);
  81. if (res.length() != 0)
  82. {
  83. // mandatory, this one should be the first because the other ones add & symbols
  84. for (i = res.find('&', 0); i != std::string::npos; i = res.find('&', i + 1)) { res.replace(i, 1, "&amp;"); }
  85. // other escape sequences
  86. for (i = res.find('\"', 0); i != std::string::npos; i = res.find('\"', i + 1)) { res.replace(i, 1, "&quot;"); }
  87. for (i = res.find('<', 0); i != std::string::npos; i = res.find('<', i + 1)) { res.replace(i, 1, "&lt;"); }
  88. for (i = res.find('>', 0); i != std::string::npos; i = res.find('>', i + 1)) { res.replace(i, 1, "&gt;"); }
  89. }
  90. return res;
  91. }
  92. void IXMLNodeImpl::applyIndentation(std::string& str, const size_t depth)
  93. {
  94. const std::string indent(depth, '\t');
  95. str.append(indent);
  96. }
  97. char* IXMLNodeImpl::getXML(const size_t depth) const
  98. {
  99. std::string str;
  100. applyIndentation(str, depth);
  101. str += "<" + m_name;
  102. //Add attributes if we have some
  103. if (!m_attibutes.empty())
  104. {
  105. for (auto it = m_attibutes.begin(); it != m_attibutes.end(); ++it) { str += " " + it->first + "=\"" + sanitize(it->second) + "\""; }
  106. }
  107. //If we have nothing else to print let's close the node and return
  108. if (!m_hasPCData && m_nodes.empty())
  109. {
  110. str += "/>";
  111. return ::strdup(str.c_str());
  112. }
  113. str += ">";
  114. if (m_hasPCData) { str = str + sanitize(m_pcData); }
  115. for (auto it = m_nodes.begin(); it != m_nodes.end(); ++it)
  116. {
  117. IXMLNode* node = static_cast<IXMLNode*>(*it);
  118. str += std::string("\n") + node->getXML(depth + 1);
  119. }
  120. if (!m_nodes.empty())
  121. {
  122. str = str + "\n";
  123. applyIndentation(str, depth);
  124. }
  125. str = str + "</" + m_name + ">";
  126. return ::strdup(str.c_str());
  127. }
  128. OV_API IXMLNode* createNode(const char* name) { return new IXMLNodeImpl(name); }
  129. } // namespace XML