aboutsummaryrefslogtreecommitdiff
path: root/engines/toon/tools.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/toon/tools.cpp')
-rw-r--r--engines/toon/tools.cpp516
1 files changed, 516 insertions, 0 deletions
diff --git a/engines/toon/tools.cpp b/engines/toon/tools.cpp
new file mode 100644
index 0000000000..a03a2d57ce
--- /dev/null
+++ b/engines/toon/tools.cpp
@@ -0,0 +1,516 @@
+/* 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 "toon/tools.h"
+#include "toon/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);
+ _dstPtr++;
+ }
+
+ }
+
+ if (crcBlock((uint8 *)output, unpackLen) != crcUnpacked)
+ return UNPACKED_CRC;
+
+ // all is done..return the amount of unpacked bytes
+ return unpackLen;
+}
+
+} // End of namespace Toon