aboutsummaryrefslogtreecommitdiff
path: root/externals/libmpq/libmpq/extract.c
diff options
context:
space:
mode:
Diffstat (limited to 'externals/libmpq/libmpq/extract.c')
-rw-r--r--externals/libmpq/libmpq/extract.c361
1 files changed, 361 insertions, 0 deletions
diff --git a/externals/libmpq/libmpq/extract.c b/externals/libmpq/libmpq/extract.c
new file mode 100644
index 00000000000..11de1071683
--- /dev/null
+++ b/externals/libmpq/libmpq/extract.c
@@ -0,0 +1,361 @@
+/*
+ * extract.c -- global extracting function for all known file compressions
+ * in a mpq archive.
+ *
+ * Copyright (c) 2003-2008 Maik Broemme <mbroemme@plusserver.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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* generic includes. */
+#include <stdlib.h>
+#include <string.h>
+
+/* zlib includes. */
+#include <zlib.h>
+#include <bzlib.h>
+
+/* libmpq main includes. */
+#include "mpq.h"
+
+/* libmpq generic includes. */
+#include "explode.h"
+#include "extract.h"
+#include "huffman.h"
+#include "wave.h"
+
+/* table with decompression bits and functions. */
+static decompress_table_s dcmp_table[] = {
+ {LIBMPQ_COMPRESSION_HUFFMAN, libmpq__decompress_huffman}, /* decompression using huffman trees. */
+ {LIBMPQ_COMPRESSION_ZLIB, libmpq__decompress_zlib}, /* decompression with the zlib library. */
+ {LIBMPQ_COMPRESSION_PKZIP, libmpq__decompress_pkzip}, /* decompression with pkware data compression library. */
+ {LIBMPQ_COMPRESSION_BZIP2, libmpq__decompress_bzip2}, /* decompression with bzip2 library. */
+ {LIBMPQ_COMPRESSION_WAVE_MONO, libmpq__decompress_wave_mono}, /* decompression for mono waves. */
+ {LIBMPQ_COMPRESSION_WAVE_STEREO, libmpq__decompress_wave_stereo} /* decompression for stereo waves. */
+};
+
+/* this function decompress a stream using huffman algorithm. */
+int32_t libmpq__decompress_huffman(uint8_t *in_buf, uint32_t in_size, uint8_t *out_buf, uint32_t out_size) {
+
+ /* TODO: make typdefs of this structs? */
+ /* some common variables. */
+ int32_t tb = 0;
+ struct huffman_tree_s *ht;
+ struct huffman_input_stream_s *is;
+
+ /* allocate memory for the huffman tree. */
+ if ((ht = malloc(sizeof(struct huffman_tree_s))) == NULL ||
+ (is = malloc(sizeof(struct huffman_input_stream_s))) == NULL) {
+
+ /* memory allocation problem. */
+ return LIBMPQ_ERROR_MALLOC;
+ }
+
+ /* cleanup structures. */
+ memset(ht, 0, sizeof(struct huffman_tree_s));
+ memset(is, 0, sizeof(struct huffman_input_stream_s));
+
+ /* initialize input stream. */
+ is->bit_buf = *(uint32_t *)in_buf;
+ in_buf += sizeof(int32_t);
+ is->in_buf = (uint8_t *)in_buf;
+ is->bits = 32;
+
+// TODO: add all the mallocs to init function and add function libmpq__huffman_tree_free() */
+// if ((result = libmpq__huffman_tree_init(ht, LIBMPQ_HUFF_DECOMPRESS)) < 0) {
+//
+// /* something on zlib initialization failed. */
+// return LIBMPQ_ERROR_UNPACK;
+// }
+
+ /* initialize the huffman tree for decompression. */
+ libmpq__huffman_tree_init(ht, LIBMPQ_HUFF_DECOMPRESS);
+
+ /* save the number of copied bytes. */
+ tb = libmpq__do_decompress_huffman(ht, is, out_buf, out_size);
+
+ /* free structures. */
+ free(is);
+ free(ht);
+
+ /* return transferred bytes. */
+ return tb;
+}
+
+/* this function decompress a stream using zlib algorithm. */
+int32_t libmpq__decompress_zlib(uint8_t *in_buf, uint32_t in_size, uint8_t *out_buf, uint32_t out_size) {
+
+ /* some common variables. */
+ int32_t result = 0;
+ int32_t tb = 0;
+ z_stream z;
+
+ /* fill the stream structure for zlib. */
+ z.next_in = (Bytef *)in_buf;
+ z.avail_in = (uInt)in_size;
+ z.total_in = in_size;
+ z.next_out = (Bytef *)out_buf;
+ z.avail_out = (uInt)out_size;
+ z.total_out = 0;
+ z.zalloc = NULL;
+ z.zfree = NULL;
+
+ /* initialize the decompression structure, storm.dll uses zlib version 1.1.3. */
+ if ((result = inflateInit(&z)) != Z_OK) {
+
+ /* something on zlib initialization failed. */
+ return result;
+ }
+
+ /* call zlib to decompress the data. */
+ if ((result = inflate(&z, Z_FINISH)) != Z_STREAM_END) {
+
+ /* something on zlib decompression failed. */
+ return result;
+ }
+
+ /* save transferred bytes. */
+ tb = z.total_out;
+
+ /* cleanup zlib. */
+ if ((result = inflateEnd(&z)) != Z_OK) {
+
+ /* something on zlib finalization failed. */
+ return result;
+ }
+
+ /* return transferred bytes. */
+ return tb;
+}
+
+/* this function decompress a stream using pkzip algorithm. */
+int32_t libmpq__decompress_pkzip(uint8_t *in_buf, uint32_t in_size, uint8_t *out_buf, uint32_t out_size) {
+
+ /* some common variables. */
+ int32_t tb = 0;
+ uint8_t *work_buf;
+ pkzip_data_s info;
+
+ /* allocate memory for pkzip data structure. */
+ if ((work_buf = malloc(sizeof(pkzip_cmp_s))) == NULL) {
+
+ /* memory allocation problem. */
+ return LIBMPQ_ERROR_MALLOC;
+ }
+
+ /* cleanup. */
+ memset(work_buf, 0, sizeof(pkzip_cmp_s));
+
+ /* fill data information structure. */
+ info.in_buf = in_buf;
+ info.in_pos = 0;
+ info.in_bytes = in_size;
+ info.out_buf = out_buf;
+ info.out_pos = 0;
+ info.max_out = out_size;
+
+ /* do the decompression. */
+ if ((tb = libmpq__do_decompress_pkzip(work_buf, &info)) < 0) {
+
+ /* free working buffer. */
+ free(work_buf);
+
+ /* something failed on pkzip decompression. */
+ return tb;
+ }
+
+ /* save transferred bytes. */
+ tb = info.out_pos;
+
+ /* free working buffer. */
+ free(work_buf);
+
+ /* return transferred bytes. */
+ return tb;
+}
+
+/* this function decompress a stream using bzip2 library. */
+int32_t libmpq__decompress_bzip2(uint8_t *in_buf, uint32_t in_size, uint8_t *out_buf, uint32_t out_size) {
+
+ /* some common variables. */
+ int32_t result = 0;
+ int32_t tb = 0;
+ bz_stream strm;
+
+ /* initialize the bzlib decompression. */
+ strm.bzalloc = NULL;
+ strm.bzfree = NULL;
+
+ /* initialize the structure. */
+ if ((result = BZ2_bzDecompressInit(&strm, 0, 0)) != BZ_OK) {
+
+ /* something on bzlib initialization failed. */
+ return result;
+ }
+
+ /* fill the stream structure for bzlib. */
+ strm.next_in = (char *)in_buf;
+ strm.avail_in = in_size;
+ strm.next_out = (char *)out_buf;
+ strm.avail_out = out_size;
+
+ /* do the decompression. */
+ while (BZ2_bzDecompress(&strm) != BZ_STREAM_END);
+
+ /* save transferred bytes. */
+ tb = strm.total_out_lo32;
+
+ /* cleanup of bzip stream. */
+ BZ2_bzDecompressEnd(&strm);
+
+ /* return transferred bytes. */
+ return tb;
+}
+
+/* this function decompress a stream using wave algorithm. (1 channel) */
+int32_t libmpq__decompress_wave_mono(uint8_t *in_buf, uint32_t in_size, uint8_t *out_buf, uint32_t out_size) {
+
+ /* some common variables. */
+ int32_t tb = 0;
+
+ /* save the number of copied bytes. */
+ if ((tb = libmpq__do_decompress_wave(out_buf, out_size, in_buf, in_size, 1)) < 0) {
+
+ /* something on wave decompression failed. */
+ return tb;
+ }
+
+ /* return transferred bytes. */
+ return tb;
+}
+
+/* this function decompress a stream using wave algorithm. (2 channels) */
+int32_t libmpq__decompress_wave_stereo(uint8_t *in_buf, uint32_t in_size, uint8_t *out_buf, uint32_t out_size) {
+
+ /* some common variables. */
+ int32_t tb = 0;
+
+ /* save the number of copied bytes. */
+ if ((tb = libmpq__do_decompress_wave(out_buf, out_size, in_buf, in_size, 2)) < 0) {
+
+ /* something on wave decompression failed. */
+ return tb;
+ }
+
+ /* return transferred bytes. */
+ return tb;
+}
+
+/* this function decompress a stream using a combination of the other compression algorithm. */
+int32_t libmpq__decompress_multi(uint8_t *in_buf, uint32_t in_size, uint8_t *out_buf, uint32_t out_size) {
+
+ /* some common variables. */
+ int32_t tb = 0;
+ uint32_t count = 0;
+ uint32_t entries = (sizeof(dcmp_table) / sizeof(decompress_table_s));
+ uint8_t *temp_buf = NULL;
+ uint8_t *work_buf = 0;
+ uint8_t decompress_flag, decompress_unsupp;
+ uint32_t i;
+
+ /* get applied compression types. */
+ decompress_flag = decompress_unsupp = *in_buf++;
+
+ /* decrement data size. */
+ in_size--;
+
+ /* search decompression table type and get all types of compression. */
+ for (i = 0; i < entries; i++) {
+
+ /* check if have to apply this decompression. */
+ if (decompress_flag & dcmp_table[i].mask) {
+
+ /* increase counter for used compression algorithms. */
+ count++;
+ /* this algorithm is supported, remove from unsupp mask */
+ decompress_unsupp &= ~dcmp_table[i].mask;
+ }
+ }
+
+ /* check if there is some method unhandled. (e.g. compressed by future versions) */
+ if (decompress_unsupp) {
+
+ /* compression type is unknown and we need to implement it. :) */
+ return LIBMPQ_ERROR_UNPACK;
+ }
+
+ /* if multiple decompressions should be made, we need temporary buffer for the data. */
+ if (count > 1) {
+
+ /* allocate memory for temporary buffer. */
+ if ((temp_buf = malloc(out_size)) == NULL) {
+
+ /* memory allocation problem. */
+ return LIBMPQ_ERROR_MALLOC;
+ }
+
+ /* cleanup. */
+ memset(temp_buf, 0, out_size);
+ }
+
+ /* apply all decompressions. */
+ for (i = 0, count = 0; i < entries; i++) {
+
+ /* check if not used this kind of compression. */
+ if (decompress_flag & dcmp_table[i].mask) {
+
+ /* if multiple decompressions should be made, we need temporary buffer for the data. */
+ if (count == 0) {
+
+ /* use output buffer as working buffer. */
+ work_buf = out_buf;
+ } else {
+
+ /* use temporary buffer as working buffer. */
+ work_buf = temp_buf;
+ }
+
+ /* decompress buffer using corresponding function. */
+ if ((tb = dcmp_table[i].decompress(in_buf, in_size, work_buf, out_size)) < 0) {
+
+ /* free temporary buffer. */
+ free(temp_buf);
+
+ /* something on decompression failed. */
+ return tb;
+ }
+
+ /* move output size to source size for next compression. */
+ in_size = out_size;
+ in_buf = work_buf;
+
+ /* increase counter. */
+ count++;
+ }
+ }
+
+ /* if output buffer is not the same like target buffer, we have to copy data (this will happen on multiple decompressions). */
+ if (work_buf != out_buf) {
+
+ /* copy buffer. */
+ memcpy(out_buf, in_buf, out_size);
+ }
+
+ /* free temporary buffer. */
+ free(temp_buf);
+
+ /* return transferred bytes. */
+ return tb;
+}