scummvm/sky/rnc_deco.cpp

304 lines
6.6 KiB
C++
Raw Normal View History

/* 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"
#define ROL(x, n) (((x) << (n)) | ((x) >> (16-(n))))
#define ROR(x, n) (((x) << (16-(n))) | ((x) >> (n)))
#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
//return codes
2003-03-05 21:50:41 +00:00
#define NOT_PACKED 0
#define PACKED_CRC -1
#define UNPACKED_CRC -2
//other defines
2003-03-05 21:50:41 +00:00
#define TABLE_SIZE (16*8)
#define MIN_LENGTH 2
#define HEADER_LEN 18
uint16 raw_table[TABLE_SIZE/2];
uint16 pos_table[TABLE_SIZE/2];
uint16 len_table[TABLE_SIZE/2];
#ifdef CHECKSUMS
uint16 crc_table[0x100];
#endif
uint32 unpack_len = 0;
uint32 pack_len = 0;
uint16 pack_paras = 0;
uint16 counts = 0;
uint16 bit_buffl = 0;
uint16 bit_buffh = 0;
uint8 blocks = 0;
uint8 bit_count = 0;
#ifdef CHECKSUMS
uint16 crc_u = 0;
uint16 crc_p = 0;
#endif
uint8 *esiptr, *ediptr; //these need to be global because input_bits() uses them
void init_crc(void)
{
uint16 cnt=0;
uint16 tmp1=0;
uint16 tmp2=0;
for (tmp2 = 0; tmp2 < 0x100; tmp2++) {
2003-03-05 21:50:41 +00:00
tmp1 = tmp2;
for (cnt = 8; cnt > 0; cnt--) {
2003-03-05 21:50:41 +00:00
if (tmp1 % 2) {
tmp1 /= 2;
tmp1 ^= 0x0a001;
2003-03-05 21:50:41 +00:00
} else
tmp1 /= 2;
}
2003-03-05 21:50:41 +00:00
crc_table[tmp2] = tmp1;
}
}
//calculate 16 bit crc of a block of memory
uint16 crc_block(uint8 *block, uint32 size)
{
uint16 crc=0;
uint8 *crcTable8 = (uint8 *)crc_table; //make a uint8* to crc_table
uint8 tmp;
uint32 i;
2003-03-05 21:50:41 +00:00
for (i = 0; i < size; i++) {
tmp = *block++;
crc ^= tmp;
2003-03-05 21:50:41 +00:00
tmp = (uint8)((crc>>8)&0x00FF);
crc &= 0x00FF;
crc = crc << 1;
2003-03-05 21:50:41 +00:00
crc = *(uint16 *)&crcTable8[crc];
crc ^= tmp;
}
return crc;
}
uint16 input_bits(uint8 amount)
{
uint16 newBitBuffh = bit_buffh;
uint16 newBitBuffl = bit_buffl;
2003-03-05 21:50:41 +00:00
int16 newBitCount = bit_count;
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;
esiptr += 2;
newBitBuffh = READ_LE_UINT16(esiptr);
XCHG(newBitCount, amount);
amount -= newBitCount;
newBitCount = 16 - amount;
}
remBits = ROR((uint16)(((1 << amount) - 1) & newBitBuffh), amount);
bit_buffh = newBitBuffh >> amount;
bit_buffl = (newBitBuffl >> amount) | remBits;
bit_count = (uint8)newBitCount;
return returnVal;
}
void make_huftable(uint16 *table)
{
uint16 bitLength, i, j;
uint16 numCodes = input_bits(5);
if (!numCodes)
return;
uint8 huffLength[16];
for (i = 0; i < numCodes; i++)
huffLength[i] = (uint8)(input_bits(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;
2003-03-05 19:23:35 +00:00
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 input_value(uint16 *table)
{
uint16 valOne, valTwo, value = bit_buffl;
do {
valTwo = (*table++) & value;
valOne = *table++;
} while (valOne != valTwo);
value = *(table+0x1e);
input_bits((uint8)((value>>8)&0x00FF));
value &= 0x00FF;
if (value >= 2) {
value--;
valOne = input_bits((uint8)value&0x00FF);
valOne |= (1 << value);
value = valOne;
}
return value;
}
2003-03-05 21:50:41 +00:00
int UnpackM1(void *input, void *output, uint16 key)
{
2003-03-05 21:50:41 +00:00
uint8 *inputHigh, *outputLow, *outputHigh;
uint8 *inputptr = (uint8 *)input;
2003-03-05 21:50:41 +00:00
if (CHECKSUMS)
init_crc();
2003-03-05 21:50:41 +00:00
//Check for "RNC "
if (READ_BE_UINT32(inputptr) != 0x524e4301)
return NOT_PACKED;
2003-03-05 21:50:41 +00:00
inputptr += 4;
2003-03-05 21:50:41 +00:00
// read unpacked/packed file length
unpack_len = READ_BE_UINT32(inputptr); inputptr += 4;
pack_len = READ_BE_UINT32(inputptr); inputptr += 4;
2003-03-05 21:50:41 +00:00
blocks = *(inputptr+5);
2003-03-05 21:50:41 +00:00
if (CHECKSUMS) {
//read CRC's
crc_u = READ_BE_UINT16(inputptr); inputptr += 2;
crc_p = READ_BE_UINT16(inputptr); inputptr += 2;
inputptr = (inputptr+HEADER_LEN-16);
2003-03-05 21:50:41 +00:00
if (crc_block(inputptr, pack_len) != crc_p)
return PACKED_CRC;
2003-03-05 21:50:41 +00:00
inputptr = (((uint8 *)input)+HEADER_LEN);
esiptr = inputptr;
}
2003-03-05 21:50:41 +00:00
// inputLow = *input
inputHigh = ((uint8 *)input) + pack_len + HEADER_LEN;;
outputLow = (uint8 *)output;
2003-03-05 21:50:41 +00:00
outputHigh = *(((uint8 *)input)+16) + unpack_len + outputLow;
2003-03-05 21:50:41 +00:00
if (! ((inputHigh <= outputLow) || (outputHigh <= inputHigh)) ) {
esiptr = inputHigh;
2003-03-05 21:50:41 +00:00
ediptr = outputHigh;
memcpy((ediptr-pack_len), (esiptr-pack_len), pack_len);
esiptr = (ediptr-pack_len);
}
//unpack3:
2003-03-05 21:50:41 +00:00
ediptr = (uint8 *)output;
bit_count = 0;
2003-03-05 21:50:41 +00:00
bit_buffl = READ_LE_UINT16(esiptr);
input_bits(2);
2003-03-05 21:50:41 +00:00
do {
make_huftable(raw_table);
make_huftable(pos_table);
make_huftable(len_table);
counts = input_bits(16);
for (;;) {
uint32 input_bits = input_value(raw_table);
if (input_bits) {
memcpy(ediptr, esiptr, input_bits); //memcpy is allowed here
ediptr += input_bits;
esiptr += input_bits;
uint16 b = READ_LE_UINT16(esiptr);
uint16 a = ROL(b, bit_count);
uint16 d = ((1 << bit_count) - 1);
bit_buffl &= d;
d &= a;
a = READ_LE_UINT16((esiptr+2));
b = (b << bit_count);
a = (a << bit_count);
a |= d;
bit_buffl |= b;
bit_buffh = a;
}
2003-03-05 21:50:41 +00:00
if (--counts) {
uint32 input_offset = input_value(pos_table) + 1;
uint32 input_length = input_value(len_table) + MIN_LENGTH;
2003-03-05 21:50:41 +00:00
inputHigh = esiptr;
esiptr = (ediptr-input_offset);
2003-03-05 21:50:41 +00:00
//Don't use memcpy here! because input and output overlap
while (input_length--)
*ediptr++ = *esiptr++;
2003-03-05 21:50:41 +00:00
esiptr = inputHigh;
} else
break;
2003-03-05 21:50:41 +00:00
}
} while (--blocks);
if (CHECKSUMS) {
if (crc_block((uint8 *)output, unpack_len) != crc_u)
return UNPACKED_CRC;
}
2003-03-05 21:50:41 +00:00
// all is done..return the amount of unpacked bytes
return unpack_len;
}
2003-03-05 21:50:41 +00:00