diff options
Diffstat (limited to 'src/Common/XmlData.h')
-rw-r--r-- | src/Common/XmlData.h | 493 |
1 files changed, 493 insertions, 0 deletions
diff --git a/src/Common/XmlData.h b/src/Common/XmlData.h new file mode 100644 index 0000000..216b0f1 --- /dev/null +++ b/src/Common/XmlData.h @@ -0,0 +1,493 @@ +/* + * XmlData.h + * + * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de> + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef MAD_COMMON_XMLDATA_H_ +#define MAD_COMMON_XMLDATA_H_ + +#include "export.h" + +#include <Net/Packet.h> + +#include <map> +#include <string> +#include <sstream> +#include <vector> + +#include <libxml/parser.h> + +#include <boost/cstdint.hpp> +#include <boost/noncopyable.hpp> +#include <boost/variant/get.hpp> +#include <boost/variant/variant.hpp> +#include <boost/smart_ptr.hpp> + +#include <iostream> + +namespace Mad { +namespace Common { + +class MAD_COMMON_EXPORT XmlData { + public: + class Entry; + class List; + + private: + xmlDocPtr doc; + xmlNodePtr rootNode; + Entry *entry; + + class MAD_COMMON_EXPORT Element : private boost::noncopyable { + private: + friend class Entry; + + enum Type { + NONE, BINARY, + INT, UINT, INT64, UINT64, + FLOAT, DOUBLE, LONGDOUBLE, STRING + }; + + typedef boost::variant<long, unsigned long, long long, unsigned long long, float, double, long double, std::vector<boost::uint8_t> > Variant; + + xmlNodePtr elementNode; + + Type type; + Variant value; + + std::string str; + + void updateStr(); + + Element(xmlNodePtr node); + + template <typename T> + void set(T val, Type type0) { + type = type0; + value = val; + + updateStr(); + } + + void set(int val) { + set<long>(val, INT); + } + + void set(unsigned int val) { + set<unsigned long>(val, UINT); + } + + void set(long val) { + set(val, INT); + } + + void set(unsigned long val) { + set(val, UINT); + } + + void set(long long val) { + set(val, INT64); + } + + void set(unsigned long long val) { + set(val, UINT64); + } + + void set(float val) { + set(val, FLOAT); + } + + void set(double val) { + set(val, DOUBLE); + } + + void set(long double val) { + set(val, LONGDOUBLE); + } + + void set(const std::string &val) { + type = STRING; + value = Element::Variant(); + str = val; + updateStr(); + } + + void set(const std::vector<boost::uint8_t> &val) { + set(val, BINARY); + } + }; + + public: + class MAD_COMMON_EXPORT Entry : private boost::noncopyable { + private: + friend class List; + friend class XmlData; + + xmlNodePtr entryNode; + + std::map<std::string, Element*> elements; + std::map<std::string, List*> lists; + + Element* getElement(const std::string &name) { + std::map<std::string, Element*>::iterator element = elements.find(name); + + if(element != elements.end()) + return element->second; + + if(lists.find(name) != lists.end()) + return 0; + + xmlNodePtr newNode = xmlNewTextChild(entryNode, 0, (xmlChar*)"value", (xmlChar*)""); + xmlSetProp(newNode, (xmlChar*)"name", (xmlChar*)name.c_str()); + xmlSetProp(newNode, (xmlChar*)"type", (xmlChar*)""); + + Element* newElement = new Element(newNode); + + elements.insert(std::make_pair(name, newElement)); + + return newElement; + } + + Element* getElement(const std::string &name) const { + std::map<std::string, Element*>::const_iterator element = elements.find(name); + + if(element != elements.end()) + return element->second; + else + return 0; + } + + Entry(xmlNodePtr node); + ~Entry() { + for(std::map<std::string, Element*>::iterator element = elements.begin(); element != elements.end(); ++element) + delete element->second; + + for(std::map<std::string, List*>::iterator list = lists.begin(); list != lists.end(); ++list) + delete list->second; + } + + public: + template <typename T> + bool set(const std::string &name, T val) { + Element *element = getElement(name); + if(!element) + return false; + + element->set(val); + + return true; + } + + template <typename T> + T get(const std::string &name) const { + Element *element = getElement(name); + if(!element) + return T(); + + switch(element->type) { + case Element::INT: + return static_cast<T>(boost::get<long>(element->value)); + case Element::UINT: + return static_cast<T>(boost::get<unsigned long>(element->value)); + case Element::INT64: + return static_cast<T>(boost::get<long long>(element->value)); + case Element::UINT64: + return static_cast<T>(boost::get<unsigned long long>(element->value)); + case Element::FLOAT: + return static_cast<T>(boost::get<float>(element->value)); + case Element::DOUBLE: + return static_cast<T>(boost::get<double>(element->value)); + case Element::LONGDOUBLE: + return static_cast<T>(boost::get<long double>(element->value)); + default: + return static_cast<T>(0); + } + } + + List* createList(const std::string &name, bool unique = false) { + std::map<std::string, List*>::iterator list = lists.find(name); + + if(list != lists.end()) + return unique ? 0 : list->second; + + if(elements.find(name) != elements.end()) + return 0; + + xmlNodePtr newNode = xmlNewChild(entryNode, 0, (xmlChar*)"list", 0); + xmlSetProp(newNode, (xmlChar*)"name", (xmlChar*)name.c_str()); + + List *newList = new List(newNode); + + lists.insert(std::make_pair(name, newList)); + + return newList; + } + + List* getList(const std::string &name) { + std::map<std::string, List*>::iterator list = lists.find(name); + + if(list == lists.end()) + return 0; + + return list->second; + } + + const List* getList(const std::string &name) const { + std::map<std::string, List*>::const_iterator list = lists.find(name); + + if(list == lists.end()) + return 0; + + return list->second; + } + + void unset(const std::string &name) { + std::map<std::string, Element*>::iterator element = elements.find(name); + + if(element != elements.end()) { + xmlUnlinkNode(element->second->elementNode); + xmlFreeNode(element->second->elementNode); + + delete element->second; + + elements.erase(element); + + return; + } + + std::map<std::string, List*>::iterator list = lists.find(name); + + if(list != lists.end()) { + xmlUnlinkNode(list->second->elementNode); + xmlFreeNode(list->second->elementNode); + + delete list->second; + + lists.erase(list); + + return; + } + + return; + } + }; + + class MAD_COMMON_EXPORT List : private boost::noncopyable { + private: + friend class Entry; + + xmlNodePtr elementNode; + + std::vector<Entry*> entries; + + template <typename Type, typename IteratorType> + class iterator_base { + public: + friend class List; + + typedef Type value_type; + + typedef value_type &reference; + typedef value_type *pointer; + + typedef long difference_type; + + private: + IteratorType it; + + iterator_base(IteratorType it0) : it(it0) {} + + public: + iterator_base() {} + + reference operator*() const { + return **it; + } + + iterator_base operator+(const difference_type &n) const { + return iterator(it+n); + } + + iterator_base operator++(int) { + return iterator(it++); + } + + iterator_base& operator++() { + ++it; + return *this; + } + + iterator_base& operator+=(const difference_type &n) { + it += n; + return *this; + } + + iterator_base operator-(const difference_type &n) const { + return iterator(it-n); + } + + iterator_base operator--(int) { + return iterator(it--); + } + + iterator_base& operator--() { + --it; + return *this; + } + + iterator_base& operator-=(const difference_type &n) { + it -= n; + return *this; + } + + bool operator==(const iterator_base &it2) { + return it2.it == it; + } + + bool operator!=(const iterator_base &it2) { + return it2.it != it; + } + + pointer operator->() const { + return *it; + } + + reference operator[](const difference_type &n) const { + return *it[n]; + } + }; + + List(xmlNodePtr node); + ~List() { + for(std::vector<Entry*>::iterator entry = entries.begin(); entry != entries.end(); ++entry) + delete *entry; + } + + public: + typedef iterator_base<Entry, std::vector<Entry*>::iterator> iterator; + typedef iterator_base<const Entry, std::vector<Entry*>::const_iterator> const_iterator; + + size_t getSize() const { + return entries.size(); + } + + bool isEmpty() const { + return entries.empty(); + } + + Entry& operator[](size_t i) { + return *entries[i]; + } + + const Entry& operator[](size_t i) const { + return *entries[i]; + } + + iterator begin() { + return iterator(entries.begin()); + } + + const_iterator begin() const { + return const_iterator(entries.begin()); + } + + iterator end() { + return iterator(entries.end()); + } + + const_iterator end() const { + return const_iterator(entries.end()); + } + + iterator insertEntry(iterator it) { + xmlNodePtr newNode = xmlNewNode(0, (xmlChar*)"entry"); + + if(it == end()) + xmlAddChild(elementNode, newNode); + else + xmlAddPrevSibling(it->entryNode, newNode); + + return iterator(entries.insert(it.it, new Entry(newNode))); + } + + iterator addEntry() { + return insertEntry(end()); + } + + void removeEntry(iterator it) { + xmlUnlinkNode(it->entryNode); + xmlFreeNode(it->entryNode); + delete *it.it; + + entries.erase(it.it); + } + }; + + XmlData(); + XmlData(const XmlData &o); + XmlData(const Net::Packet &packet); + + XmlData& operator=(const XmlData &o); + + virtual ~XmlData() { + delete entry; + + xmlFreeDoc(doc); + } + + std::string getType() const; + void setType(const std::string &type); + + template <typename T> + bool set(const std::string &name, T val) { + return entry->set(name, val); + } + + template <typename T> + T get(const std::string &name) const { + return entry->get<T>(name); + } + + List* createList(const std::string &name, bool unique = false) { + return entry->createList(name, unique); + } + + List* getList(const std::string &name) { + return entry->getList(name); + } + + const List* getList(const std::string &name) const { + return entry->getList(name); + } + + void unset(const std::string &name) { + entry->unset(name); + } + + Net::Packet toPacket(boost::uint16_t requestId) const; +}; + +template <> MAD_COMMON_EXPORT std::string XmlData::Entry::get<std::string>(const std::string &name) const; +template <> MAD_COMMON_EXPORT const std::string& XmlData::Entry::get<const std::string&>(const std::string &name) const; + +template <> MAD_COMMON_EXPORT std::vector<boost::uint8_t> XmlData::Entry::get<std::vector<unsigned char> >(const std::string &name) const; +template <> MAD_COMMON_EXPORT const std::vector<boost::uint8_t>& XmlData::Entry::get<const std::vector<unsigned char>&>(const std::string &name) const; + +} +} + +#endif /* MAD_COMMON_XMLDATA_H_ */ |