diff options
author | Chuck Miller <shadowmil@gmail.com> | 2010-08-15 15:57:21 -0400 |
---|---|---|
committer | Chuck Miller <shadowmil@gmail.com> | 2010-08-15 15:57:21 -0400 |
commit | 8f573b6c425dc82be42ad80eae565b0641a90a3b (patch) | |
tree | 149c7889d384e10fd9dc95f1aa90478e69b314c8 /src | |
parent | fee9fbce12e620f25aecdc0690285cc47fa8791d (diff) | |
parent | 2b676bbf6fcf7dfd45cb33f06dacd2ca5bce19fe (diff) | |
download | mana-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.txt | 14 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/main.cpp | 23 | ||||
-rw-r--r-- | src/net/manaserv/gamehandler.cpp | 10 | ||||
-rw-r--r-- | src/net/manaserv/network.cpp | 4 | ||||
-rw-r--r-- | src/net/manaserv/playerhandler.cpp | 17 | ||||
-rw-r--r-- | src/net/manaserv/stats.cpp | 12 | ||||
-rw-r--r-- | src/net/tmwa/gamehandler.cpp | 3 | ||||
-rw-r--r-- | src/resources/mapreader.cpp | 142 | ||||
-rw-r--r-- | src/resources/resourcemanager.cpp | 45 | ||||
-rw-r--r-- | src/resources/resourcemanager.h | 9 | ||||
-rw-r--r-- | src/utils/xml.cpp | 77 | ||||
-rw-r--r-- | src/utils/xml.h | 14 | ||||
-rw-r--r-- | src/utils/zlib.cpp | 184 | ||||
-rw-r--r-- | src/utils/zlib.h | 48 |
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 |