summaryrefslogtreecommitdiffstats
path: root/src/Common
diff options
context:
space:
mode:
Diffstat (limited to 'src/Common')
-rw-r--r--src/Common/Makefile.am4
-rw-r--r--src/Common/Makefile.in9
-rw-r--r--src/Common/RequestHandlers/Makefile.in2
-rw-r--r--src/Common/RequestManager.cpp120
-rw-r--r--src/Common/RequestManager.h42
-rw-r--r--src/Common/Requests/Makefile.in2
-rw-r--r--src/Common/XmlPacket.cpp239
-rw-r--r--src/Common/XmlPacket.h437
-rw-r--r--src/Common/XmlRequest.h92
-rw-r--r--src/Common/XmlRequestBase.h39
-rw-r--r--src/Common/XmlRequestHandler.h60
11 files changed, 1037 insertions, 9 deletions
diff --git a/src/Common/Makefile.am b/src/Common/Makefile.am
index 665c21a..2fd4edb 100644
--- a/src/Common/Makefile.am
+++ b/src/Common/Makefile.am
@@ -3,10 +3,10 @@ SUBDIRS = Requests RequestHandlers
noinst_LTLIBRARIES = libcommon.la
libcommon_la_SOURCES = ActionManager.cpp ConfigEntry.cpp ConfigManager.cpp Exception.cpp Initializable.cpp \
Logger.cpp LogManager.cpp ModuleManager.cpp RequestManager.cpp \
- SystemBackend.cpp Tokenizer.cpp
+ SystemBackend.cpp Tokenizer.cpp XmlPacket.cpp
libcommon_la_LIBADD = Requests/librequests.la RequestHandlers/librequesthandlers.la
noinst_HEADERS = ActionManager.h ConfigEntry.h ConfigManager.h Configurable.h Exception.h HostInfo.h \
Initializable.h Logger.h LoggerBase.h LogManager.h ModuleManager.h \
RemoteLogger.h Request.h RequestBase.h RequestHandler.h RequestManager.h \
- SystemBackend.h Tokenizer.h UserInfo.h
+ SystemBackend.h Tokenizer.h UserInfo.h XmlPacket.h XmlRequestHandler.h
diff --git a/src/Common/Makefile.in b/src/Common/Makefile.in
index 2fb869f..3638371 100644
--- a/src/Common/Makefile.in
+++ b/src/Common/Makefile.in
@@ -54,7 +54,7 @@ libcommon_la_DEPENDENCIES = Requests/librequests.la \
am_libcommon_la_OBJECTS = ActionManager.lo ConfigEntry.lo \
ConfigManager.lo Exception.lo Initializable.lo Logger.lo \
LogManager.lo ModuleManager.lo RequestManager.lo \
- SystemBackend.lo Tokenizer.lo
+ SystemBackend.lo Tokenizer.lo XmlPacket.lo
libcommon_la_OBJECTS = $(am_libcommon_la_OBJECTS)
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/config/depcomp
@@ -204,6 +204,8 @@ infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
+libxml2_CFLAGS = @libxml2_CFLAGS@
+libxml2_LIBS = @libxml2_LIBS@
localedir = @localedir@
localstatedir = @localstatedir@
lt_ECHO = @lt_ECHO@
@@ -231,13 +233,13 @@ SUBDIRS = Requests RequestHandlers
noinst_LTLIBRARIES = libcommon.la
libcommon_la_SOURCES = ActionManager.cpp ConfigEntry.cpp ConfigManager.cpp Exception.cpp Initializable.cpp \
Logger.cpp LogManager.cpp ModuleManager.cpp RequestManager.cpp \
- SystemBackend.cpp Tokenizer.cpp
+ SystemBackend.cpp Tokenizer.cpp XmlPacket.cpp
libcommon_la_LIBADD = Requests/librequests.la RequestHandlers/librequesthandlers.la
noinst_HEADERS = ActionManager.h ConfigEntry.h ConfigManager.h Configurable.h Exception.h HostInfo.h \
Initializable.h Logger.h LoggerBase.h LogManager.h ModuleManager.h \
RemoteLogger.h Request.h RequestBase.h RequestHandler.h RequestManager.h \
- SystemBackend.h Tokenizer.h UserInfo.h
+ SystemBackend.h Tokenizer.h UserInfo.h XmlPacket.h XmlRequestHandler.h
all: all-recursive
@@ -301,6 +303,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestManager.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SystemBackend.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Tokenizer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XmlPacket.Plo@am__quote@
.cpp.o:
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
diff --git a/src/Common/RequestHandlers/Makefile.in b/src/Common/RequestHandlers/Makefile.in
index dc292e3..ccf87b4 100644
--- a/src/Common/RequestHandlers/Makefile.in
+++ b/src/Common/RequestHandlers/Makefile.in
@@ -191,6 +191,8 @@ infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
+libxml2_CFLAGS = @libxml2_CFLAGS@
+libxml2_LIBS = @libxml2_LIBS@
localedir = @localedir@
localstatedir = @localstatedir@
lt_ECHO = @lt_ECHO@
diff --git a/src/Common/RequestManager.cpp b/src/Common/RequestManager.cpp
index d852f5d..94b3da9 100644
--- a/src/Common/RequestManager.cpp
+++ b/src/Common/RequestManager.cpp
@@ -19,6 +19,8 @@
#include "RequestManager.h"
#include "Request.h"
+#include "XmlRequest.h"
+#include "XmlPacket.h"
#include "RequestHandlers/DisconnectRequestHandler.h"
#include "Logger.h"
@@ -67,6 +69,40 @@ bool RequestManager::RequestMap::deleteRequest(uint16_t id) {
}
+RequestManager::XmlRequestMap::~XmlRequestMap() {
+ for(iterator it = begin(); it != end(); ++it)
+ delete it->second;
+}
+
+bool RequestManager::XmlRequestMap::addRequest(uint16_t id, XmlRequestHandler *info) {
+ if(!insert(std::make_pair(id, info)).second)
+ return false;
+
+ info->signalFinished().connect(sigc::hide_return(sigc::bind(sigc::mem_fun(this, &RequestManager::XmlRequestMap::deleteRequest), id)));
+
+ return true;
+}
+
+XmlRequestHandler* RequestManager::XmlRequestMap::findRequest(uint16_t id) {
+ iterator it = find(id);
+ if(it == end())
+ return 0;
+
+ return it->second;
+}
+
+bool RequestManager::XmlRequestMap::deleteRequest(uint16_t id) {
+ iterator it = find(id);
+ if(it == end())
+ return false;
+
+ delete it->second;
+
+ erase(it);
+ return true;
+}
+
+
void RequestManager::receiveHandler(Net::Connection *connection, const Net::Packet &packet) {
std::map<Net::Connection*,RequestMap*>::iterator it = requestMaps.find(connection);
@@ -86,6 +122,37 @@ void RequestManager::receiveHandler(Net::Connection *connection, const Net::Pack
return;
}
+ std::map<Net::Connection*,XmlRequestMap*>::iterator it2 = xmlRequestMaps.find(connection);
+ if(it2 == xmlRequestMaps.end()) {
+ // TODO: Error
+ Logger::log(Logger::ERROR, "Received a packet from an unregistered connection.");
+
+ return;
+ }
+
+ XmlRequestMap *xmlRequestMap = it2->second;
+ XmlRequestHandler *xmlRequest = xmlRequestMap->findRequest(packet.getRequestId());
+
+ if(xmlRequest) {
+ XmlPacket xmlPacket(packet);
+ xmlRequest->handlePacket(connection, xmlPacket);
+
+ return;
+ }
+
+ if(packet.getType() == Net::Packet::XML) {
+ XmlPacket xmlPacket(packet);
+
+ std::map<std::string,XmlRequestHandlerFactory*>::iterator factoryIt = xmlRequestHandlerFactories.find(xmlPacket.getType());
+ if(factoryIt != xmlRequestHandlerFactories.end()) {
+ xmlRequest = factoryIt->second->createRequestHandler();
+ xmlRequestMap->addRequest(packet.getRequestId(), xmlRequest);
+ xmlRequest->handlePacket(connection, xmlPacket);
+
+ return;
+ }
+ }
+
std::map<Net::Packet::Type,RequestHandlerFactory*>::iterator factoryIt = requestHandlerFactories.find(packet.getType());
if(factoryIt != requestHandlerFactories.end()) {
request = factoryIt->second->createRequestHandler();
@@ -121,8 +188,31 @@ bool RequestManager::sendRequest(Net::Connection *connection, std::auto_ptr<Requ
return true;
}
+bool RequestManager::sendRequest(Net::Connection *connection, std::auto_ptr<XmlRequestBase> request) {
+ std::map<Net::Connection*,XmlRequestMap*>::iterator it = xmlRequestMaps.find(connection);
+
+ if(it == xmlRequestMaps.end()) {
+ Logger::log(Logger::CRITICAL, "Trying to send a request over an unregistered connecion.");
+ return false;
+ }
+
+ XmlRequestMap *requestMap = it->second;
+
+ uint16_t id;
+ do {
+ id = getRequestId();
+ } while(requestMap->findRequest(id));
+
+ request->sendRequest(connection, id);
+
+ requestMap->addRequest(id, request.release());
+
+ return true;
+}
+
void RequestManager::registerConnection(Net::Connection *connection) {
requestMaps.insert(std::make_pair(connection, new RequestMap()));
+ xmlRequestMaps.insert(std::make_pair(connection, new XmlRequestMap()));
connection->signalReceive().connect(sigc::mem_fun(this, &RequestManager::receiveHandler));
}
@@ -130,12 +220,17 @@ void RequestManager::registerConnection(Net::Connection *connection) {
void RequestManager::unregisterConnection(Net::Connection *connection) {
std::map<Net::Connection*,RequestMap*>::iterator it = requestMaps.find(connection);
- if(it == requestMaps.end())
- return;
+ if(it != requestMaps.end()) {
+ delete it->second;
+ requestMaps.erase(it);
+ }
- delete it->second;
+ std::map<Net::Connection*,XmlRequestMap*>::iterator it2 = xmlRequestMaps.find(connection);
- requestMaps.erase(it);
+ if(it2 != xmlRequestMaps.end()) {
+ delete it2->second;
+ xmlRequestMaps.erase(it2);
+ }
}
void RequestManager::unregisterPacketType(Net::Packet::Type type) {
@@ -149,6 +244,17 @@ void RequestManager::unregisterPacketType(Net::Packet::Type type) {
requestHandlerFactories.erase(it);
}
+void RequestManager::unregisterPacketType(const std::string &type) {
+ std::map<std::string,XmlRequestHandlerFactory*>::iterator it = xmlRequestHandlerFactories.find(type);
+
+ if(it == xmlRequestHandlerFactories.end())
+ return;
+
+ delete it->second;
+
+ xmlRequestHandlerFactories.erase(it);
+}
+
RequestManager::RequestManager() : core(false), requestId(-1) {
registerPacketType<RequestHandlers::DisconnectRequestHandler>(Net::Packet::DISCONNECT);
}
@@ -159,8 +265,14 @@ RequestManager::~RequestManager() {
for(std::map<Net::Connection*,RequestMap*>::iterator it = requestMaps.begin(); it != requestMaps.end(); ++it)
delete it->second;
+ for(std::map<Net::Connection*,XmlRequestMap*>::iterator it = xmlRequestMaps.begin(); it != xmlRequestMaps.end(); ++it)
+ delete it->second;
+
for(std::map<Net::Packet::Type,RequestHandlerFactory*>::iterator it = requestHandlerFactories.begin(); it != requestHandlerFactories.end(); ++it)
delete it->second;
+
+ for(std::map<std::string,XmlRequestHandlerFactory*>::iterator it = xmlRequestHandlerFactories.begin(); it != xmlRequestHandlerFactories.end(); ++it)
+ delete it->second;
}
}
diff --git a/src/Common/RequestManager.h b/src/Common/RequestManager.h
index c2f58d2..00d940d 100644
--- a/src/Common/RequestManager.h
+++ b/src/Common/RequestManager.h
@@ -30,6 +30,8 @@ namespace Common {
class RequestBase;
class RequestHandler;
+class XmlRequestBase;
+class XmlRequestHandler;
class RequestManager {
private:
@@ -48,6 +50,21 @@ class RequestManager {
bool deleteRequest(uint16_t id);
};
+ class XmlRequestMap : private std::map<uint16_t,XmlRequestHandler*> {
+ private:
+ // Prevent shallow copy
+ XmlRequestMap(const XmlRequestMap &o);
+ XmlRequestMap& operator=(const XmlRequestMap &o);
+
+ public:
+ XmlRequestMap() {}
+ ~XmlRequestMap();
+
+ bool addRequest(uint16_t id, XmlRequestHandler *info);
+ XmlRequestHandler* findRequest(uint16_t id);
+ bool deleteRequest(uint16_t id);
+ };
+
class RequestHandlerFactory {
protected:
RequestHandlerFactory() {}
@@ -64,13 +81,31 @@ class RequestManager {
}
};
+ class XmlRequestHandlerFactory {
+ protected:
+ XmlRequestHandlerFactory() {}
+
+ public:
+ virtual XmlRequestHandler* createRequestHandler() = 0;
+ virtual ~XmlRequestHandlerFactory() {}
+ };
+
+ template<class T> class SpecificXmlRequestHandlerFactory : public XmlRequestHandlerFactory {
+ public:
+ virtual XmlRequestHandler* createRequestHandler() {
+ return new T();
+ }
+ };
+
static RequestManager requestManager;
std::map<Net::Connection*,RequestMap*> requestMaps;
+ std::map<Net::Connection*,XmlRequestMap*> xmlRequestMaps;
bool core;
uint16_t requestId;
std::map<Net::Packet::Type,RequestHandlerFactory*> requestHandlerFactories;
+ std::map<std::string,XmlRequestHandlerFactory*> xmlRequestHandlerFactories;
uint16_t getRequestId() {
return requestId+=2;
@@ -108,7 +143,14 @@ class RequestManager {
void unregisterPacketType(Net::Packet::Type type);
+ template <class T> void registerPacketType(const std::string &type) {
+ xmlRequestHandlerFactories.insert(std::make_pair(type, new SpecificXmlRequestHandlerFactory<T>()));
+ }
+
+ void unregisterPacketType(const std::string &type);
+
bool sendRequest(Net::Connection *connection, std::auto_ptr<RequestBase> request);
+ bool sendRequest(Net::Connection *connection, std::auto_ptr<XmlRequestBase> request);
virtual ~RequestManager();
};
diff --git a/src/Common/Requests/Makefile.in b/src/Common/Requests/Makefile.in
index 2c363eb..768a8a6 100644
--- a/src/Common/Requests/Makefile.in
+++ b/src/Common/Requests/Makefile.in
@@ -191,6 +191,8 @@ infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
+libxml2_CFLAGS = @libxml2_CFLAGS@
+libxml2_LIBS = @libxml2_LIBS@
localedir = @localedir@
localstatedir = @localstatedir@
lt_ECHO = @lt_ECHO@
diff --git a/src/Common/XmlPacket.cpp b/src/Common/XmlPacket.cpp
new file mode 100644
index 0000000..8da861c
--- /dev/null
+++ b/src/Common/XmlPacket.cpp
@@ -0,0 +1,239 @@
+/*
+ * XmlProcessor.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 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "XmlPacket.h"
+#include <cstdlib>
+
+namespace Mad {
+namespace Common {
+
+XmlPacket::Entry XmlPacket::Element::nilEntry(0);
+XmlPacket::Element XmlPacket::Entry::nilElement(0);
+
+void XmlPacket::Element::updateStr() {
+ if(type == NONE || type == LIST)
+ return;
+
+ if(type != STRING) {
+ std::ostringstream buf;
+
+ switch(type) {
+ case INT:
+ buf << value.var_int;
+ break;
+ case UINT:
+ buf << value.var_uint;
+ break;
+ case INT64:
+ buf << value.var_int64;
+ break;
+ case UINT64:
+ buf << value.var_uint64;
+ break;
+ case FLOAT:
+ buf << value.var_float;
+ break;
+ case DOUBLE:
+ buf << value.var_double;
+ break;
+ case LONGDOUBLE:
+ buf << value.var_ldouble;
+ default:
+ break;
+
+ }
+
+ str = buf.str();
+ }
+
+ xmlNodePtr newNode = xmlNewText((xmlChar*)str.c_str());
+ xmlNodePtr oldNode = elementNode->children;
+
+ xmlReplaceNode(oldNode, newNode);
+ xmlFreeNode(oldNode);
+}
+
+XmlPacket::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;
+
+ if(!xmlStrcmp(typestr, (xmlChar*)"int")) {
+ type = INT;
+ value.var_int = std::strtol((char*)content, 0, 10);
+ }
+ else if(!xmlStrcmp(typestr, (xmlChar*)"uint")) {
+ type = UINT;
+ value.var_uint = std::strtoul((char*)content, 0, 10);
+ }
+ else if(!xmlStrcmp(typestr, (xmlChar*)"int64")) {
+ type = INT64;
+ value.var_int64 = std::strtoll((char*)content, 0, 10);
+ }
+ else if(!xmlStrcmp(typestr, (xmlChar*)"uint64")) {
+ type = UINT64;
+ value.var_uint64 = std::strtoull((char*)content, 0, 10);
+ }
+ else if(!xmlStrcmp(typestr, (xmlChar*)"float")) {
+ type = FLOAT;
+ value.var_float = std::strtof((char*)content, 0);
+ }
+ else if(!xmlStrcmp(typestr, (xmlChar*)"double")) {
+ type = DOUBLE;
+ value.var_double = std::strtod((char*)content, 0);
+ }
+ else if(!xmlStrcmp(typestr, (xmlChar*)"longdouble")) {
+ type = LONGDOUBLE;
+ value.var_ldouble = std::strtold((char*)content, 0);
+ }
+ else if(!xmlStrcmp(typestr, (xmlChar*)"string")) {
+ type = STRING;
+ }
+
+ xmlFree(typestr);
+ xmlFree(content);
+
+ updateStr();
+}
+
+XmlPacket::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), List(element)));
+ else if(!xmlStrcmp(element->name, (xmlChar*)"value"))
+ elements.insert(std::make_pair(std::string((char*)name), Element(element)));
+
+ xmlFree(name);
+ }
+}
+
+XmlPacket::Element& XmlPacket::Entry::operator[](const std::string &name) {
+ std::map<std::string, Element>::iterator it = elements.find(name);
+ if(it != elements.end())
+ return it->second;
+
+ std::map<std::string, List>::iterator it2 = lists.find(name);
+ if(it2 != lists.end())
+ return it2->second;
+
+ return nilElement;
+}
+
+const XmlPacket::Element& XmlPacket::Entry::operator[](const std::string &name) const {
+ std::map<std::string, Element>::const_iterator it = elements.find(name);
+ if(it != elements.end())
+ return it->second;
+
+ std::map<std::string, List>::const_iterator it2 = lists.find(name);
+ if(it2 != lists.end())
+ return it2->second;
+
+ return nilElement;
+}
+
+XmlPacket::List::List(xmlNodePtr node) : Element(node, LIST) {
+ 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(Entry(entry));
+ }
+}
+
+
+XmlPacket::XmlPacket() {
+ doc = xmlNewDoc((xmlChar*)"1.0");
+
+ packetNode = xmlNewNode(0, (xmlChar*)"packet");
+ xmlDocSetRootElement(doc, packetNode);
+
+ entry = new Entry(packetNode);
+}
+
+XmlPacket::XmlPacket(const XmlPacket &o) {
+ doc = xmlCopyDoc(o.doc, 1);
+ packetNode = xmlDocGetRootElement(doc);
+ entry = new Entry(packetNode);
+}
+
+XmlPacket::XmlPacket(const Net::Packet &packet) {
+ doc = xmlParseMemory((const char*)packet.getData(), packet.getLength());
+ packetNode = xmlDocGetRootElement(doc);
+ entry = new Entry(packetNode);
+}
+
+XmlPacket& XmlPacket::operator=(const XmlPacket &o) {
+ delete entry;
+ xmlFreeDoc(doc);
+
+ doc = xmlCopyDoc(o.doc, 1);
+ packetNode = xmlDocGetRootElement(doc);
+ entry = new Entry(packetNode);
+
+ return *this;
+}
+
+std::string XmlPacket::getType() const {
+ xmlChar *type = xmlGetProp(packetNode, (xmlChar*)"type");
+
+ std::string ret(type ? (char*)type : "");
+
+ xmlFree(type);
+
+ return ret;
+}
+
+void XmlPacket::setType(const std::string &type) {
+ xmlSetProp(packetNode, (xmlChar*)"type", (xmlChar*)type.c_str());
+}
+
+Net::Packet XmlPacket::encode(uint16_t requestId) {
+ xmlChar *buf;
+ int length;
+
+ xmlDocDumpMemory(doc, &buf, &length);
+
+ Net::Packet packet(Net::Packet::XML, requestId, buf, length);
+
+ xmlFree(buf);
+
+ return packet;
+}
+
+}
+}
diff --git a/src/Common/XmlPacket.h b/src/Common/XmlPacket.h
new file mode 100644
index 0000000..007404a
--- /dev/null
+++ b/src/Common/XmlPacket.h
@@ -0,0 +1,437 @@
+/*
+ * XmlProcessor.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 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_COMMON_XMLPACKET_H_
+#define MAD_COMMON_XMLPACKET_H_
+
+#include <Net/Packet.h>
+
+#include <map>
+#include <string>
+#include <sstream>
+#include <vector>
+
+#include <libxml/parser.h>
+
+namespace Mad {
+namespace Common {
+
+class XmlPacket {
+ public:
+ class Entry;
+ class List;
+
+ private:
+ xmlDocPtr doc;
+ xmlNodePtr packetNode;
+ Entry *entry;
+
+ public:
+
+ class Element {
+ public:
+ enum Type {
+ NONE, LIST,
+ INT, UINT, INT64, UINT64,
+ FLOAT, DOUBLE, LONGDOUBLE, STRING
+ };
+
+ protected:
+ friend class Entry;
+
+ xmlNodePtr elementNode;
+
+ private:
+ std::string str;
+
+ Type type;
+ union Variant {
+ int var_int;
+ unsigned int var_uint;
+
+ long long var_int64;
+ unsigned long long var_uint64;
+
+ float var_float;
+ double var_double;
+ long double var_ldouble;
+ } value;
+
+ static Entry nilEntry;
+
+ template<typename T>
+ void set(T val) {
+ switch(type) {
+ case INT:
+ value.var_int = static_cast<int>(val);
+ break;
+ case UINT:
+ value.var_uint = static_cast<unsigned int>(val);
+ break;
+ case INT64:
+ value.var_int64 = static_cast<long long>(val);
+ break;
+ case UINT64:
+ value.var_uint64 = static_cast<unsigned long long>(val);
+ break;
+ case FLOAT:
+ value.var_float = static_cast<float>(val);
+ break;
+ case DOUBLE:
+ value.var_double = static_cast<double>(val);
+ break;
+ case LONGDOUBLE:
+ value.var_ldouble = static_cast<long double>(val);
+ break;
+ default:
+ break;
+ }
+
+ updateStr();
+ }
+
+ void updateStr();
+
+ protected:
+ Element(xmlNodePtr node, Type type0) : elementNode(node), type(type0) {}
+
+ public:
+ Element(xmlNodePtr node);
+
+ Type getType() const {
+ return type;
+ }
+
+ virtual size_t getSize() const {
+ return 0;
+ }
+
+ virtual Entry& operator[](size_t) {
+ return nilEntry;
+ }
+
+ virtual const Entry& operator[](size_t) const {
+ return nilEntry;
+ }
+
+ virtual bool insertEntry(size_t) {return false;}
+ virtual bool addEntry() {return false;}
+ virtual bool removeEntry(size_t) {return false;}
+
+ template<typename T>
+ operator T() {
+ switch(type) {
+ case INT:
+ return static_cast<T>(value.var_int);
+ case UINT:
+ return static_cast<T>(value.var_uint);
+ case INT64:
+ return static_cast<T>(value.var_int64);
+ case UINT64:
+ return static_cast<T>(value.var_uint64);
+ case FLOAT:
+ return static_cast<T>(value.var_float);
+ case DOUBLE:
+ return static_cast<T>(value.var_double);
+ case LONGDOUBLE:
+ return static_cast<T>(value.var_ldouble);
+ default:
+ return static_cast<T>(0);
+ }
+ }
+
+ operator std::string() {
+ return str;
+ }
+
+ const Element& operator=(int val) {
+ set(val);
+ return *this;
+ }
+
+ const Element& operator=(unsigned int val) {
+ set(val);
+ return *this;
+ }
+
+ const Element& operator=(long long val) {
+ set(val);
+ return *this;
+ }
+
+ const Element& operator=(unsigned long long val) {
+ set(val);
+ return *this;
+ }
+
+ const Element& operator=(float val) {
+ set(val);
+ return *this;
+ }
+
+ const Element& operator=(double val) {
+ set(val);
+ return *this;
+ }
+
+ const Element& operator=(long double val) {
+ set(val);
+ return *this;
+ }
+
+ const Element& operator=(const std::string &val) {
+ if(type == STRING) {
+ str = val;
+ updateStr();
+ }
+
+ return *this;
+ }
+ };
+
+ class Entry {
+ private:
+ friend class List;
+
+ xmlNodePtr entryNode;
+
+ std::map<std::string, Element> elements;
+ std::map<std::string, List> lists;
+
+ static Element nilElement;
+
+ private:
+ bool add(const std::string &name, const std::string &value, const char *type) {
+ if(!entryNode)
+ return false;
+
+ if(lists.find(name) != lists.end() || elements.find(name) != elements.end())
+ return false;
+
+ xmlNodePtr newNode = xmlNewTextChild(entryNode, 0, (xmlChar*)"value", (xmlChar*)value.c_str());
+ xmlSetProp(newNode, (xmlChar*)"name", (xmlChar*)name.c_str());
+ xmlSetProp(newNode, (xmlChar*)"type", (xmlChar*)type);
+
+ if(!elements.insert(std::make_pair(name, Element(newNode))).second) {
+ xmlUnlinkNode(newNode);
+ xmlFreeNode(newNode);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ public:
+ Entry(xmlNodePtr node);
+
+ Element& operator[](const std::string &name);
+ const Element& operator[](const std::string &name) const;
+
+ bool add(const std::string &name, int val) {
+ std::ostringstream buf;
+ buf << val;
+
+ return add(name, buf.str(), "int");
+ }
+
+ bool add(const std::string &name, unsigned int val) {
+ std::ostringstream buf;
+ buf << val;
+
+ return add(name, buf.str(), "uint");
+ }
+
+ bool add(const std::string &name, long long val) {
+ std::ostringstream buf;
+ buf << val;
+
+ return add(name, buf.str(), "int64");
+ }
+
+ bool add(const std::string &name, unsigned long long val) {
+ std::ostringstream buf;
+ buf << val;
+
+ return add(name, buf.str(), "uint64");
+ }
+
+ bool add(const std::string &name, float val) {
+ std::ostringstream buf;
+ buf << val;
+
+ return add(name, buf.str(), "float");
+ }
+
+ bool add(const std::string &name, double val) {
+ std::ostringstream buf;
+ buf << val;
+
+ return add(name, buf.str(), "double");
+ }
+
+ bool add(const std::string &name, long double val) {
+ std::ostringstream buf;
+ buf << val;
+
+ return add(name, buf.str(), "longdouble");
+ }
+
+ bool add(const std::string &name, const std::string &val) {
+ return add(name, val, "string");
+ }
+
+ bool addList(const std::string &name) {
+ if(!entryNode)
+ return false;
+
+ if(elements.find(name) != elements.end() || lists.find(name) != lists.end())
+ return false;
+
+ xmlNodePtr newNode = xmlNewChild(entryNode, 0, (xmlChar*)"list", 0);
+ xmlSetProp(newNode, (xmlChar*)"name", (xmlChar*)name.c_str());
+
+ if(!lists.insert(std::make_pair(name, List(newNode))).second) {
+ xmlUnlinkNode(newNode);
+ xmlFreeNode(newNode);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ bool remove(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);
+
+ elements.erase(element);
+
+ return true;
+ }
+
+ std::map<std::string, List>::iterator list = lists.find(name);
+
+ if(list != lists.end()) {
+ xmlUnlinkNode(list->second.elementNode);
+ xmlFreeNode(list->second.elementNode);
+
+ lists.erase(list);
+
+ return true;
+ }
+
+ return false;
+ }
+ };
+
+ class List : public Element {
+ private:
+ std::vector<Entry> entries;
+
+ public:
+ List(xmlNodePtr node);
+
+ virtual size_t getSize() const {
+ return entries.size();
+ }
+
+ virtual Entry& operator[](size_t i) {
+ return entries[i];
+ }
+
+ virtual const Entry& operator[](size_t i) const {
+ return entries[i];
+ }
+
+ virtual bool insertEntry(size_t i) {
+ if(i > getSize())
+ return false;
+
+ xmlNodePtr newNode = xmlNewNode(0, (xmlChar*)"entry");
+ xmlAddChild(elementNode, newNode);
+
+ entries.insert(entries.begin()+i, Entry(newNode));
+
+ return true;
+ }
+
+ virtual bool addEntry() {
+ return insertEntry(getSize());
+ }
+
+ virtual bool removeEntry(size_t i) {
+ if(i >= getSize())
+ return false;
+
+ xmlUnlinkNode(entries[i].entryNode);
+ xmlFreeNode(entries[i].entryNode);
+
+ entries.erase(entries.begin()+i);
+
+ return true;
+ }
+ };
+
+ XmlPacket();
+ XmlPacket(const XmlPacket &o);
+ XmlPacket(const Net::Packet &packet);
+
+ XmlPacket& operator=(const XmlPacket &o);
+
+ virtual ~XmlPacket() {
+ delete entry;
+
+ xmlFreeDoc(doc);
+ }
+
+ std::string getType() const;
+ void setType(const std::string &type);
+
+ Element& operator[](const std::string &name) {
+ return entry->operator[](name);
+ }
+
+ const Element& operator[](const std::string &name) const {
+ return entry->operator[](name);
+ }
+
+ template <typename T>
+ bool add(const std::string &name, T val) {
+ return entry->add(name, val);
+ }
+
+ bool addList(const std::string &name) {
+ return entry->addList(name);
+ }
+
+ bool remove(const std::string &name) {
+ return entry->remove(name);
+ }
+
+ Net::Packet encode(uint16_t requestId);
+};
+
+}
+}
+
+#endif /* MAD_COMMON_XMLPACKET_H_ */
diff --git a/src/Common/XmlRequest.h b/src/Common/XmlRequest.h
new file mode 100644
index 0000000..0de0291
--- /dev/null
+++ b/src/Common/XmlRequest.h
@@ -0,0 +1,92 @@
+/*
+ * Request.h
+ *
+ * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_COMMON_XMLREQUEST_H_
+#define MAD_COMMON_XMLREQUEST_H_
+
+#include "XmlRequestBase.h"
+#include "Exception.h"
+
+#include <memory>
+#include <sigc++/adaptors/hide.h>
+
+namespace Mad {
+namespace Common {
+
+template<typename T = void> class XmlRequest : public XmlRequestBase {
+ private:
+ sigc::signal<void,const XmlRequest<T>&> finished;
+
+ std::auto_ptr<T> res;
+ Exception exp;
+
+ public:
+ typedef sigc::slot<void,const XmlRequest<T>&> slot_type;
+
+ protected:
+ XmlRequest(slot_type slot) : exp(Exception::NOT_FINISHED) {
+ finished.connect(slot);
+ finished.connect(sigc::hide(signalFinished().make_slot()));
+ }
+
+ void finish(std::auto_ptr<T> result) {res = result; finished(*this);}
+ void finish(const T& result) {res.reset(new T(result)); finished(*this);}
+ void finishWithError(const Exception &e) {exp = e; finished(*this);}
+
+ public:
+ const T& getResult() const throw(Exception) {
+ if(res.get())
+ return *res;
+
+ throw exp;
+ }
+};
+
+template<> class XmlRequest<void> : public XmlRequestBase {
+ private:
+ sigc::signal<void,const XmlRequest<void>&> finished;
+
+ bool isFinished;
+ Exception exp;
+
+ public:
+ typedef sigc::slot<void,const XmlRequest<void>&> slot_type;
+
+ protected:
+ XmlRequest(slot_type slot) : isFinished(false), exp(Exception::NOT_FINISHED) {
+ finished.connect(slot);
+ finished.connect(sigc::hide(signalFinished().make_slot()));
+ }
+
+ void finish() {isFinished = true; finished(*this);}
+ void finishWithError(const Exception &e) {exp = e; finished(*this);}
+
+ public:
+ void getResult() const throw(Exception) {
+ if(isFinished)
+ return;
+
+ throw exp;
+ }
+};
+
+}
+}
+
+#endif /* MAD_COMMON_XMLREQUEST_H_ */
diff --git a/src/Common/XmlRequestBase.h b/src/Common/XmlRequestBase.h
new file mode 100644
index 0000000..fbecc71
--- /dev/null
+++ b/src/Common/XmlRequestBase.h
@@ -0,0 +1,39 @@
+/*
+ * RequestBase.h
+ *
+ * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_COMMON_XMLREQUESTBASE_H_
+#define MAD_COMMON_XMLREQUESTBASE_H_
+
+#include "XmlRequestHandler.h"
+#include <stdint.h>
+
+namespace Mad {
+namespace Common {
+
+class XmlRequestBase : public XmlRequestHandler {
+ protected:
+ virtual void sendRequest(Net::Connection *connection, uint16_t requestId) = 0;
+
+ friend class RequestManager;
+};
+
+}
+}
+
+#endif /* MAD_COMMON_XMLREQUESTBASE_H_ */
diff --git a/src/Common/XmlRequestHandler.h b/src/Common/XmlRequestHandler.h
new file mode 100644
index 0000000..e04e5b9
--- /dev/null
+++ b/src/Common/XmlRequestHandler.h
@@ -0,0 +1,60 @@
+/*
+ * RequestHandler.h
+ *
+ * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_COMMON_XMLREQUESTHANDLER_H_
+#define MAD_COMMON_XMLREQUESTHANDLER_H_
+
+#include <sigc++/signal.h>
+
+namespace Mad {
+
+namespace Net {
+class Connection;
+}
+
+namespace Common {
+
+class RequestManager;
+class XmlPacket;
+
+class XmlRequestHandler {
+ private:
+ sigc::signal<void> finished;
+
+ // Prevent shallow copy
+ XmlRequestHandler(const XmlRequestHandler &o);
+ XmlRequestHandler& operator=(const XmlRequestHandler &o);
+
+ protected:
+ XmlRequestHandler() {}
+
+ sigc::signal<void> signalFinished() {return finished;}
+
+ virtual void handlePacket(Net::Connection *connection, const XmlPacket &packet) = 0;
+
+ public:
+ virtual ~XmlRequestHandler() {}
+
+ friend class RequestManager;
+};
+
+}
+}
+
+#endif /* MAD_COMMON_XMLREQUESTHANDLER_H_ */