aboutsummaryrefslogtreecommitdiff
path: root/sky/rnc_deco.cpp
diff options
context:
space:
mode:
authorMax Horn2003-03-05 19:04:34 +0000
committerMax Horn2003-03-05 19:04:34 +0000
commit5ffeedb1cbea471b3d902da96767ffad168023c5 (patch)
tree5ba28837ca5499b4ae6edcab35d5522c63612a1b /sky/rnc_deco.cpp
parentf02506f9931c3b4d7eb97887e16228623461011b (diff)
downloadscummvm-rg350-5ffeedb1cbea471b3d902da96767ffad168023c5.tar.gz
scummvm-rg350-5ffeedb1cbea471b3d902da96767ffad168023c5.tar.bz2
scummvm-rg350-5ffeedb1cbea471b3d902da96767ffad168023c5.zip
Patch #697312: Beneath a Steel Sky interim/initial support patch
svn-id: r6691
Diffstat (limited to 'sky/rnc_deco.cpp')
-rw-r--r--sky/rnc_deco.cpp345
1 files changed, 345 insertions, 0 deletions
diff --git a/sky/rnc_deco.cpp b/sky/rnc_deco.cpp
new file mode 100644
index 0000000000..975f3736da
--- /dev/null
+++ b/sky/rnc_deco.cpp
@@ -0,0 +1,345 @@
+/* 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
+#define CHECKSUMS 1
+#define PROTECTED 0
+
+//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
+
+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++) {
+ tmp1 = tmp2;
+ for (cnt = 8; cnt > 0; cnt--) {
+ if (tmp1 % 2) {
+ tmp1 /= 2;
+ tmp1 ^= 0x0a001;
+ }
+ else
+ tmp1 /= 2;
+ }
+ 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;
+
+ for (i = 0; i < size; i++) {
+ tmp = *block++;
+ crc ^= tmp;
+ tmp = (uint8)((crc>>8)&0x00FF);
+ crc &= 0x00FF;
+ crc = crc << 1;
+ crc = *(uint16 *)&crcTable8[crc];
+ crc ^= tmp;
+ }
+
+ return crc;
+}
+
+uint16 input_bits(uint8 amount)
+{
+ uint16 newBitBuffh = bit_buffh;
+ uint16 newBitBuffl = bit_buffl;
+ 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 = newBitCount;
+
+ return returnVal;
+
+}
+
+// RCL/RCR functions..operate on 16 bit ints only
+uint16 rcl(uint16 reg, uint16 *cflag)
+{
+ uint16 lsb = *cflag;
+ *cflag = reg >> 15;
+ return (reg << 1) | lsb;
+}
+
+uint16 rcr(uint16 reg, uint16 *cflag)
+{
+ uint16 msb = *cflag << 15;
+ *cflag = reg & 1;
+ return (reg >> 1) | msb;
+}
+
+
+
+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;
+ uint16 carry = 0;
+
+ for (j = 0; j < bitLength; j++) {
+ b = rcr(b, &carry);
+ a = rcl(a, &carry);
+
+ }
+ *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;
+}
+
+int UnpackM1(void *input, void *output, uint16 key)
+{
+ uint8 cl;
+ uint8 *inputHigh, *outputLow;
+ uint32 eax, ebx, ecx, edx;
+ uint8 *inputptr = (uint8 *)input;
+
+ if (CHECKSUMS)
+ init_crc();
+
+ //Check for "RNC "
+ if (READ_BE_UINT32(inputptr) != 0x524e4301)
+ return NOT_PACKED;
+
+ inputptr += 4;
+
+ // read unpacked/packed file length
+ unpack_len = READ_BE_UINT32(inputptr); inputptr += 4;
+ pack_len = READ_BE_UINT32(inputptr); inputptr += 4;
+
+ blocks = *(inputptr+5);
+
+ 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);
+
+ if (crc_block(inputptr, pack_len) != crc_p)
+ return PACKED_CRC;
+
+ inputptr = (((uint8 *)input)+HEADER_LEN);
+ esiptr = inputptr;
+
+ }
+
+ inputHigh = ((uint8 *)input) + pack_len + HEADER_LEN;;
+ outputLow = (uint8 *)output;
+
+ eax = *(((uint8 *)input)+16) + unpack_len;
+
+ if (! ((inputHigh <= outputLow ) || ((outputLow+eax) <= inputHigh )) ) {
+ esiptr = inputHigh;
+ ediptr = (outputLow+eax);
+ memcpy((ediptr-pack_len), (esiptr-pack_len), pack_len);
+ esiptr = (ediptr-pack_len);
+ }
+
+
+ //unpack3:
+ ediptr = (uint8 *)output;
+ bit_count = 0;
+
+ bit_buffl = READ_LE_UINT16(esiptr);
+ /*eax =*/ input_bits(2);
+
+
+ //Argh! Labels!!
+ unpack4:
+ make_huftable(raw_table);
+ make_huftable(pos_table);
+ make_huftable(len_table);
+
+ counts = input_bits(16);
+
+ goto unpack6;
+
+ unpack5:
+
+ eax = input_value(pos_table) + 1; //input offset
+ ecx = input_value(len_table) + MIN_LENGTH; //input length
+
+ inputHigh = esiptr;
+ esiptr = (ediptr-eax);
+
+ //Don't use memcpy here! because input and output overlap
+ while (ecx) {
+ *ediptr++ = *esiptr++; ecx--;
+ }
+
+ esiptr = inputHigh;
+
+ unpack6:
+
+ ecx = input_value(raw_table);
+
+ if (ecx == 0)
+ goto unpack7;
+
+ memcpy(ediptr, esiptr, ecx); //memcpy is allowed here
+ ediptr += ecx;
+ esiptr += ecx;
+ cl = bit_count;
+ eax = READ_LE_UINT16(esiptr);
+ ebx = eax;
+ eax = ROL((uint16)eax, cl);
+ edx = ((1 << cl) - 1) & 0x0000FFFF; //make sure we only get 16bits
+ bit_buffl &= (uint16)edx;
+ edx &= eax;
+
+ eax = READ_LE_UINT16((esiptr+2));
+ ebx = (ebx << cl)&0x0000FFFF;
+ eax = (eax << cl)&0x0000FFFF;
+ eax |= edx;
+ bit_buffl |= (uint16)ebx;
+ bit_buffh = (uint16)eax;
+
+ unpack7:
+
+ counts--;
+ if (counts)
+ goto unpack5;
+
+ blocks--;
+ if (blocks)
+ goto unpack4;
+
+ if (CHECKSUMS) {
+ if (crc_block((uint8 *)output, unpack_len) != crc_u)
+ return UNPACKED_CRC;
+ }
+
+ // all is done..return the amount of unpacked bytes
+ return unpack_len;
+}