/* * The Mana Client * Copyright (C) 2004-2009 The Mana World Development Team * Copyright (C) 2009-2012 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 . */ #include "utils/zlib.h" #include "log.h" #include #include #include #include #include /** * 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 == nullptr) { 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 == nullptr) { 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 == nullptr) { 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 = nullptr; outLength = 0; } return outLength; } void *loadCompressedFile(const std::string &filename, int &filesize) { std::ifstream file; file.open(filename, 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 (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) { logger->log("Could not decompress file: %s", filename.c_str()); return nullptr; } filesize = inflatedSize; return inflated; } else { return buffer; } } else { logger->log("Error loading file from drive: %s", filename.c_str()); } return nullptr; }