Files
azerothcore-wotlk/deps/libmpq/libmpq/common.c
Yehonal f06f32849f Directory Structure [step 1]: moving files
working on #672

NOTE: This commit can't be compiled!!
2017-10-12 20:00:52 +02:00

221 lines
6.3 KiB
C

/*
* common.c -- shared functions used by mpq-tools.
*
* 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 <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
/* libmpq main includes. */
#include "mpq.h"
#include "mpq-internal.h"
/* libmpq generic includes. */
#include "extract.h"
#include "common.h"
/* the global shared decryption buffer. it's a static array compiled into the
* library, and can be re-created by compiling and running crypt_buf_gen.c
*/
#include "crypt_buf.h"
/* function to return the hash to a given string. */
uint32_t libmpq__hash_string(const char *key, uint32_t offset) {
/* some common variables. */
uint32_t seed1 = 0x7FED7FED;
uint32_t seed2 = 0xEEEEEEEE;
/* one key character. */
uint32_t ch;
/* prepare seeds. */
while (*key != 0) {
ch = toupper(*key++);
seed1 = crypt_buf[offset + ch] ^ (seed1 + seed2);
seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
}
return seed1;
}
/* function to encrypt a block. */
int32_t libmpq__encrypt_block(uint32_t *in_buf, uint32_t in_size, uint32_t seed) {
/* some common variables. */
uint32_t seed2 = 0xEEEEEEEE;
uint32_t ch;
/* we're processing the data 4 bytes at a time. */
for (; in_size >= 4; in_size -= 4) {
seed2 += crypt_buf[0x400 + (seed & 0xFF)];
ch = *in_buf ^ (seed + seed2);
seed = ((~seed << 0x15) + 0x11111111) | (seed >> 0x0B);
seed2 = *in_buf + seed2 + (seed2 << 5) + 3;
*in_buf++ = ch;
}
/* if no error was found, return decrypted bytes. */
return LIBMPQ_SUCCESS;
}
/* function to decrypt a block. */
int32_t libmpq__decrypt_block(uint32_t *in_buf, uint32_t in_size, uint32_t seed) {
/* some common variables. */
uint32_t seed2 = 0xEEEEEEEE;
uint32_t ch;
/* we're processing the data 4 bytes at a time. */
for (; in_size >= 4; in_size -= 4) {
seed2 += crypt_buf[0x400 + (seed & 0xFF)];
ch = *in_buf ^ (seed + seed2);
seed = ((~seed << 0x15) + 0x11111111) | (seed >> 0x0B);
seed2 = ch + seed2 + (seed2 << 5) + 3;
*in_buf++ = ch;
}
/* if no error was found, return decrypted bytes. */
return LIBMPQ_SUCCESS;
}
/* function to detect decryption key. */
int32_t libmpq__decrypt_key(uint8_t *in_buf, uint32_t in_size, uint32_t block_size, uint32_t *key) {
/* some common variables. */
uint32_t saveseed1;
/* temp = seed1 + seed2 */
uint32_t temp;
uint32_t i = 0;
/* temp = seed1 + buffer[0x400 + (seed1 & 0xFF)] */
temp = (*(uint32_t *)in_buf ^ in_size) - 0xEEEEEEEE;
/* try all 255 possibilities. */
for (i = 0; i < 0x100; i++) {
/* some common variables. */
uint32_t seed1;
uint32_t seed2 = 0xEEEEEEEE;
uint32_t ch;
uint32_t ch2;
/* try the first uint32_t's (we exactly know the value). */
seed1 = temp - crypt_buf[0x400 + i];
seed2 += crypt_buf[0x400 + (seed1 & 0xFF)];
ch = ((uint32_t *)in_buf)[0] ^ (seed1 + seed2);
if (ch != in_size) {
continue;
}
/* add one because we are decrypting block positions. */
saveseed1 = seed1 + 1;
ch2 = ch;
/*
* if ok, continue and test the second value. we don't know exactly the value,
* but we know that the second one has lower 16 bits set to zero (no compressed
* block is larger than 0xFFFF bytes)
*/
seed1 = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
seed2 = ch + seed2 + (seed2 << 5) + 3;
seed2 += crypt_buf[0x400 + (seed1 & 0xFF)];
ch = ((uint32_t *)in_buf)[1] ^ (seed1 + seed2);
/* check if we found the file seed. */
if ((ch - ch2) <= block_size) {
/* file seed found, so return it. */
*key = saveseed1;
return LIBMPQ_SUCCESS;
}
}
/* if no file seed was found return with error. */
return LIBMPQ_ERROR_DECRYPT;
}
/* function to decompress or explode a block from mpq archive. */
int32_t libmpq__decompress_block(uint8_t *in_buf, uint32_t in_size, uint8_t *out_buf, uint32_t out_size, uint32_t compression_type) {
/* some common variables. */
int32_t tb = 0;
/* check if buffer is not compressed. */
if (compression_type == LIBMPQ_FLAG_COMPRESS_NONE) {
/* no compressed data, so copy input buffer to output buffer. */
memcpy(out_buf, in_buf, out_size);
/* store number of bytes copied. */
tb = out_size;
}
/* check if one compression mode is used. */
else if (compression_type == LIBMPQ_FLAG_COMPRESS_PKZIP ||
compression_type == LIBMPQ_FLAG_COMPRESS_MULTI) {
/* check if block is really compressed, some blocks have set the compression flag, but are not compressed. */
if (in_size < out_size) {
/* check if we are using pkzip compression algorithm. */
if (compression_type == LIBMPQ_FLAG_COMPRESS_PKZIP) {
/* decompress using pkzip. */
if ((tb = libmpq__decompress_pkzip(in_buf, in_size, out_buf, out_size)) < 0) {
/* something on decompression failed. */
return tb;
}
}
/* check if we are using multiple compression algorithm. */
else if (compression_type == LIBMPQ_FLAG_COMPRESS_MULTI) {
/*
* check if it is a file compressed by blizzard's multiple compression, note that storm.dll
* version 1.0.9 distributed with warcraft 3 passes the full path name of the opened archive
* as the new last parameter.
*/
if ((tb = libmpq__decompress_multi(in_buf, in_size, out_buf, out_size)) < 0) {
/* something on decompression failed. */
return tb;
}
}
} else {
/* block has set compression flag, but is not compressed, so copy data to output buffer. */
memcpy(out_buf, in_buf, out_size);
/* save the number of transferred bytes. */
tb = in_size;
}
}
/* if no error was found, return transferred bytes. */
return tb;
}