diff options
Diffstat (limited to 'src/Common/XmlData.cpp')
-rw-r--r-- | src/Common/XmlData.cpp | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/src/Common/XmlData.cpp b/src/Common/XmlData.cpp new file mode 100644 index 0000000..d3c948b --- /dev/null +++ b/src/Common/XmlData.cpp @@ -0,0 +1,311 @@ +/* + * XmlData.cpp + * + * 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/>. + */ + +#include "XmlData.h" +#include "Base64Encoder.h" +#include <cstdlib> +#include <cstring> + +#include <iostream> + +namespace Mad { +namespace Common { + +void XmlData::Element::updateStr() { + std::string typeStr; + + if(type == NONE) { + str = ""; + } + else if(type == BINARY) { + str = Base64Encoder::encode(boost::get<std::vector<boost::uint8_t> >(value)); + typeStr = "binary"; + } + else if(type != STRING) { + std::ostringstream buf; + + switch(type) { + case INT: + buf << boost::get<long>(value); + typeStr = "int"; + break; + case UINT: + buf << boost::get<unsigned long>(value); + typeStr = "uint"; + break; + case INT64: + buf << boost::get<long long>(value); + typeStr = "int64"; + break; + case UINT64: + buf << boost::get<unsigned long long>(value); + typeStr = "uint64"; + break; + case FLOAT: + buf << boost::get<float>(value); + typeStr = "float"; + break; + case DOUBLE: + buf << boost::get<double>(value); + typeStr = "double"; + break; + case LONGDOUBLE: + buf << boost::get<long double>(value); + typeStr = "longdouble"; + default: + break; + } + + str = buf.str(); + } + else + typeStr = "string"; + + xmlNodePtr newNode = xmlNewText((xmlChar*)str.c_str()); + xmlNodePtr oldNode = elementNode->children; + + xmlReplaceNode(oldNode, newNode); + xmlFreeNode(oldNode); + + xmlSetProp(elementNode, (xmlChar*)"type", (xmlChar*)typeStr.c_str()); +} + +XmlData::Element::Element(xmlNodePtr node) : elementNode(node), type(NONE) { + if(!node) + return; + + xmlChar *typestr = xmlGetProp(node, (xmlChar*)"type"); + if(!typestr) + return; + + xmlChar *content = xmlNodeGetContent(node->children); + if(!content) { + xmlFree(typestr); + return; + } + + str = (char*)content; + std::istringstream buf(str); + + if(!xmlStrcmp(typestr, (xmlChar*)"binary")) { + type = BINARY; + + value = Base64Encoder::decode(str); + } + else if(!xmlStrcmp(typestr, (xmlChar*)"int")) { + type = INT; + + long tmp; + buf >> tmp; + value = tmp; + } + else if(!xmlStrcmp(typestr, (xmlChar*)"uint")) { + type = UINT; + + unsigned long tmp; + buf >> tmp; + value = tmp; + } + else if(!xmlStrcmp(typestr, (xmlChar*)"int64")) { + type = INT64; + + long long tmp; + buf >> tmp; + value = tmp; + } + else if(!xmlStrcmp(typestr, (xmlChar*)"uint64")) { + type = UINT64; + + unsigned long long tmp; + buf >> tmp; + value = tmp; + } + else if(!xmlStrcmp(typestr, (xmlChar*)"float")) { + type = FLOAT; + + float tmp; + buf >> tmp; + value = tmp; + } + else if(!xmlStrcmp(typestr, (xmlChar*)"double")) { + type = DOUBLE; + + double tmp; + buf >> tmp; + value = tmp; + } + else if(!xmlStrcmp(typestr, (xmlChar*)"longdouble")) { + type = LONGDOUBLE; + + long double tmp; + buf >> tmp; + value = tmp; + } + else if(!xmlStrcmp(typestr, (xmlChar*)"string")) { + type = STRING; + } + + xmlFree(typestr); + xmlFree(content); + + if(type != NONE) + updateStr(); +} + +XmlData::Entry::Entry(xmlNodePtr node) : entryNode(node) { + if(!node) + return; + + for(xmlNodePtr element = node->children; element != 0; element = element->next) { + if(element->type != XML_ELEMENT_NODE) + continue; + + xmlChar *name = xmlGetProp(element, (xmlChar*)"name"); + + if(!xmlStrcmp(element->name, (xmlChar*)"list")) + lists.insert(std::make_pair(std::string((char*)name), new List(element))); + else if(!xmlStrcmp(element->name, (xmlChar*)"value")) + elements.insert(std::make_pair(std::string((char*)name), new Element(element))); + + xmlFree(name); + } +} + + + +template <> +std::string XmlData::Entry::get<std::string>(const std::string &name) const { + Element *element = getElement(name); + if(!element) + return std::string(); + + return element->str; +} + +template <> +const std::string& XmlData::Entry::get<const std::string&>(const std::string &name) const { + static std::string empty; + + Element *element = getElement(name); + if(!element) + return empty; + + return element->str; +} + +template <> +std::vector<boost::uint8_t> XmlData::Entry::get<std::vector<unsigned char> >(const std::string &name) const { + Element *element = getElement(name); + if(!element) + return std::vector<boost::uint8_t>(); + + switch(element->type) { + case Element::BINARY: + return boost::get<std::vector<boost::uint8_t> >(element->value); + default: + return std::vector<boost::uint8_t>(); + } +} + +template <> +const std::vector<boost::uint8_t>& XmlData::Entry::get<const std::vector<unsigned char>&>(const std::string &name) const { + static std::vector<boost::uint8_t> empty; + + Element *element = getElement(name); + if(!element) + return empty; + + switch(element->type) { + case Element::BINARY: + return boost::get<std::vector<boost::uint8_t> >(element->value); + default: + return empty; + } +} + +XmlData::List::List(xmlNodePtr node) : elementNode(node) { + for(xmlNodePtr entry = node->children; entry != 0; entry = entry->next) { + if(entry->type != XML_ELEMENT_NODE || xmlStrcmp(entry->name, (xmlChar*)"entry")) + continue; + + entries.push_back(new Entry(entry)); + } +} + +XmlData::XmlData() { + doc = xmlNewDoc((xmlChar*)"1.0"); + + rootNode = xmlNewNode(0, (xmlChar*)"mad"); + xmlDocSetRootElement(doc, rootNode); + + entry = new Entry(rootNode); +} + +XmlData::XmlData(const XmlData &o) { + doc = xmlCopyDoc(o.doc, 1); + rootNode = xmlDocGetRootElement(doc); + entry = new Entry(rootNode); +} + +XmlData::XmlData(const Net::Packet &packet) { + doc = xmlParseMemory((const char*)packet.getData(), packet.getLength()); + rootNode = xmlDocGetRootElement(doc); + entry = new Entry(rootNode); +} + +XmlData& XmlData::operator=(const XmlData &o) { + delete entry; + xmlFreeDoc(doc); + + doc = xmlCopyDoc(o.doc, 1); + rootNode = xmlDocGetRootElement(doc); + entry = new Entry(rootNode); + + return *this; +} + +std::string XmlData::getType() const { + xmlChar *type = xmlGetProp(rootNode, (xmlChar*)"type"); + + std::string ret(type ? (char*)type : ""); + + xmlFree(type); + + return ret; +} + +void XmlData::setType(const std::string &type) { + xmlSetProp(rootNode, (xmlChar*)"type", (xmlChar*)type.c_str()); +} + +Net::Packet XmlData::toPacket(boost::uint16_t requestId) const { + xmlChar *buf; + int length; + + xmlDocDumpMemory(doc, &buf, &length); + + Net::Packet packet(requestId, buf, length); + + xmlFree(buf); + + return packet; +} + +} +} |