summaryrefslogtreecommitdiffstats
path: root/src/Common/XmlData.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/Common/XmlData.h')
-rw-r--r--src/Common/XmlData.h493
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_ */