/* * The Mana Client * Copyright (C) 2004-2009 The Mana World Development Team * Copyright (C) 2009-2012 The Mana Developers * * This file is part of The Mana Client. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "utils/stringutils.h" #include #include #include #include /** * XML helper functions. */ namespace XML { class Node { public: Node(xmlNodePtr node = nullptr) : node(node) {} operator bool() const { return node != nullptr; } std::string_view name() const { return (const char *) node->name; } std::string_view textContent() const; template bool attribute(const char *name, T &value) const; bool hasAttribute(const char *name) const; int getProperty(const char *name, int def) const; double getFloatProperty(const char *name, double def) const; std::string getProperty(const char *name, const std::string &def) const; bool getBoolProperty(const char *name, bool def) const; Node findFirstChildByName(const char *name) const; /** * Helper class to iterate over the children of a node. Enables * range-based for loops. */ class Children { public: class Iterator { public: explicit Iterator(xmlNodePtr node) : mNode(node) { while (mNode && mNode->type != XML_ELEMENT_NODE) mNode = mNode->next; } bool operator!=(const Iterator &other) const { return mNode != other.mNode; } void operator++() { do { mNode = mNode->next; } while (mNode && mNode->type != XML_ELEMENT_NODE); } Node operator*() const { return mNode; } private: xmlNodePtr mNode; }; explicit Children(xmlNodePtr node) : mNode(node) {} Iterator begin() const { return Iterator(mNode->children); } Iterator end() const { return Iterator(nullptr); } private: xmlNodePtr mNode; }; Children children() const { return Children(node); } private: const char *attribute(const char *name) const; xmlNodePtr node; }; inline std::string_view Node::textContent() const { if (node->children && node->children->type == XML_TEXT_NODE) return (const char *) node->children->content; return {}; } inline const char *Node::attribute(const char *name) const { if (node->type != XML_ELEMENT_NODE) return nullptr; for (xmlAttrPtr prop = node->properties; prop; prop = prop->next) { if (xmlStrEqual(prop->name, BAD_CAST name)) { if (prop->children) return reinterpret_cast(prop->children->content); else return nullptr; } } return nullptr; } template inline bool Node::attribute(const char *name, T &value) const { if (const char *str = attribute(name)) { fromString(str, value); return true; } return false; } inline bool Node::hasAttribute(const char *name) const { return attribute(name) != nullptr; } inline int Node::getProperty(const char *name, int def) const { int ret = def; if (const char *str = attribute(name)) fromString(str, ret); return ret; } inline double Node::getFloatProperty(const char *name, double def) const { double ret = def; if (const char *str = attribute(name)) fromString(str, ret); return ret; } inline std::string Node::getProperty(const char *name, const std::string &def) const { if (const char *str = attribute(name)) return str; return def; } inline bool Node::getBoolProperty(const char *name, bool def) const { bool ret = def; if (const char *str = attribute(name)) ret = getBoolFromString(str, def); return ret; } inline Node Node::findFirstChildByName(const char *name) const { for (auto child : children()) if (child.name() == name) return child; return nullptr; } /** * A helper class for parsing an XML document, which also cleans it up * again (RAII). */ class Document { public: /** * Constructor that attempts to load the given file through the * resource manager. Logs errors. */ Document(const std::string &filename, bool useResman = true); /** * Destructor. Frees the loaded XML file. */ ~Document(); /** * Returns the root node of the document (or NULL if there was a * load error). */ Node rootNode() const; private: xmlDocPtr mDoc; }; inline Node Document::rootNode() const { return mDoc ? xmlDocGetRootElement(mDoc) : nullptr; } /** * Initializes the XML engine. */ void init(); /** * Helper class for writing out XML data. * * Based on libxml2's text writing API for XML. */ class Writer { public: Writer(const std::string &fileName); ~Writer(); bool isValid() const { return mWriter != nullptr; } void startElement(const char *name); void endElement(); void addAttribute(const char *name, const std::string &value); void addAttribute(const char *name, const char *value); void addAttribute(const char *name, int value); void addAttribute(const char *name, unsigned value); void addAttribute(const char *name, float value); void addAttribute(const char *name, bool value); template, bool> = true> void addAttribute(const char *name, Enum &value); void writeText(const std::string &text); private: xmlTextWriterPtr mWriter; }; template, bool>> inline void Writer::addAttribute(const char *name, Enum &value) { return addAttribute(name, static_cast(value)); } inline void Writer::startElement(const char *name) { xmlTextWriterStartElement(mWriter, BAD_CAST name); } inline void Writer::endElement() { xmlTextWriterEndElement(mWriter); } inline void Writer::addAttribute(const char *name, const std::string &value) { addAttribute(name, value.c_str()); } inline void Writer::addAttribute(const char *name, const char *value) { xmlTextWriterWriteAttribute(mWriter, BAD_CAST name, BAD_CAST value); } inline void Writer::addAttribute(const char *name, int value) { xmlTextWriterWriteAttribute(mWriter, BAD_CAST name, BAD_CAST toString(value).c_str()); } inline void Writer::addAttribute(const char *name, unsigned value) { xmlTextWriterWriteAttribute(mWriter, BAD_CAST name, BAD_CAST toString(value).c_str()); } inline void Writer::addAttribute(const char *name, float value) { xmlTextWriterWriteAttribute(mWriter, BAD_CAST name, BAD_CAST toString(value).c_str()); } inline void Writer::addAttribute(const char *name, bool value) { xmlTextWriterWriteAttribute(mWriter, BAD_CAST name, BAD_CAST (value ? "1" : "0")); } inline void Writer::writeText(const std::string &text) { xmlTextWriterWriteString(mWriter, BAD_CAST text.c_str()); } }