diff options
Diffstat (limited to 'engines/toon/tools.cpp')
| -rw-r--r-- | engines/toon/tools.cpp | 514 | 
1 files changed, 514 insertions, 0 deletions
| diff --git a/engines/toon/tools.cpp b/engines/toon/tools.cpp new file mode 100644 index 0000000000..856fc59eb4 --- /dev/null +++ b/engines/toon/tools.cpp @@ -0,0 +1,514 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* $URL$ +* $Id$ +* +*/ + +#include "tools.h" +#include "toon.h" + +namespace Toon { + +uint32 decompressLZSS(byte *src, byte *dst, int dstsize) { +	debugC(5, kDebugTools, "decompressLZSS(src, dst, %d)", dstsize); + +	byte *srcp = src; +	byte *dstp = dst; +	uint16 bitbuf; +	int32 len, ofs; +	len = 0; +	while (dstsize > 0) { +		bitbuf = 0x100 | *(srcp++); +		while (bitbuf != 1 && dstsize > 0) { +			if (bitbuf & 1) { +				ofs = READ_LE_UINT16(srcp); +				srcp += 2; +				len = ((ofs & 0xF000) >> 12) + 3; +				ofs = ofs | 0xF000; +				dstsize -= len; +				if (dstsize < 0) +					break; +				while (len--) { +					*dstp = *(byte *)(dstp + (signed short)ofs); +					dstp++; +				} +			} else { +				len = 0; +				while ((bitbuf & 2) == 0) { +					len++; +					bitbuf >>= 1; +				} +				len++; +				dstsize -= len; +				if (dstsize < 0) +					break; +				while (len--) +					*(dstp++) = *(srcp++); +			} +			bitbuf >>= 1; +		} +	} +	len += dstsize; +	if (len < 0) +		return 0; + +	while (len--) +		*(dstp++) = *(srcp++); + +	return (dstp - dst); +} + +uint32 decompressSPCN(byte *src, byte *dst, uint32 dstsize) { +	debugC(1, kDebugTools, "decompressSPCN(src, dst, %d)", dstsize); + +	byte *srcp = src; +	byte *dstp = dst, *dste = dst + dstsize; +	byte val; +	uint16 len, ofs; +	if (!(*srcp & 0x80)) srcp++; +	while (dstp < dste) { +		val = *(srcp++); +		if (val & 0x80) { +			if (val & 0x40) { +				if (val == 0xFE) { +					len = READ_LE_UINT16(srcp); +					while (len--) +						*(dstp++) = srcp[2]; +					srcp += 3; +				} else { +					if (val == 0xFF) { +						len = READ_LE_UINT16(srcp); +						srcp += 2; +					} else { +						len = (val & 0x3F) + 3; +					} +					ofs = READ_LE_UINT16(srcp); +					srcp += 2; +					while (len--) { +						*dstp = *(byte *)(dstp - ofs); +						dstp++; +					} +				} +			} else { +				len = val & 0x3F; +				while (len--) +					*(dstp++) = *(srcp++); +			} +		} else { +			len = (val >> 4) + 3; +			ofs = ((val & 0x0F) << 8) | *(srcp++); +			while (len--) { +				*dstp = *(byte *)(dstp - ofs); +				dstp++; +			} +		} +	} +	return (dstp - dst); +} + + +//return codes +#define NOT_PACKED  0 +#define PACKED_CRC  -1 +#define UNPACKED_CRC    -2 + +//other defines +#define TABLE_SIZE  (16 * 8) +#define MIN_LENGTH  2 +#define HEADER_LEN  18 + +RncDecoder::RncDecoder() { +	initCrc(); +} + +RncDecoder::~RncDecoder() { } + +void RncDecoder::initCrc() { +	debugC(1, kDebugTools, "initCrc()"); + +	uint16 cnt = 0; +	uint16 tmp1 = 0; +	uint16 tmp2 = 0; + +	for (tmp2 = 0; tmp2 < 0x100; tmp2++) { +		tmp1 = tmp2; +		for (cnt = 8; cnt > 0; cnt--) { +			if (tmp1 % 2) { +				tmp1 >>= 1; +				tmp1 ^= 0x0a001; +			} else +				tmp1 >>= 1; +		} +		_crcTable[tmp2] = tmp1; +	} +} + +//calculate 16 bit crc of a block of memory +uint16 RncDecoder::crcBlock(const uint8 *block, uint32 size) { +	debugC(1, kDebugTools, "crcBlock(block, %d)", size); + +	uint16 crc = 0; +	uint8 *crcTable8 = (uint8 *)_crcTable; //make a uint8* to crc_table +	uint8 tmp; +	uint32 i; + +	for (i = 0; i < size; i++) { +		tmp = *block++; +		crc ^= tmp; +		tmp = (uint8)((crc >> 8) & 0x00FF); +		crc &= 0x00FF; +		crc = *(uint16 *)&crcTable8[crc << 1]; +		crc ^= tmp; +	} + +	return crc; +} + +uint16 RncDecoder::inputBits(uint8 amount) { +	debugC(5, kDebugTools, "inputBits(%d)", amount); + +	uint16 newBitBuffh = _bitBuffh; +	uint16 newBitBuffl = _bitBuffl; +	int16 newBitCount = _bitCount; +	uint16 remBits, returnVal; + +	returnVal = ((1 << amount) - 1) & newBitBuffl; +	newBitCount -= amount; + +	if (newBitCount < 0) { +		newBitCount += amount; +		remBits = (newBitBuffh << (16 - newBitCount)); +		newBitBuffh >>= newBitCount; +		newBitBuffl >>= newBitCount; +		newBitBuffl |= remBits; +		_srcPtr += 2; +		newBitBuffh = READ_LE_UINT16(_srcPtr); +		amount -= newBitCount; +		newBitCount = 16 - amount; +	} +	remBits = (newBitBuffh << (16 - amount)); +	_bitBuffh = newBitBuffh >> amount; +	_bitBuffl = (newBitBuffl >> amount) | remBits; +	_bitCount = (uint8)newBitCount; + +	return returnVal; +} + +void RncDecoder::makeHufftable(uint16 *table) { +	debugC(1, kDebugTools, "makeHufftable(table)"); + +	uint16 bitLength, i, j; +	uint16 numCodes = inputBits(5); + +	if (!numCodes) +		return; + +	uint8 huffLength[16]; +	for (i = 0; i < numCodes; i++) +		huffLength[i] = (uint8)(inputBits(4) & 0x00FF); + +	uint16 huffCode = 0; + +	for (bitLength = 1; bitLength < 17; bitLength++) { +		for (i = 0; i < numCodes; i++) { +			if (huffLength[i] == bitLength) { +				*table++ = (1 << bitLength) - 1; + +				uint16 b = huffCode >> (16 - bitLength); +				uint16 a = 0; + +				for (j = 0; j < bitLength; j++) +					a |= ((b >> j) & 1) << (bitLength - j - 1); +				*table++ = a; + +				*(table + 0x1e) = (huffLength[i] << 8) | (i & 0x00FF); +				huffCode += 1 << (16 - bitLength); +			} +		} +	} +} + +uint16 RncDecoder::inputValue(uint16 *table) { +	debugC(5, kDebugTools, "inputValue(table)"); + +	uint16 valOne, valTwo, value = _bitBuffl; + +	do { +		valTwo = (*table++) & value; +		valOne = *table++; +	} while (valOne != valTwo); + +	value = *(table + 0x1e); +	inputBits((uint8)((value >> 8) & 0x00FF)); +	value &= 0x00FF; + +	if (value >= 2) { +		value--; +		valOne = inputBits((uint8)value & 0x00FF); +		valOne |= (1 << value); +		value = valOne; +	} + +	return value; +} + +int RncDecoder::getbit() { +	debugC(6, kDebugTools, "getbits()"); + +	if (_bitCount == 0) { +		_bitBuffl = *_srcPtr++; +		_bitCount = 8; +	} +	byte temp = (_bitBuffl & 0x80) >> 7; +	_bitBuffl <<= 1; +	_bitCount--; +	return temp; +} + +int32 RncDecoder::unpackM1(const void *input, void *output) { +	debugC(1, kDebugTools, "unpackM1(input, output)"); + +	uint8 *outputLow, *outputHigh; +	const uint8 *inputHigh, *inputptr = (const uint8 *)input; + +	uint32 unpackLen = 0; +	uint32 packLen = 0; +	uint16 counts = 0; +	uint16 crcUnpacked = 0; +	uint16 crcPacked = 0; + + +	_bitBuffl = 0; +	_bitBuffh = 0; +	_bitCount = 0; + +	//Check for "RNC " +	if (READ_BE_UINT32(inputptr) != RNC1_SIGNATURE) +		return NOT_PACKED; + +	inputptr += 4; + +	// read unpacked/packed file length +	unpackLen = READ_BE_UINT32(inputptr); +	inputptr += 4; +	packLen = READ_BE_UINT32(inputptr); +	inputptr += 4; + +	uint8 blocks = *(inputptr + 5); + +	//read CRC's +	crcUnpacked = READ_BE_UINT16(inputptr); +	inputptr += 2; +	crcPacked = READ_BE_UINT16(inputptr); +	inputptr += 2; +	inputptr = (inputptr + HEADER_LEN - 16); + +	if (crcBlock(inputptr, packLen) != crcPacked) +		return PACKED_CRC; + +	inputptr = (((const uint8 *)input) + HEADER_LEN); +	_srcPtr = inputptr; + +	inputHigh = ((const uint8 *)input) + packLen + HEADER_LEN; +	outputLow = (uint8 *)output; +	outputHigh = *(((const uint8 *)input) + 16) + unpackLen + outputLow; + +	if (!((inputHigh <= outputLow) || (outputHigh <= inputHigh))) { +		_srcPtr = inputHigh; +		_dstPtr = outputHigh; +		memcpy((_dstPtr - packLen), (_srcPtr - packLen), packLen); +		_srcPtr = (_dstPtr - packLen); +	} + +	_dstPtr = (uint8 *)output; +	_bitCount = 0; + +	_bitBuffl = READ_LE_UINT16(_srcPtr); +	inputBits(2); + +	do { +		makeHufftable(_rawTable); +		makeHufftable(_posTable); +		makeHufftable(_lenTable); + +		counts = inputBits(16); + +		do { +			uint32 inputLength = inputValue(_rawTable); +			uint32 inputOffset; + +			if (inputLength) { +				memcpy(_dstPtr, _srcPtr, inputLength); //memcpy is allowed here +				_dstPtr += inputLength; +				_srcPtr += inputLength; +				uint16 a = READ_LE_UINT16(_srcPtr); +				uint16 b = READ_LE_UINT16(_srcPtr + 2); + +				_bitBuffl &= ((1 << _bitCount) - 1); +				_bitBuffl |= (a << _bitCount); +				_bitBuffh = (a >> (16 - _bitCount)) | (b << _bitCount); +			} + +			if (counts > 1) { +				inputOffset = inputValue(_posTable) + 1; +				inputLength = inputValue(_lenTable) + MIN_LENGTH; + +				// Don't use memcpy here! because input and output overlap. +				uint8 *tmpPtr = (_dstPtr - inputOffset); +				while (inputLength--) +					*_dstPtr++ = *tmpPtr++; +			} +		} while (--counts); +	} while (--blocks); + +	if (crcBlock((uint8 *)output, unpackLen) != crcUnpacked) +		return UNPACKED_CRC; + +	// all is done..return the amount of unpacked bytes +	return unpackLen; +} + +int32 RncDecoder::unpackM2(const void *input, void *output) { +	debugC(1, kDebugTools, "unpackM2(input, output)"); + +	const uint8 *inputptr = (const uint8 *)input; + +	uint32 unpackLen = 0; +	uint32 packLen = 0; +	uint16 crcUnpacked = 0; +	uint16 crcPacked = 0; + +// Strangerke - Commented (not used) +//	uint16 counts = 0; + +	_bitBuffl = 0; +	_bitCount = 0; + +	//Check for "RNC " +	if (READ_BE_UINT32(inputptr) != RNC2_SIGNATURE) +		return NOT_PACKED; + +	inputptr += 4; + +	// read unpacked/packed file length +	unpackLen = READ_BE_UINT32(inputptr); +	inputptr += 4; +	packLen = READ_BE_UINT32(inputptr); +	inputptr += 4; + +	//read CRC's +	crcUnpacked = READ_BE_UINT16(inputptr); +	inputptr += 2; +	crcPacked = READ_BE_UINT16(inputptr); +	inputptr += 2; +	inputptr = (inputptr + HEADER_LEN - 16); + +	if (crcBlock(inputptr, packLen) != crcPacked) +		return PACKED_CRC; + +	inputptr = (((const uint8 *)input) + HEADER_LEN); +	_srcPtr = inputptr; +	_dstPtr = (uint8 *)output; + + +	uint16 ofs, len; +	byte ofs_hi, ofs_lo; + +	len = 0; +	ofs_hi = 0; +	ofs_lo = 0; + +	getbit(); +	getbit(); + +	while (1) { + +		bool loadVal = false; + +		while (getbit() == 0) +			*_dstPtr++ = *_srcPtr++; + +		len = 2; +		ofs_hi = 0; +		if (getbit() == 0) { +			len = (len << 1) | getbit(); +			if (getbit() == 1) { +				len--; +				len = (len << 1) | getbit(); +				if (len == 9) { +					len = 4; +					while (len--) +						ofs_hi = (ofs_hi << 1) | getbit(); +					len = (ofs_hi + 3) * 4; +					while (len--) +						*_dstPtr++ = *_srcPtr++; +					continue; +				} +			} +			loadVal = true; +		} else { +			if (getbit() == 1) { +				len++; +				if (getbit() == 1) { +					len = *_srcPtr++; +					if (len == 0) { +						if (getbit() == 1) +							continue; +						else +							break; +					} +					len += 8; +				} +				loadVal = true; +			} else { +				loadVal = false; +			} +		} + +		if (loadVal) { +			if (getbit() == 1) { +				ofs_hi = (ofs_hi << 1) | getbit(); +				if (getbit() == 1) { +					ofs_hi = ((ofs_hi << 1) | getbit()) | 4; +					if (getbit() == 0) +						ofs_hi = (ofs_hi << 1) | getbit(); +				} else if (ofs_hi == 0) { +					ofs_hi = 2 | getbit(); +				} +			} +		} + +		ofs_lo = *_srcPtr++; +		ofs = (ofs_hi << 8) | ofs_lo; +		while (len--) +			*_dstPtr++ = *(byte *)(_dstPtr - ofs - 1); + +	} + +	if (crcBlock((uint8 *)output, unpackLen) != crcUnpacked) +		return UNPACKED_CRC; + +	// all is done..return the amount of unpacked bytes +	return unpackLen; +} + +} // End of namespace Toon | 
