diff options
author | Jared Adams <jaxad0127@gmail.com> | 2010-08-13 14:45:52 -0600 |
---|---|---|
committer | Jared Adams <jaxad0127@gmail.com> | 2010-08-13 18:43:16 -0600 |
commit | 8eadc834ed3e8439836f7dc87390a56a1164ec11 (patch) | |
tree | 36cf9915914517b137d488a40d1f61265867723d /src/utils | |
parent | 6d315d0e61f419636021476582a49ab0b1f1b5e9 (diff) | |
download | mana-8eadc834ed3e8439836f7dc87390a56a1164ec11.tar.gz mana-8eadc834ed3e8439836f7dc87390a56a1164ec11.tar.bz2 mana-8eadc834ed3e8439836f7dc87390a56a1164ec11.tar.xz mana-8eadc834ed3e8439836f7dc87390a56a1164ec11.zip |
Simplify handling of compressed files
ResourceManager will now check for ".gz" and act appropriately (unless told
not to). Compression handling functions are now in new utils/zlib files,
along with a function to load a file from drive, uncompressing it if it ends
in ".gz".
Reviewed-by: Freeyorp
Diffstat (limited to 'src/utils')
-rw-r--r-- | src/utils/xml.cpp | 25 | ||||
-rw-r--r-- | src/utils/zlib.cpp | 184 | ||||
-rw-r--r-- | src/utils/zlib.h | 48 |
3 files changed, 235 insertions, 22 deletions
diff --git a/src/utils/xml.cpp b/src/utils/xml.cpp index 8d444fab..9835f88c 100644 --- a/src/utils/xml.cpp +++ b/src/utils/xml.cpp @@ -25,12 +25,11 @@ #include "resources/resourcemanager.h" +#include "utils/zlib.h" + #include <libxml/parser.h> #include <libxml/xmlerror.h> -#include <fstream> -#include <iostream> - namespace XML { static void xmlLogger(void *ctx, xmlErrorPtr error); @@ -58,25 +57,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) 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 |