2003-03-05 19:04:34 +00:00
|
|
|
/* ScummVM - Scumm Interpreter
|
|
|
|
* Copyright (C) 2003 The ScummVM project
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* $Header$
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include "common/scummsys.h"
|
2003-03-06 15:35:07 +00:00
|
|
|
#include "sky/rnc_deco.h"
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-06 07:52:40 +00:00
|
|
|
#define ROL(x, n) (((x) << (n)) | ((x) >> (16 - (n))))
|
|
|
|
#define ROR(x, n) (((x) << (16 - (n))) | ((x) >> (n)))
|
2003-03-05 19:04:34 +00:00
|
|
|
#define XCHG(a, b) (a ^=b, b ^= a, a ^= b)
|
|
|
|
|
|
|
|
//conditional flags
|
2003-03-05 21:50:41 +00:00
|
|
|
#define CHECKSUMS 1
|
|
|
|
#define PROTECTED 0
|
2003-03-05 19:04:34 +00:00
|
|
|
|
|
|
|
//return codes
|
2003-03-05 21:50:41 +00:00
|
|
|
#define NOT_PACKED 0
|
|
|
|
#define PACKED_CRC -1
|
|
|
|
#define UNPACKED_CRC -2
|
2003-03-05 19:04:34 +00:00
|
|
|
|
|
|
|
//other defines
|
2003-03-06 07:52:40 +00:00
|
|
|
#define TABLE_SIZE (16 * 8)
|
2003-03-05 21:50:41 +00:00
|
|
|
#define MIN_LENGTH 2
|
|
|
|
#define HEADER_LEN 18
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-06 15:35:07 +00:00
|
|
|
RncDecoder::RncDecoder()
|
|
|
|
{
|
|
|
|
_bitBuffl = 0;
|
|
|
|
_bitBuffh = 0;
|
|
|
|
_bitCount = 0;
|
|
|
|
}
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-06 15:35:07 +00:00
|
|
|
RncDecoder::~RncDecoder()
|
|
|
|
{
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-06 15:35:07 +00:00
|
|
|
}
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-06 15:35:07 +00:00
|
|
|
void RncDecoder::initCrc()
|
2003-03-05 19:04:34 +00:00
|
|
|
{
|
2003-03-06 07:52:40 +00:00
|
|
|
uint16 cnt = 0;
|
|
|
|
uint16 tmp1 = 0;
|
|
|
|
uint16 tmp2 = 0;
|
2003-03-05 19:04:34 +00:00
|
|
|
|
|
|
|
for (tmp2 = 0; tmp2 < 0x100; tmp2++) {
|
2003-03-05 21:50:41 +00:00
|
|
|
tmp1 = tmp2;
|
2003-03-05 19:04:34 +00:00
|
|
|
for (cnt = 8; cnt > 0; cnt--) {
|
2003-03-05 21:50:41 +00:00
|
|
|
if (tmp1 % 2) {
|
2003-03-05 19:04:34 +00:00
|
|
|
tmp1 /= 2;
|
|
|
|
tmp1 ^= 0x0a001;
|
2003-03-05 21:50:41 +00:00
|
|
|
} else
|
|
|
|
tmp1 /= 2;
|
2003-03-05 19:04:34 +00:00
|
|
|
}
|
2003-03-06 15:35:07 +00:00
|
|
|
_crcTable[tmp2] = tmp1;
|
2003-03-05 19:04:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//calculate 16 bit crc of a block of memory
|
2003-03-06 15:35:07 +00:00
|
|
|
uint16 RncDecoder::crcBlock(uint8 *block, uint32 size)
|
2003-03-05 19:04:34 +00:00
|
|
|
{
|
2003-03-06 07:52:40 +00:00
|
|
|
uint16 crc = 0;
|
2003-03-06 15:35:07 +00:00
|
|
|
uint8 *crcTable8 = (uint8 *)_crcTable; //make a uint8* to crc_table
|
2003-03-06 07:52:40 +00:00
|
|
|
uint8 tmp;
|
|
|
|
uint32 i;
|
2003-03-05 21:50:41 +00:00
|
|
|
|
2003-03-05 19:04:34 +00:00
|
|
|
for (i = 0; i < size; i++) {
|
|
|
|
tmp = *block++;
|
|
|
|
crc ^= tmp;
|
2003-03-06 07:52:40 +00:00
|
|
|
tmp = (uint8)((crc >> 8) & 0x00FF);
|
2003-03-05 21:50:41 +00:00
|
|
|
crc &= 0x00FF;
|
2003-03-05 19:04:34 +00:00
|
|
|
crc = crc << 1;
|
2003-03-05 21:50:41 +00:00
|
|
|
crc = *(uint16 *)&crcTable8[crc];
|
2003-03-06 07:52:40 +00:00
|
|
|
crc ^= tmp;
|
2003-03-05 19:04:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return crc;
|
|
|
|
}
|
|
|
|
|
2003-03-06 15:35:07 +00:00
|
|
|
uint16 RncDecoder::inputBits(uint8 amount)
|
2003-03-05 19:04:34 +00:00
|
|
|
{
|
2003-03-06 15:35:07 +00:00
|
|
|
uint16 newBitBuffh = _bitBuffh;
|
|
|
|
uint16 newBitBuffl = _bitBuffl;
|
|
|
|
int16 newBitCount = _bitCount;
|
2003-03-05 19:04:34 +00:00
|
|
|
uint16 remBits, returnVal;
|
|
|
|
|
|
|
|
returnVal = ((1 << amount) - 1) & newBitBuffl;
|
|
|
|
newBitCount -= amount;
|
|
|
|
|
|
|
|
if (newBitCount < 0) {
|
|
|
|
newBitCount += amount;
|
|
|
|
XCHG(newBitCount, amount);
|
|
|
|
remBits = ROR((uint16)(((1 << amount) - 1) & newBitBuffh), amount);
|
|
|
|
newBitBuffh >>= amount;
|
|
|
|
newBitBuffl >>= amount;
|
|
|
|
newBitBuffl |= remBits;
|
2003-03-06 15:35:07 +00:00
|
|
|
_srcPtr += 2;
|
|
|
|
newBitBuffh = READ_LE_UINT16(_srcPtr);
|
2003-03-05 19:04:34 +00:00
|
|
|
XCHG(newBitCount, amount);
|
|
|
|
amount -= newBitCount;
|
2003-03-06 07:52:40 +00:00
|
|
|
newBitCount = 16 - amount;
|
2003-03-05 19:04:34 +00:00
|
|
|
}
|
|
|
|
remBits = ROR((uint16)(((1 << amount) - 1) & newBitBuffh), amount);
|
2003-03-06 15:35:07 +00:00
|
|
|
_bitBuffh = newBitBuffh >> amount;
|
|
|
|
_bitBuffl = (newBitBuffl >> amount) | remBits;
|
|
|
|
_bitCount = (uint8)newBitCount;
|
2003-03-05 19:04:34 +00:00
|
|
|
|
|
|
|
return returnVal;
|
|
|
|
}
|
|
|
|
|
2003-03-06 15:35:07 +00:00
|
|
|
void RncDecoder::makeHufftable(uint16 *table)
|
2003-03-05 19:04:34 +00:00
|
|
|
{
|
|
|
|
uint16 bitLength, i, j;
|
2003-03-06 15:35:07 +00:00
|
|
|
uint16 numCodes = inputBits(5);
|
2003-03-05 19:04:34 +00:00
|
|
|
|
|
|
|
if (!numCodes)
|
|
|
|
return;
|
|
|
|
|
|
|
|
uint8 huffLength[16];
|
|
|
|
for (i = 0; i < numCodes; i++)
|
2003-03-06 15:35:07 +00:00
|
|
|
huffLength[i] = (uint8)(inputBits(4) & 0x00FF);
|
2003-03-05 19:04:34 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2003-03-05 19:23:35 +00:00
|
|
|
for (j = 0; j < bitLength; j++)
|
|
|
|
a |= ((b >> j) & 1) << (bitLength - j - 1);
|
2003-03-05 19:04:34 +00:00
|
|
|
*table++ = a;
|
|
|
|
|
2003-03-06 07:52:40 +00:00
|
|
|
*(table + 0x1e) = (huffLength[i] << 8)|(i & 0x00FF);
|
2003-03-05 19:04:34 +00:00
|
|
|
huffCode += 1 << (16 - bitLength);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-03-06 15:35:07 +00:00
|
|
|
uint16 RncDecoder::inputValue(uint16 *table)
|
2003-03-05 19:04:34 +00:00
|
|
|
{
|
2003-03-06 15:35:07 +00:00
|
|
|
uint16 valOne, valTwo, value = _bitBuffl;
|
2003-03-06 07:52:40 +00:00
|
|
|
|
2003-03-05 19:04:34 +00:00
|
|
|
do {
|
|
|
|
valTwo = (*table++) & value;
|
|
|
|
valOne = *table++;
|
|
|
|
|
2003-03-06 07:52:40 +00:00
|
|
|
} while (valOne != valTwo);
|
|
|
|
|
|
|
|
value = *(table + 0x1e);
|
2003-03-06 15:35:07 +00:00
|
|
|
inputBits((uint8)((value>>8) & 0x00FF));
|
2003-03-06 07:52:40 +00:00
|
|
|
value &= 0x00FF;
|
2003-03-05 19:04:34 +00:00
|
|
|
|
|
|
|
if (value >= 2) {
|
|
|
|
value--;
|
2003-03-06 15:35:07 +00:00
|
|
|
valOne = inputBits((uint8)value & 0x00FF);
|
2003-03-05 19:04:34 +00:00
|
|
|
valOne |= (1 << value);
|
|
|
|
value = valOne;
|
|
|
|
}
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2003-03-06 15:35:07 +00:00
|
|
|
int32 RncDecoder::unpackM1(void *input, void *output, uint16 key)
|
2003-03-05 19:04:34 +00:00
|
|
|
{
|
2003-03-05 21:50:41 +00:00
|
|
|
uint8 *inputHigh, *outputLow, *outputHigh;
|
|
|
|
uint8 *inputptr = (uint8 *)input;
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-06 15:35:07 +00:00
|
|
|
uint32 unpackLen = 0;
|
|
|
|
uint32 packLen = 0;
|
2003-03-06 02:50:50 +00:00
|
|
|
uint16 counts = 0;
|
|
|
|
|
|
|
|
#ifdef CHECKSUMS
|
2003-03-06 15:35:07 +00:00
|
|
|
uint16 crcUnpacked = 0;
|
|
|
|
uint16 crcPacked = 0;
|
2003-03-06 02:50:50 +00:00
|
|
|
#endif
|
|
|
|
|
2003-03-05 21:50:41 +00:00
|
|
|
if (CHECKSUMS)
|
2003-03-06 15:35:07 +00:00
|
|
|
initCrc();
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-06 07:52:40 +00:00
|
|
|
//Check for "RNC "
|
2003-03-05 21:50:41 +00:00
|
|
|
if (READ_BE_UINT32(inputptr) != 0x524e4301)
|
|
|
|
return NOT_PACKED;
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-05 21:50:41 +00:00
|
|
|
inputptr += 4;
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-05 21:50:41 +00:00
|
|
|
// read unpacked/packed file length
|
2003-03-06 15:35:07 +00:00
|
|
|
unpackLen = READ_BE_UINT32(inputptr); inputptr += 4;
|
|
|
|
packLen = READ_BE_UINT32(inputptr); inputptr += 4;
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-06 07:52:40 +00:00
|
|
|
uint8 blocks = *(inputptr + 5);
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-05 21:50:41 +00:00
|
|
|
if (CHECKSUMS) {
|
|
|
|
//read CRC's
|
2003-03-06 15:35:07 +00:00
|
|
|
crcUnpacked = READ_BE_UINT16(inputptr); inputptr += 2;
|
|
|
|
crcPacked = READ_BE_UINT16(inputptr); inputptr += 2;
|
2003-03-06 07:52:40 +00:00
|
|
|
inputptr = (inputptr + HEADER_LEN - 16);
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-06 15:35:07 +00:00
|
|
|
if (crcBlock(inputptr, packLen) != crcPacked)
|
2003-03-05 21:50:41 +00:00
|
|
|
return PACKED_CRC;
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-06 07:52:40 +00:00
|
|
|
inputptr = (((uint8 *)input) + HEADER_LEN);
|
2003-03-06 15:35:07 +00:00
|
|
|
_srcPtr = inputptr;
|
2003-03-05 21:50:41 +00:00
|
|
|
}
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-05 21:50:41 +00:00
|
|
|
// inputLow = *input
|
2003-03-06 15:35:07 +00:00
|
|
|
inputHigh = ((uint8 *)input) + packLen + HEADER_LEN;;
|
2003-03-05 19:04:34 +00:00
|
|
|
outputLow = (uint8 *)output;
|
2003-03-06 15:35:07 +00:00
|
|
|
outputHigh = *(((uint8 *)input) + 16) + unpackLen + outputLow;
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-05 21:50:41 +00:00
|
|
|
if (! ((inputHigh <= outputLow) || (outputHigh <= inputHigh)) ) {
|
2003-03-06 15:35:07 +00:00
|
|
|
_srcPtr = inputHigh;
|
|
|
|
_dstPtr = outputHigh;
|
|
|
|
memcpy((_dstPtr-packLen), (_srcPtr-packLen), packLen);
|
|
|
|
_srcPtr = (_dstPtr-packLen);
|
2003-03-05 19:04:34 +00:00
|
|
|
}
|
|
|
|
|
2003-03-06 15:35:07 +00:00
|
|
|
_dstPtr = (uint8 *)output;
|
|
|
|
_bitCount = 0;
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-06 15:35:07 +00:00
|
|
|
_bitBuffl = READ_LE_UINT16(_srcPtr);
|
|
|
|
inputBits(2);
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-05 21:50:41 +00:00
|
|
|
do {
|
2003-03-06 15:35:07 +00:00
|
|
|
makeHufftable(_rawTable);
|
|
|
|
makeHufftable(_posTable);
|
|
|
|
makeHufftable(_lenTable);
|
2003-03-05 21:50:41 +00:00
|
|
|
|
2003-03-06 15:35:07 +00:00
|
|
|
counts = inputBits(16);
|
2003-03-05 21:50:41 +00:00
|
|
|
|
|
|
|
for (;;) {
|
2003-03-06 16:08:13 +00:00
|
|
|
uint32 inputBytes = inputValue(_rawTable);
|
2003-03-06 15:35:07 +00:00
|
|
|
|
2003-03-06 16:08:13 +00:00
|
|
|
if (inputBytes) {
|
|
|
|
memcpy(_dstPtr, _srcPtr, inputBytes); //memcpy is allowed here
|
|
|
|
_dstPtr += inputBytes;
|
|
|
|
_srcPtr += inputBytes;
|
2003-03-06 15:35:07 +00:00
|
|
|
uint16 b = READ_LE_UINT16(_srcPtr);
|
|
|
|
uint16 a = ROL(b, _bitCount);
|
|
|
|
uint16 d = ((1 << _bitCount) - 1);
|
|
|
|
_bitBuffl &= d;
|
2003-03-05 21:50:41 +00:00
|
|
|
d &= a;
|
|
|
|
|
2003-03-06 15:35:07 +00:00
|
|
|
a = READ_LE_UINT16((_srcPtr + 2));
|
|
|
|
b = (b << _bitCount);
|
|
|
|
a = (a << _bitCount);
|
2003-03-05 21:50:41 +00:00
|
|
|
a |= d;
|
2003-03-06 15:35:07 +00:00
|
|
|
_bitBuffl |= b;
|
|
|
|
_bitBuffh = a;
|
2003-03-05 21:50:41 +00:00
|
|
|
}
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-05 21:50:41 +00:00
|
|
|
if (--counts) {
|
2003-03-06 15:35:07 +00:00
|
|
|
uint32 inputOffset = inputValue(_posTable) + 1;
|
|
|
|
uint32 inputLength = inputValue(_lenTable) + MIN_LENGTH;
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-06 15:35:07 +00:00
|
|
|
inputHigh = _srcPtr;
|
|
|
|
_srcPtr = (_dstPtr-inputOffset);
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-05 21:50:41 +00:00
|
|
|
//Don't use memcpy here! because input and output overlap
|
2003-03-06 15:35:07 +00:00
|
|
|
while (inputLength--)
|
|
|
|
*_dstPtr++ = *_srcPtr++;
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-06 15:35:07 +00:00
|
|
|
_srcPtr = inputHigh;
|
2003-03-05 21:50:41 +00:00
|
|
|
} else
|
|
|
|
break;
|
2003-03-05 19:04:34 +00:00
|
|
|
|
2003-03-05 21:50:41 +00:00
|
|
|
}
|
|
|
|
} while (--blocks);
|
2003-03-05 19:04:34 +00:00
|
|
|
|
|
|
|
if (CHECKSUMS) {
|
2003-03-06 15:35:07 +00:00
|
|
|
if (crcBlock((uint8 *)output, unpackLen) != crcUnpacked)
|
2003-03-05 19:04:34 +00:00
|
|
|
return UNPACKED_CRC;
|
|
|
|
}
|
|
|
|
|
2003-03-05 21:50:41 +00:00
|
|
|
// all is done..return the amount of unpacked bytes
|
2003-03-06 15:35:07 +00:00
|
|
|
return unpackLen;
|
2003-03-05 19:04:34 +00:00
|
|
|
}
|
2003-03-05 21:50:41 +00:00
|
|
|
|