summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChuck Miller <shadowmil@gmail.com>2010-08-15 15:57:21 -0400
committerChuck Miller <shadowmil@gmail.com>2010-08-15 15:57:21 -0400
commit8f573b6c425dc82be42ad80eae565b0641a90a3b (patch)
tree149c7889d384e10fd9dc95f1aa90478e69b314c8 /src
parentfee9fbce12e620f25aecdc0690285cc47fa8791d (diff)
parent2b676bbf6fcf7dfd45cb33f06dacd2ca5bce19fe (diff)
downloadmana-8f573b6c425dc82be42ad80eae565b0641a90a3b.tar.gz
mana-8f573b6c425dc82be42ad80eae565b0641a90a3b.tar.bz2
mana-8f573b6c425dc82be42ad80eae565b0641a90a3b.tar.xz
mana-8f573b6c425dc82be42ad80eae565b0641a90a3b.zip
Merge branch '1.0'
Conflicts: mana.cbp mana.files src/CMakeLists.txt src/Makefile.am src/utils/xml.cpp
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt14
-rw-r--r--src/Makefile.am2
-rw-r--r--src/main.cpp23
-rw-r--r--src/net/manaserv/gamehandler.cpp10
-rw-r--r--src/net/manaserv/network.cpp4
-rw-r--r--src/net/manaserv/playerhandler.cpp17
-rw-r--r--src/net/manaserv/stats.cpp12
-rw-r--r--src/net/tmwa/gamehandler.cpp3
-rw-r--r--src/resources/mapreader.cpp142
-rw-r--r--src/resources/resourcemanager.cpp45
-rw-r--r--src/resources/resourcemanager.h9
-rw-r--r--src/utils/xml.cpp77
-rw-r--r--src/utils/xml.h14
-rw-r--r--src/utils/zlib.cpp184
-rw-r--r--src/utils/zlib.h48
15 files changed, 381 insertions, 223 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 4a442bd6..6963663d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -4,7 +4,6 @@ FIND_PACKAGE(SDL_mixer REQUIRED)
FIND_PACKAGE(SDL_net REQUIRED)
FIND_PACKAGE(SDL_ttf REQUIRED)
FIND_PACKAGE(SDL_gfx REQUIRED)
-FIND_PACKAGE(ENet REQUIRED)
FIND_PACKAGE(CURL REQUIRED)
FIND_PACKAGE(LibXml2 REQUIRED)
FIND_PACKAGE(PhysFS REQUIRED)
@@ -22,6 +21,13 @@ IF (CMAKE_COMPILER_IS_GNUCXX)
ENDIF()
ENDIF()
+IF (POLICY CMP0015)
+ CMAKE_POLICY(SET CMP0015 OLD)
+ENDIF()
+INCLUDE_DIRECTORIES("../libs/enet/include")
+LINK_DIRECTORIES("../libs/enet")
+SET(INTERNAL_LIBRARIES enet)
+
SET(FLAGS "-DPACKAGE_VERSION=\\\"${VERSION}\\\"")
SET(FLAGS "${FLAGS} -DPKG_DATADIR=\\\"${PKG_DATADIR}/\\\"")
SET(FLAGS "${FLAGS} -DLOCALEDIR=\\\"${LOCALEDIR}/\\\"")
@@ -71,7 +77,6 @@ INCLUDE_DIRECTORIES(
${SDLNET_INCLUDE_DIR}
${SDLTTF_INCLUDE_DIR}
${SDLGFX_INCLUDE_DIR}
- ${ENET_INCLUDE_DIR}
${PNG_INCLUDE_DIR}
${PHYSFS_INCLUDE_DIR}
${CURL_INCLUDE_DIR}
@@ -404,6 +409,8 @@ SET(SRCS
utils/mkdir.h
utils/xml.cpp
utils/xml.h
+ utils/zlib.cpp
+ utils/zlib.h
actor.cpp
actor.h
actorsprite.cpp
@@ -636,13 +643,13 @@ SET (PROGRAMS mana)
ADD_EXECUTABLE(mana WIN32 ${SRCS} ${SRCS_MANA} ${SRCS_TMWA})
TARGET_LINK_LIBRARIES(mana
+ ${INTERNAL_LIBRARIES}
${SDLGFX_LIBRARIES}
${SDL_LIBRARY}
${SDLIMAGE_LIBRARY}
${SDLMIXER_LIBRARY}
${SDLNET_LIBRARY}
${SDLTTF_LIBRARY}
- ${ENET_LIBRARIES}
${PNG_LIBRARIES}
${PHYSFS_LIBRARY}
${CURL_LIBRARIES}
@@ -651,6 +658,7 @@ TARGET_LINK_LIBRARIES(mana
${OPENGL_LIBRARIES}
${LIBINTL_LIBRARIES}
${EXTRA_LIBRARIES})
+
INSTALL(TARGETS mana RUNTIME DESTINATION ${PKG_BINDIR})
IF (CMAKE_SYSTEM_NAME STREQUAL SunOS)
diff --git a/src/Makefile.am b/src/Makefile.am
index fb3c7327..fa72eb08 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -303,6 +303,8 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \
utils/mutex.h \
utils/xml.cpp \
utils/xml.h \
+ utils/zlib.cpp \
+ utils/zlib.h \
actor.cpp \
actor.h \
actorsprite.cpp \
diff --git a/src/main.cpp b/src/main.cpp
index 0dd00f56..f3962c40 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -21,11 +21,10 @@
#include "main.h"
-#include "utils/gettext.h"
-
#include "client.h"
-#include <libxml/parser.h>
+#include "utils/gettext.h"
+#include "utils/xml.h"
#include <getopt.h>
#include <iostream>
@@ -186,22 +185,6 @@ static void initInternationalization()
#endif
}
-static void xmlNullLogger(void *ctx, const char *msg, ...)
-{
- // Does nothing, that's the whole point of it
-}
-
-// Initialize libxml2 and check for potential ABI mismatches between
-// compiled version and the shared library actually used.
-static void initXML()
-{
- xmlInitParser();
- LIBXML_TEST_VERSION;
-
- // Suppress libxml2 error messages
- xmlSetGenericErrorFunc(NULL, xmlNullLogger);
-}
-
int main(int argc, char *argv[])
{
@@ -235,7 +218,7 @@ int main(int argc, char *argv[])
}
atexit((void(*)()) PHYSFS_deinit);
- initXML();
+ XML::init();
Client client(options);
return client.exec();
diff --git a/src/net/manaserv/gamehandler.cpp b/src/net/manaserv/gamehandler.cpp
index 65010ad3..3cb9f0ea 100644
--- a/src/net/manaserv/gamehandler.cpp
+++ b/src/net/manaserv/gamehandler.cpp
@@ -94,7 +94,10 @@ void GameHandler::handleMessage(Net::MessageIn &msg)
void GameHandler::connect()
{
gameServerConnection->connect(gameServer.hostname, gameServer.port);
- chatServerConnection->connect(chatServer.hostname, chatServer.port);
+
+ // Will already be connected if we just changed gameservers
+ if (!chatServerConnection->isConnected())
+ chatServerConnection->connect(chatServer.hostname, chatServer.port);
}
bool GameHandler::isConnected()
@@ -106,7 +109,10 @@ bool GameHandler::isConnected()
void GameHandler::disconnect()
{
gameServerConnection->disconnect();
- chatHandler->disconnect();
+
+ // No need if we're just changing gameservers
+ if (Client::getState() != STATE_CHANGE_MAP)
+ chatHandler->disconnect();
}
void GameHandler::who()
diff --git a/src/net/manaserv/network.cpp b/src/net/manaserv/network.cpp
index 607100b7..a5bf6186 100644
--- a/src/net/manaserv/network.cpp
+++ b/src/net/manaserv/network.cpp
@@ -73,7 +73,7 @@ void finalize()
if (connections)
{
logger->error("Tried to shutdown the network subsystem while there "
- "are network connections left!");
+ "are network connections left!");
}
clearNetworkHandlers();
@@ -85,7 +85,7 @@ Connection *getConnection()
if (!client)
{
logger->error("Tried to instantiate a network object before "
- "initializing the network subsystem!");
+ "initializing the network subsystem!");
}
return new Connection(client);
diff --git a/src/net/manaserv/playerhandler.cpp b/src/net/manaserv/playerhandler.cpp
index 4957bbbc..db2dcf7a 100644
--- a/src/net/manaserv/playerhandler.cpp
+++ b/src/net/manaserv/playerhandler.cpp
@@ -56,6 +56,10 @@ extern Net::PlayerHandler *playerHandler;
namespace ManaServ {
+extern Connection *gameServerConnection;
+extern std::string netToken;
+extern ServerInfo gameServer;
+
void RespawnRequestListener::action(const gcn::ActionEvent &event)
{
Net::getPlayerHandler()->respawn();
@@ -63,8 +67,6 @@ void RespawnRequestListener::action(const gcn::ActionEvent &event)
Mana::Event::trigger("NPC", "CloseAll");
}
-extern Connection *gameServerConnection;
-
PlayerHandler::PlayerHandler()
{
static const Uint16 _messages[] = {
@@ -92,11 +94,18 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
break;
case GPMSG_PLAYER_SERVER_CHANGE:
- { // TODO: Implement reconnecting to another game server
- std::string token = msg.readString(32);
+ { // TODO: Fix the servers to test this
+ netToken = msg.readString(32);
std::string address = msg.readString();
int port = msg.readInt16();
logger->log("Changing server to %s:%d", address.c_str(), port);
+
+ gameServer.hostname = address;
+ gameServer.port = port;
+
+ gameServerConnection->disconnect();
+ Client::setState(STATE_CHANGE_MAP);
+ player_node->setMap(0);
} break;
case GPMSG_PLAYER_ATTRIBUTE_CHANGE:
diff --git a/src/net/manaserv/stats.cpp b/src/net/manaserv/stats.cpp
index f109a232..ece0e72a 100644
--- a/src/net/manaserv/stats.cpp
+++ b/src/net/manaserv/stats.cpp
@@ -32,6 +32,8 @@
#include <list>
#include <map>
+#define DEFAULT_ATTRIBUTESDB_FILE "attributes.xml"
+
namespace ManaServ {
namespace Stats {
typedef struct {
@@ -123,12 +125,13 @@ namespace Stats {
void load()
{
- XML::Document doc("stats.xml");
+ XML::Document doc(DEFAULT_ATTRIBUTESDB_FILE);
xmlNodePtr rootNode = doc.rootNode();
if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "stats"))
{
- logger->log("Stats: Error while loading stats.xml!");
+ logger->log("Stats: Error while loading "
+ DEFAULT_ATTRIBUTESDB_FILE ". Using Built-ins.");
loadBuiltins();
return;
}
@@ -142,7 +145,8 @@ namespace Stats {
if (id == 0)
{
- logger->log("Stats: Invalid or missing stat ID in stats.xml!");
+ logger->log("Stats: Invalid or missing stat ID in "
+ DEFAULT_ATTRIBUTESDB_FILE "!");
continue;
}
else if (stats.find(id) != stats.end())
@@ -155,7 +159,7 @@ namespace Stats {
if (name.empty())
{
logger->log("Stats: Invalid or missing stat name in "
- "stats.xml!");
+ DEFAULT_ATTRIBUTESDB_FILE "!");
continue;
}
diff --git a/src/net/tmwa/gamehandler.cpp b/src/net/tmwa/gamehandler.cpp
index 2a9508d3..334a2e37 100644
--- a/src/net/tmwa/gamehandler.cpp
+++ b/src/net/tmwa/gamehandler.cpp
@@ -98,7 +98,8 @@ void GameHandler::handleMessage(Net::MessageIn &msg)
case SMSG_MAP_QUIT_RESPONSE:
if (msg.readInt8())
{
- new OkDialog(_("Game"), _("Request to quit denied!"), NULL);
+ new OkDialog(_("Game"), _("Request to quit denied!"), false,
+ NULL);
}
break;
}
diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp
index bb7ffee0..b30bec0a 100644
--- a/src/resources/mapreader.cpp
+++ b/src/resources/mapreader.cpp
@@ -33,10 +33,9 @@
#include "utils/base64.h"
#include "utils/stringutils.h"
#include "utils/xml.h"
+#include "utils/zlib.h"
-#include <cassert>
#include <iostream>
-#include <zlib.h>
// DO NOT CHANGE THESE STRINGS TO BE PASSED BY REFERENCE, AS THIS METHOD ALTERS
// (THAT IS, DESTROYS) THEM.
@@ -66,149 +65,12 @@ static std::string resolveRelativePath(std::string base, std::string relative)
return base + relative;
}
-/**
- * Inflates either zlib or gzip deflated memory. The inflated memory is
- * expected to be freed by the caller.
- */
-int inflateMemory(unsigned char *in, unsigned int inLength,
- unsigned char *&out, unsigned int &outLength)
-{
- int bufferSize = 256 * 1024;
- int ret;
- z_stream strm;
-
- out = (unsigned char*) malloc(bufferSize);
-
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- strm.next_in = in;
- strm.avail_in = inLength;
- strm.next_out = out;
- strm.avail_out = bufferSize;
-
- ret = inflateInit2(&strm, 15 + 32);
-
- if (ret != Z_OK)
- return ret;
-
- do
- {
- if (strm.next_out == NULL)
- {
- inflateEnd(&strm);
- return Z_MEM_ERROR;
- }
-
- ret = inflate(&strm, Z_NO_FLUSH);
- assert(ret != Z_STREAM_ERROR);
-
- switch (ret)
- {
- case Z_NEED_DICT:
- ret = Z_DATA_ERROR;
- case Z_DATA_ERROR:
- case Z_MEM_ERROR:
- (void) inflateEnd(&strm);
- return ret;
- }
-
- if (ret != Z_STREAM_END)
- {
- out = (unsigned char*) realloc(out, bufferSize * 2);
-
- if (out == NULL)
- {
- inflateEnd(&strm);
- return Z_MEM_ERROR;
- }
-
- strm.next_out = out + bufferSize;
- strm.avail_out = bufferSize;
- bufferSize *= 2;
- }
- }
- while (ret != Z_STREAM_END);
- assert(strm.avail_in == 0);
-
- outLength = bufferSize - strm.avail_out;
- (void) inflateEnd(&strm);
- return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
-}
-
-int inflateMemory(unsigned char *in, unsigned int inLength,
- unsigned char *&out)
-{
- unsigned int outLength = 0;
- int ret = inflateMemory(in, inLength, out, outLength);
-
- if (ret != Z_OK || out == NULL)
- {
- if (ret == Z_MEM_ERROR)
- {
- logger->log("Error: Out of memory while decompressing map data!");
- }
- else if (ret == Z_VERSION_ERROR)
- {
- logger->log("Error: Incompatible zlib version!");
- }
- else if (ret == Z_DATA_ERROR)
- {
- logger->log("Error: Incorrect zlib compressed data!");
- }
- else
- {
- logger->log("Error: Unknown error while decompressing map data!");
- }
-
- free(out);
- out = NULL;
- outLength = 0;
- }
-
- return outLength;
-}
-
Map *MapReader::readMap(const std::string &filename)
{
logger->log("Attempting to read map %s", filename.c_str());
- // Load the file through resource manager
- ResourceManager *resman = ResourceManager::getInstance();
- int fileSize;
- void *buffer = resman->loadFile(filename, fileSize);
Map *map = NULL;
- if (buffer == NULL)
- {
- logger->log("Map file not found (%s)", filename.c_str());
- return NULL;
- }
-
- unsigned char *inflated;
- unsigned int inflatedSize;
-
- if (filename.find(".gz", filename.length() - 3) != std::string::npos)
- {
- // Inflate the gzipped map data
- inflatedSize =
- inflateMemory((unsigned char*) buffer, fileSize, inflated);
- free(buffer);
-
- if (inflated == NULL)
- {
- logger->log("Could not decompress map file (%s)",
- filename.c_str());
- return NULL;
- }
- }
- else
- {
- inflated = (unsigned char*) buffer;
- inflatedSize = fileSize;
- }
-
- XML::Document doc((char*) inflated, inflatedSize);
- free(inflated);
+ XML::Document doc(filename);
xmlNodePtr node = doc.rootNode();
diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp
index f785f20a..c63b626e 100644
--- a/src/resources/resourcemanager.cpp
+++ b/src/resources/resourcemanager.cpp
@@ -31,6 +31,8 @@
#include "resources/soundeffect.h"
#include "resources/spritedef.h"
+#include "utils/zlib.h"
+
#include <physfs.h>
#include <SDL_image.h>
@@ -411,34 +413,59 @@ void ResourceManager::deleteInstance()
instance = NULL;
}
-void *ResourceManager::loadFile(const std::string &fileName, int &fileSize)
+void *ResourceManager::loadFile(const std::string &filename, int &filesize,
+ bool inflate)
{
// Attempt to open the specified file using PhysicsFS
- PHYSFS_file *file = PHYSFS_openRead(fileName.c_str());
+ PHYSFS_file *file = PHYSFS_openRead(filename.c_str());
// If the handler is an invalid pointer indicate failure
if (file == NULL)
{
logger->log("Warning: Failed to load %s: %s",
- fileName.c_str(), PHYSFS_getLastError());
+ filename.c_str(), PHYSFS_getLastError());
return NULL;
}
// Log the real dir of the file
- logger->log("Loaded %s/%s", PHYSFS_getRealDir(fileName.c_str()),
- fileName.c_str());
+ logger->log("Loaded %s/%s", PHYSFS_getRealDir(filename.c_str()),
+ filename.c_str());
// Get the size of the file
- fileSize = PHYSFS_fileLength(file);
+ filesize = PHYSFS_fileLength(file);
// Allocate memory and load the file
- void *buffer = malloc(fileSize);
- PHYSFS_read(file, buffer, 1, fileSize);
+ void *buffer = malloc(filesize);
+ PHYSFS_read(file, buffer, 1, filesize);
// Close the file and let the user deallocate the memory
PHYSFS_close(file);
- return buffer;
+ unsigned char *inflated;
+ unsigned int inflatedSize;
+
+ if (inflate && filename.find(".gz", filename.length() - 3)
+ != std::string::npos)
+ {
+ // Inflate the gzipped map data
+ inflatedSize =
+ inflateMemory((unsigned char*) buffer, filesize, inflated);
+ free(buffer);
+
+ if (inflated == NULL)
+ {
+ logger->log("Could not decompress file: %s",
+ filename.c_str());
+ return NULL;
+ }
+
+ filesize = inflatedSize;
+ return inflated;
+ }
+ else
+ {
+ return buffer;
+ }
}
bool ResourceManager::copyFile(const std::string &src, const std::string &dst)
diff --git a/src/resources/resourcemanager.h b/src/resources/resourcemanager.h
index e1aed521..28ab4725 100644
--- a/src/resources/resourcemanager.h
+++ b/src/resources/resourcemanager.h
@@ -183,13 +183,16 @@ class ResourceManager
* Allocates data into a buffer pointer for raw data loading. The
* returned data is expected to be freed using <code>free()</code>.
*
- * @param fileName The name of the file to be loaded.
- * @param fileSize The size of the file that was loaded.
+ * @param filename The name of the file to be loaded.
+ * @param filesize The size of the file that was loaded.
+ * @param inflate True to uncompress the file if the filename ends in
+ * ".gz", false to ignore that.
*
* @return An allocated byte array containing the data that was loaded,
* or <code>NULL</code> on fail.
*/
- void *loadFile(const std::string &fileName, int &fileSize);
+ void *loadFile(const std::string &filename, int &filesize,
+ bool inflate = true);
/**
* Retrieves the contents of a text file.
diff --git a/src/utils/xml.cpp b/src/utils/xml.cpp
index 94e0e38d..bb386f51 100644
--- a/src/utils/xml.cpp
+++ b/src/utils/xml.cpp
@@ -21,19 +21,37 @@
#include "utils/xml.h"
+#include <iostream>
+#include <fstream>
+#include <cstring>
+
+#include <libxml/parser.h>
+#include <libxml/xmlerror.h>
+
#include "log.h"
#include "resources/resourcemanager.h"
-#include <iostream>
-#include <fstream>
-#include <cstring>
+#include "utils/zlib.h"
namespace XML
{
+ static void xmlLogger(void *ctx, xmlErrorPtr error);
+
+ struct XMLContext
+ {
+ std::string file;
+ bool resman;
+ };
+
Document::Document(const std::string &filename, bool useResman):
mDoc(0)
{
+ XMLContext *ctx = new XMLContext();
+ ctx->file = filename;
+ ctx->resman = useResman;
+ xmlSetStructuredErrorFunc(ctx, xmlLogger);
+
int size;
char *data = NULL;
if (useResman)
@@ -43,25 +61,7 @@ namespace XML
}
else
{
- std::ifstream file;
- file.open(filename.c_str(), std::ios::in);
-
- if (file.is_open())
- {
- // Get length of file
- file.seekg (0, std::ios::end);
- size = file.tellg();
- file.seekg(0, std::ios::beg);
-
- data = (char*) malloc(size);
-
- file.read(data, size);
- file.close();
- }
- else
- {
- logger->log("Error loading XML file %s", filename.c_str());
- }
+ data = (char *) loadCompressedFile(filename, size);
}
if (data)
@@ -76,11 +76,8 @@ namespace XML
{
logger->log("Error loading %s", filename.c_str());
}
- }
- Document::Document(const char *data, int size)
- {
- mDoc = xmlParseMemory(data, size);
+ xmlSetStructuredErrorFunc(NULL, xmlLogger);
}
Document::~Document()
@@ -154,4 +151,32 @@ namespace XML
return NULL;
}
+ static void xmlLogger(void *ctx, xmlErrorPtr error)
+ {
+ XMLContext *context = static_cast<XMLContext*>(ctx);
+
+ if (context)
+ logger->log("Error in XML file '%s' on line %d",
+ context->file.c_str(), error->line);
+ else
+ logger->log("Error in unknown xml file on line %d",
+ error->line);
+
+ logger->log(error->message);
+
+ // No need to keep errors around
+ xmlCtxtResetLastError(error->ctxt);
+ }
+
+ void init()
+ {
+ // Initialize libxml2 and check for potential ABI mismatches between
+ // compiled version and the shared library actually used.
+ xmlInitParser();
+ LIBXML_TEST_VERSION;
+
+ // Handle libxml2 error messages
+ xmlSetStructuredErrorFunc(NULL, xmlLogger);
+ }
+
} // namespace XML
diff --git a/src/utils/xml.h b/src/utils/xml.h
index 253c4e09..48e66787 100644
--- a/src/utils/xml.h
+++ b/src/utils/xml.h
@@ -45,15 +45,6 @@ namespace XML
Document(const std::string &filename, bool useResman = true);
/**
- * Constructor that attempts to load an XML document from memory.
- * Does not log errors.
- *
- * @param data the string to parse as XML
- * @param size the length of the string in bytes
- */
- Document(const char *data, int size);
-
- /**
* Destructor. Frees the loaded XML file.
*/
~Document();
@@ -93,6 +84,11 @@ namespace XML
* Finds the first child node with the given name
*/
xmlNodePtr findFirstChildByName(xmlNodePtr parent, const char *name);
+
+ /**
+ * Initializes the XML engine.
+ */
+ void init();
}
#define for_each_xml_child_node(var, parent) \
diff --git a/src/utils/zlib.cpp b/src/utils/zlib.cpp
new file mode 100644
index 00000000..8e2a1795
--- /dev/null
+++ b/src/utils/zlib.cpp
@@ -0,0 +1,184 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2004-2009 The Mana World Development Team
+ * Copyright (C) 2009-2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * 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 2 of the License, or
+ * 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 "utils/zlib.h"
+
+#include "log.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <fstream>
+#include <iostream>
+#include <zlib.h>
+
+/**
+ * Inflates either zlib or gzip deflated memory. The inflated memory is
+ * expected to be freed by the caller.
+ */
+int inflateMemory(unsigned char *in, unsigned int inLength,
+ unsigned char *&out, unsigned int &outLength)
+{
+ int bufferSize = 256 * 1024;
+ int ret;
+ z_stream strm;
+
+ out = (unsigned char*) malloc(bufferSize);
+
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.next_in = in;
+ strm.avail_in = inLength;
+ strm.next_out = out;
+ strm.avail_out = bufferSize;
+
+ ret = inflateInit2(&strm, 15 + 32);
+
+ if (ret != Z_OK)
+ return ret;
+
+ do
+ {
+ if (strm.next_out == NULL)
+ {
+ inflateEnd(&strm);
+ return Z_MEM_ERROR;
+ }
+
+ ret = inflate(&strm, Z_NO_FLUSH);
+ assert(ret != Z_STREAM_ERROR);
+
+ switch (ret)
+ {
+ case Z_NEED_DICT:
+ ret = Z_DATA_ERROR;
+ case Z_DATA_ERROR:
+ case Z_MEM_ERROR:
+ (void) inflateEnd(&strm);
+ return ret;
+ }
+
+ if (ret != Z_STREAM_END)
+ {
+ out = (unsigned char*) realloc(out, bufferSize * 2);
+
+ if (out == NULL)
+ {
+ inflateEnd(&strm);
+ return Z_MEM_ERROR;
+ }
+
+ strm.next_out = out + bufferSize;
+ strm.avail_out = bufferSize;
+ bufferSize *= 2;
+ }
+ }
+ while (ret != Z_STREAM_END);
+ assert(strm.avail_in == 0);
+
+ outLength = bufferSize - strm.avail_out;
+ (void) inflateEnd(&strm);
+ return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
+}
+
+int inflateMemory(unsigned char *in, unsigned int inLength,
+ unsigned char *&out)
+{
+ unsigned int outLength = 0;
+ int ret = inflateMemory(in, inLength, out, outLength);
+
+ if (ret != Z_OK || out == NULL)
+ {
+ if (ret == Z_MEM_ERROR)
+ {
+ logger->log("Error: Out of memory while decompressing data!");
+ }
+ else if (ret == Z_VERSION_ERROR)
+ {
+ logger->log("Error: Incompatible zlib version!");
+ }
+ else if (ret == Z_DATA_ERROR)
+ {
+ logger->log("Error: Incorrect zlib compressed data!");
+ }
+ else
+ {
+ logger->log("Error: Unknown error while decompressing data!");
+ }
+
+ free(out);
+ out = NULL;
+ outLength = 0;
+ }
+
+ return outLength;
+}
+
+void *loadCompressedFile(const std::string &filename, int &filesize)
+{
+ std::ifstream file;
+ file.open(filename.c_str(), std::ios::in);
+
+ if (file.is_open())
+ {
+ // Get length of file
+ file.seekg (0, std::ios::end);
+ filesize = file.tellg();
+ file.seekg(0, std::ios::beg);
+
+ char *buffer = (char *) malloc(filesize);
+
+ file.read(buffer, filesize);
+ file.close();
+
+ unsigned char *inflated;
+ unsigned int inflatedSize;
+
+ if (inflated && filename.find(".gz", filename.length() - 3)
+ != std::string::npos)
+ {
+ // Inflate the gzipped map data
+ inflatedSize =
+ inflateMemory((unsigned char*) buffer, filesize, inflated);
+ free(buffer);
+
+ if (inflated == NULL)
+ {
+ logger->log("Could not decompress file: %s",
+ filename.c_str());
+ return NULL;
+ }
+
+ filesize = inflatedSize;
+ return inflated;
+ }
+ else
+ {
+ return buffer;
+ }
+ }
+ else
+ {
+ logger->log("Error loading file from drive: %s", filename.c_str());
+ }
+
+ return NULL;
+}
diff --git a/src/utils/zlib.h b/src/utils/zlib.h
new file mode 100644
index 00000000..003e64b6
--- /dev/null
+++ b/src/utils/zlib.h
@@ -0,0 +1,48 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2007-2009 The Mana World Development Team
+ * Copyright (C) 2009-2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * 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 2 of the License, or
+ * 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 UTILS_ZLIB_H
+#define UTILS_ZLIB_H
+
+#include <string>
+
+/**
+ * Inflates either zlib or gzip deflated memory. The inflated memory is
+ * expected to be freed by the caller.
+ */
+int inflateMemory(unsigned char *in, unsigned int inLength,
+ unsigned char *&out, unsigned int &outLength);
+
+int inflateMemory(unsigned char *in, unsigned int inLength,
+ unsigned char *&out);
+
+/**
+ * Loads the given file from the filesystem, uncompressing if it ends in ".gz".
+ *
+ * @param filename The name of the file to be loaded and uncompressed
+ * @param filesize The size of the file that was loaded and uncompressed.
+ *
+ * @return An allocated byte array containing the data that was loaded and
+ * uncompressed, or <code>NULL</code> on fail.
+ */
+void *loadCompressedFile(const std::string &filename, int &filesize);
+
+#endif // UTILS_ZLIB_H