diff options
Diffstat (limited to 'src/xmpp/xmpp_stanza.cpp')
-rw-r--r-- | src/xmpp/xmpp_stanza.cpp | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/src/xmpp/xmpp_stanza.cpp b/src/xmpp/xmpp_stanza.cpp new file mode 100644 index 0000000..435f333 --- /dev/null +++ b/src/xmpp/xmpp_stanza.cpp @@ -0,0 +1,229 @@ +#include <xmpp/xmpp_stanza.hpp> + +#include <utils/encoding.hpp> +#include <utils/split.hpp> + +#include <stdexcept> +#include <iostream> +#include <sstream> + +#include <cstring> + +std::string xml_escape(const std::string& data) +{ + std::string res; + res.reserve(data.size()); + for (size_t pos = 0; pos != data.size(); ++pos) + { + switch(data[pos]) + { + case '&': + res += "&"; + break; + case '<': + res += "<"; + break; + case '>': + res += ">"; + break; + case '\"': + res += """; + break; + case '\'': + res += "'"; + break; + default: + res += data[pos]; + break; + } + } + return res; +} + +std::string sanitize(const std::string& data, const std::string& encoding) +{ + if (utils::is_valid_utf8(data.data())) + return xml_escape(utils::remove_invalid_xml_chars(data)); + else + return xml_escape(utils::remove_invalid_xml_chars(utils::convert_to_utf8(data, encoding.data()))); +} + +XmlNode::XmlNode(const std::string& name, XmlNode* parent): + parent(parent) +{ + // split the namespace and the name + auto n = name.rfind(':'); + if (n == std::string::npos) + this->name = name; + else + { + this->name = name.substr(n+1); + this->attributes["xmlns"] = name.substr(0, n); + } +} + +XmlNode::XmlNode(const std::string& name): + XmlNode(name, nullptr) +{ +} + +void XmlNode::delete_all_children() +{ + this->children.clear(); +} + +void XmlNode::set_attribute(const std::string& name, const std::string& value) +{ + this->attributes[name] = value; +} + +void XmlNode::set_tail(const std::string& data) +{ + this->tail = data; +} + +void XmlNode::add_to_tail(const std::string& data) +{ + this->tail += data; +} + +void XmlNode::set_inner(const std::string& data) +{ + this->inner = data; +} + +void XmlNode::add_to_inner(const std::string& data) +{ + this->inner += data; +} + +std::string XmlNode::get_inner() const +{ + return this->inner; +} + +std::string XmlNode::get_tail() const +{ + return this->tail; +} + +const XmlNode* XmlNode::get_child(const std::string& name, const std::string& xmlns) const +{ + for (const auto& child: this->children) + { + if (child->name == name && child->get_tag("xmlns") == xmlns) + return child.get(); + } + return nullptr; +} + +std::vector<const XmlNode*> XmlNode::get_children(const std::string& name, const std::string& xmlns) const +{ + std::vector<const XmlNode*> res; + for (const auto& child: this->children) + { + if (child->name == name && child->get_tag("xmlns") == xmlns) + res.push_back(child.get()); + } + return res; +} + +XmlNode* XmlNode::add_child(std::unique_ptr<XmlNode> child) +{ + child->parent = this; + auto ret = child.get(); + this->children.push_back(std::move(child)); + return ret; +} + +XmlNode* XmlNode::add_child(XmlNode&& child) +{ + auto new_node = std::make_unique<XmlNode>(std::move(child)); + return this->add_child(std::move(new_node)); +} + +XmlNode* XmlNode::add_child(const XmlNode& child) +{ + auto new_node = std::make_unique<XmlNode>(child); + return this->add_child(std::move(new_node)); +} + +XmlNode* XmlNode::get_last_child() const +{ + return this->children.back().get(); +} + +XmlNode* XmlNode::get_parent() const +{ + return this->parent; +} + +void XmlNode::set_name(const std::string& name) +{ + this->name = name; +} + +void XmlNode::set_name(std::string&& name) +{ + this->name = std::move(name); +} + +const std::string XmlNode::get_name() const +{ + return this->name; +} + +std::string XmlNode::to_string() const +{ + std::ostringstream res; + res << "<" << this->name; + for (const auto& it: this->attributes) + res << " " << it.first << "='" << sanitize(it.second) + "'"; + if (!this->has_children() && this->inner.empty()) + res << "/>"; + else + { + res << ">" + sanitize(this->inner); + for (const auto& child: this->children) + res << child->to_string(); + res << "</" << this->get_name() << ">"; + } + res << sanitize(this->tail); + return res.str(); +} + +bool XmlNode::has_children() const +{ + return !this->children.empty(); +} + +const std::string& XmlNode::get_tag(const std::string& name) const +{ + try + { + const auto& value = this->attributes.at(name); + return value; + } + catch (const std::out_of_range& e) + { + static const std::string def{}; + return def; + } +} + +bool XmlNode::del_tag(const std::string& name) +{ + if (this->attributes.erase(name) != 0) + return true; + return false; +} + +std::string& XmlNode::operator[](const std::string& name) +{ + return this->attributes[name]; +} + +std::ostream& operator<<(std::ostream& os, const XmlNode& node) +{ + return os << node.to_string(); +} |