/* * XmlData.h * * Copyright (C) 2009 Matthias Schiffer * * 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 . */ #ifndef MAD_COMMON_XMLDATA_H_ #define MAD_COMMON_XMLDATA_H_ #include "export.h" #include #include #include #include #include #include #include #include #include #include #include #include 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 > Variant; xmlNodePtr elementNode; Type type; Variant value; Core::String str; void updateStr(); Element(xmlNodePtr node); template void set(T val, Type type0) { type = type0; value = val; updateStr(); } void set(int val) { set(val, INT); } void set(unsigned int val) { set(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 Core::String &val) { type = STRING; value = Element::Variant(); str = val; updateStr(); } void set(const std::vector &val) { set(val, BINARY); } }; public: class MAD_COMMON_EXPORT Entry : private boost::noncopyable { private: friend class List; friend class XmlData; xmlNodePtr entryNode; std::map elements; std::map lists; Element* getElement(const Core::String &name) { std::map::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.extractUTF8().c_str()); xmlSetProp(newNode, (xmlChar*)"type", (xmlChar*)""); Element* newElement = new Element(newNode); elements.insert(std::make_pair(name, newElement)); return newElement; } Element* getElement(const Core::String &name) const { std::map::const_iterator element = elements.find(name); if(element != elements.end()) return element->second; else return 0; } Entry(xmlNodePtr node); ~Entry() { for(std::map::iterator element = elements.begin(); element != elements.end(); ++element) delete element->second; for(std::map::iterator list = lists.begin(); list != lists.end(); ++list) delete list->second; } public: template bool set(const Core::String &name, T val) { Element *element = getElement(name); if(!element) return false; element->set(val); return true; } template T get(const Core::String &name) const { Element *element = getElement(name); if(!element) return T(); switch(element->type) { case Element::INT: return static_cast(boost::get(element->value)); case Element::UINT: return static_cast(boost::get(element->value)); case Element::INT64: return static_cast(boost::get(element->value)); case Element::UINT64: return static_cast(boost::get(element->value)); case Element::FLOAT: return static_cast(boost::get(element->value)); case Element::DOUBLE: return static_cast(boost::get(element->value)); case Element::LONGDOUBLE: return static_cast(boost::get(element->value)); default: return static_cast(0); } } List* createList(const Core::String &name, bool unique = false) { std::map::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.extractUTF8().c_str()); List *newList = new List(newNode); lists.insert(std::make_pair(name, newList)); return newList; } List* getList(const Core::String &name) { std::map::iterator list = lists.find(name); if(list == lists.end()) return 0; return list->second; } const List* getList(const Core::String &name) const { std::map::const_iterator list = lists.find(name); if(list == lists.end()) return 0; return list->second; } void unset(const Core::String &name) { std::map::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::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; } std::set getChildren() const { std::set childNames; for(std::map::const_iterator it = elements.begin(); it != elements.end(); ++it) childNames.insert(it->first); return childNames; } std::set getLists() const { std::set listNames; for(std::map::const_iterator it = lists.begin(); it != lists.end(); ++it) listNames.insert(it->first); return listNames; } }; class MAD_COMMON_EXPORT List : private boost::noncopyable { private: friend class Entry; xmlNodePtr elementNode; std::vector entries; template 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::iterator entry = entries.begin(); entry != entries.end(); ++entry) delete *entry; } public: typedef iterator_base::iterator> iterator; typedef iterator_base::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(const std::string &filename) throw (Core::Exception); XmlData& operator=(const XmlData &o); virtual ~XmlData() { delete entry; xmlFreeDoc(doc); } Core::String getType() const; void setType(const Core::String &type); template bool set(const Core::String &name, T val) { return entry->set(name, val); } template T get(const Core::String &name) const { return entry->get(name); } List* createList(const Core::String &name, bool unique = false) { return entry->createList(name, unique); } List* getList(const Core::String &name) { return entry->getList(name); } const List* getList(const Core::String &name) const { return entry->getList(name); } void unset(const Core::String &name) { entry->unset(name); } Net::Packet toPacket(boost::uint16_t requestId) const; void toFile(const std::string &filename) const throw (Core::Exception); }; template <> MAD_COMMON_EXPORT Core::String XmlData::Entry::get(const Core::String &name) const; template <> MAD_COMMON_EXPORT const Core::String& XmlData::Entry::get(const Core::String &name) const; template <> MAD_COMMON_EXPORT std::vector XmlData::Entry::get >(const Core::String &name) const; template <> MAD_COMMON_EXPORT const std::vector& XmlData::Entry::get&>(const Core::String &name) const; } } #endif /* MAD_COMMON_XMLDATA_H_ */