summaryrefslogtreecommitdiffstats
path: root/src/Common/XmlData.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Common/XmlData.cpp')
-rw-r--r--src/Common/XmlData.cpp311
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;
+}
+
+}
+}