aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Frieger2009-03-10 21:44:03 +0000
committerGreg Frieger2009-03-10 21:44:03 +0000
commit0a38541cc50d0dc36172b337dc7eab4ae9ec5bb2 (patch)
tree6e27acf269199ed5501191b0d3e4e9ceff3bdb6e
parent24e6587b169cb28340398c357b09a7b9e10fb873 (diff)
downloadscummvm-rg350-0a38541cc50d0dc36172b337dc7eab4ae9ec5bb2.tar.gz
scummvm-rg350-0a38541cc50d0dc36172b337dc7eab4ae9ec5bb2.tar.bz2
scummvm-rg350-0a38541cc50d0dc36172b337dc7eab4ae9ec5bb2.zip
Resource decompression functions moved to scicore\decompressor.cpp and turned into classes.
svn-id: r39311
-rw-r--r--dists/msvc8/sci.vcproj14
-rw-r--r--engines/sci/module.mk5
-rw-r--r--engines/sci/scicore/decompress0.cpp336
-rw-r--r--engines/sci/scicore/decompress01.cpp601
-rw-r--r--engines/sci/scicore/decompress1.cpp382
-rw-r--r--engines/sci/scicore/decompress11.cpp146
-rw-r--r--engines/sci/scicore/decompressor.cpp877
-rw-r--r--engines/sci/scicore/decompressor.h179
-rw-r--r--engines/sci/scicore/resource.cpp221
-rw-r--r--engines/sci/scicore/resource.h69
10 files changed, 1253 insertions, 1577 deletions
diff --git a/dists/msvc8/sci.vcproj b/dists/msvc8/sci.vcproj
index 9806b55b8f..96de5fa93f 100644
--- a/dists/msvc8/sci.vcproj
+++ b/dists/msvc8/sci.vcproj
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
- Version="8,00"
+ Version="8.00"
Name="sci"
ProjectGUID="{53F17B2B-0412-4EC3-A999-ED0537BB5223}"
RootNamespace="sci"
@@ -486,19 +486,11 @@
Name="scicore"
>
<File
- RelativePath="..\..\engines\sci\scicore\decompress0.cpp"
+ RelativePath="..\..\engines\sci\scicore\decompressor.cpp"
>
</File>
<File
- RelativePath="..\..\engines\sci\scicore\decompress01.cpp"
- >
- </File>
- <File
- RelativePath="..\..\engines\sci\scicore\decompress1.cpp"
- >
- </File>
- <File
- RelativePath="..\..\engines\sci\scicore\decompress11.cpp"
+ RelativePath="..\..\engines\sci\scicore\decompressor.h"
>
</File>
<File
diff --git a/engines/sci/module.mk b/engines/sci/module.mk
index 62380f015b..35457a382b 100644
--- a/engines/sci/module.mk
+++ b/engines/sci/module.mk
@@ -55,10 +55,7 @@ MODULE_OBJS = \
gfx/resource/res_pic.o \
gfx/resource/res_view0.o \
gfx/resource/res_view1.o \
- scicore/decompress0.o \
- scicore/decompress01.o \
- scicore/decompress1.o \
- scicore/decompress11.o \
+ scicore/decompressor.o \
scicore/resource.o \
scicore/sciconsole.o \
scicore/versions.o \
diff --git a/engines/sci/scicore/decompress0.cpp b/engines/sci/scicore/decompress0.cpp
deleted file mode 100644
index fda253b31e..0000000000
--- a/engines/sci/scicore/decompress0.cpp
+++ /dev/null
@@ -1,336 +0,0 @@
-/* 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$
- *
- */
-
-/* Reads data from a resource file and stores the result in memory.
-** This is for SCI version 0 style compression.
-*/
-
-#include "common/stream.h"
-#include "common/endian.h"
-
-#include "sci/sci_memory.h"
-#include "sci/scicore/resource.h"
-
-namespace Sci {
-
-//#define _SCI_DECOMPRESS_DEBUG
-
-// 9-12 bit LZW encoding
-int unpackLZW(uint8 *dest, uint8 *src, int length, int complength) {
- // Doesn't do length checking yet
- /* Theory: Considering the input as a bit stream, we get a series of
- ** 9 bit elements in the beginning. Every one of them is a 'token'
- ** and either represents a literal (if < 0x100), or a link to a previous
- ** token (tokens start at 0x102, because 0x101 is the end-of-stream
- ** indicator and 0x100 is used to reset the bit stream decoder).
- ** If it's a link, the indicated token and the character following it are
- ** placed into the output stream. Note that the 'indicated token' may
- ** very well consist of a link-token-plus-literal construct again, so
- ** it's possible to represent strings longer than 2 recursively.
- ** If the maximum number of tokens has been reached, the bit length is
- ** increased by one, up to a maximum of 12 bits.
- ** This implementation remembers the position each token was print to in
- ** the output array, and the length of this token. This method should
- ** be faster than the recursive approach.
- */
-
- uint16 bitlen = 9; // no. of bits to read (max. 12)
- uint16 bitmask = 0x01ff;
- uint16 bitctr = 0; // current bit position
- uint16 bytectr = 0; // current byte position
- uint16 token; // The last received value
- uint16 maxtoken = 0x200; // The biggest token
-
- uint16 tokenlist[4096]; // pointers to dest[]
- uint16 tokenlengthlist[4096]; // char length of each token
- uint16 tokenctr = 0x102; // no. of registered tokens (starts here)
-
- uint16 tokenlastlength = 0;
-
- uint16 destctr = 0;
-
- while (bytectr < complength) {
-
- uint32 tokenmaker = src[bytectr++] >> bitctr;
- if (bytectr < complength)
- tokenmaker |= (src[bytectr] << (8 - bitctr));
- if (bytectr + 1 < complength)
- tokenmaker |= (src[bytectr+1] << (16 - bitctr));
-
- token = tokenmaker & bitmask;
-
- bitctr += bitlen - 8;
-
- while (bitctr >= 8) {
- bitctr -= 8;
- bytectr++;
- }
-
- if (token == 0x101)
- return 0; // terminator
- if (token == 0x100) { // reset command
- maxtoken = 0x200;
- bitlen = 9;
- bitmask = 0x01ff;
- tokenctr = 0x0102;
- } else {
- {
- int i;
-
- if (token > 0xff) {
- if (token >= tokenctr) {
-#ifdef _SCI_DECOMPRESS_DEBUG
- warning("unpackLZW: Bad token %x", token);
-#endif
- // Well this is really bad
- // May be it should throw something like SCI_ERROR_DECOMPRESSION_INSANE
- } else {
- tokenlastlength = tokenlengthlist[token] + 1;
- if (destctr + tokenlastlength > length) {
-#ifdef _SCI_DECOMPRESS_DEBUG
- // For me this seems a normal situation, It's necessary to handle it
- warning("unpackLZW: Trying to write beyond the end of array(len=%d, destctr=%d, tok_len=%d)",
- length, destctr, tokenlastlength);
-#endif
- i = 0;
- for (; destctr < length; destctr++) {
- dest[destctr++] = dest [tokenlist[token] + i];
- i++;
- }
- } else
- for (i = 0; i < tokenlastlength; i++) {
- dest[destctr++] = dest[tokenlist[token] + i];
- }
- }
- } else {
- tokenlastlength = 1;
- if (destctr >= length) {
-#ifdef _SCI_DECOMPRESS_DEBUG
- warning("unpackLZW: Try to write single byte beyond end of array");
-#endif
- } else
- dest[destctr++] = (byte)token;
- }
-
- }
-
- if (tokenctr == maxtoken) {
- if (bitlen < 12) {
- bitlen++;
- bitmask <<= 1;
- bitmask |= 1;
- maxtoken <<= 1;
- } else
- continue; // no further tokens allowed
- }
-
- tokenlist[tokenctr] = destctr - tokenlastlength;
- tokenlengthlist[tokenctr++] = tokenlastlength;
- }
- }
-
- return 0;
-}
-
-// Huffman-style token encoding
-/***************************************************************************/
-/* This code was taken from Carl Muckenhoupt's sde.c, with some minor */
-/* modifications. */
-/***************************************************************************/
-
-// unpackHuffman helper function
-int16 getc2(uint8 *node, uint8 *src, uint16 *bytectr, uint16 *bitctr, int complength) {
- uint16 next;
-
- while (node[1] != 0) {
- int16 value = (src[*bytectr] << (*bitctr));
- (*bitctr)++;
- if (*bitctr == 8) {
- (*bitctr) = 0;
- (*bytectr)++;
- }
-
- if (value & 0x80) {
- next = node[1] & 0x0f; // low 4 bits
- if (next == 0) {
- uint16 result = (src[*bytectr] << (*bitctr));
-
- if (++(*bytectr) > complength)
- return -1;
- else if (*bytectr < complength)
- result |= src[*bytectr] >> (8 - (*bitctr));
-
- result &= 0x0ff;
- return (result | 0x100);
- }
- } else {
- next = node[1] >> 4; // high 4 bits
- }
- node += next << 1;
- }
-
- return (int16)READ_LE_UINT16(node);
-}
-
-// Huffman token decryptor
-int unpackHuffman(uint8* dest, uint8* src, int length, int complength) {
- // no complength checking atm */
- uint8 numnodes, terminator;
- uint8 *nodes;
- int16 c;
- uint16 bitctr = 0, bytectr;
-
- numnodes = src[0];
- terminator = src[1];
- bytectr = 2 + (numnodes << 1);
- nodes = src + 2;
-
- while (((c = getc2(nodes, src, &bytectr, &bitctr, complength)) != (0x0100 | terminator)) && (c >= 0)) {
- if (length-- == 0)
- return SCI_ERROR_DECOMPRESSION_OVERFLOW;
-
- *dest = (uint8)c;
- dest++;
- }
-
- return (c == -1) ? SCI_ERROR_DECOMPRESSION_OVERFLOW : 0;
-
-}
-
-// Carl Muckenhoupt's decompression code ends here
-
-int sci0_get_compression_method(Common::ReadStream &stream) {
- uint16 compressionMethod;
-
- stream.readUint16LE();
- stream.readUint16LE();
- stream.readUint16LE();
- compressionMethod = stream.readUint16LE();
- if (stream.err())
- return SCI_ERROR_IO_ERROR;
-
- return compressionMethod;
-}
-
-int decompress0(Resource *result, Common::ReadStream &stream, int sci_version) {
- uint16 compressedLength;
- uint16 compressionMethod;
- uint8 *buffer;
- uint8 type;
-
- result->id = stream.readUint16LE();
- if (stream.err())
- return SCI_ERROR_IO_ERROR;
-
- result->number = result->id & 0x07ff;
- type = result->id >> 11;
-
- result->type = (ResourceType)type;
-
- if ((result->number > sci_max_resource_nr[sci_version]) || (type > kResourceTypeInvalid))
- return SCI_ERROR_DECOMPRESSION_INSANE;
-
- compressedLength = stream.readUint16LE();
- result->size = stream.readUint16LE();
- compressionMethod = stream.readUint16LE();
- if (stream.err())
- return SCI_ERROR_IO_ERROR;
-
- if (result->size > SCI_MAX_RESOURCE_SIZE)
- return SCI_ERROR_RESOURCE_TOO_BIG;
-
- if (compressedLength > 4)
- compressedLength -= 4;
- else { // Object has size zero (e.g. view.000 in sq3) (does this really exist?)
- result->data = 0;
- result->status = SCI_STATUS_NOMALLOC;
- return SCI_ERROR_EMPTY_OBJECT;
- }
-
- buffer = (uint8 *)sci_malloc(compressedLength);
- result->data = (unsigned char *)sci_malloc(result->size);
-
- if (stream.read(buffer, compressedLength) != compressedLength) {
- free(result->data);
- free(buffer);
- result->data = 0;
- return SCI_ERROR_IO_ERROR;
- };
-
-
-#ifdef _SCI_DECOMPRESS_DEBUG
- debug("Resource %s.%03hi encrypted with method %hi at %.2f%% ratio",
- getResourceTypeName(result->type), result->number, compressionMethod,
- (result->size == 0) ? -1.0 :
- (100.0 * compressedLength / result->size));
- debug(" compressedLength = 0x%hx, actualLength=0x%hx",
- compressedLength, result->size);
-#endif
-
- bool overflow = false;
-
- switch (compressionMethod) {
- case 0: // no compression
- if (result->size != compressedLength)
- overflow = true;
- else
- memcpy(result->data, buffer, compressedLength);
- break;
-
- case 1: // LZW compression
- if (unpackLZW(result->data, buffer, result->size, compressedLength))
- overflow = true;
- break;
-
- case 2: // Some sort of Huffman encoding
- if (unpackHuffman(result->data, buffer, result->size, compressedLength))
- overflow = true;
- break;
-
- default:
- warning("Resource %s.%03hi: Compression method %hi not supported",
- getResourceTypeName(result->type), result->number,
- compressionMethod);
- free(result->data);
- result->data = 0; // So that we know that it didn't work
- result->status = SCI_STATUS_NOMALLOC;
- free(buffer);
- return SCI_ERROR_UNKNOWN_COMPRESSION;
- }
-
- if (overflow) {
- free(result->data);
- result->data = 0; // So that we know that it didn't work
- result->status = SCI_STATUS_NOMALLOC;
- free(buffer);
- return SCI_ERROR_DECOMPRESSION_OVERFLOW;
- }
-
- result->status = SCI_STATUS_ALLOCATED;
- free(buffer);
- return 0;
-}
-
-} // End of namespace Sci
diff --git a/engines/sci/scicore/decompress01.cpp b/engines/sci/scicore/decompress01.cpp
deleted file mode 100644
index 9cdb02f9cb..0000000000
--- a/engines/sci/scicore/decompress01.cpp
+++ /dev/null
@@ -1,601 +0,0 @@
-/* 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$
- *
- */
-
-// Reads data from a resource file and stores the result in memory
-
-#include "common/stream.h"
-#include "common/endian.h"
-
-#include "sci/sci_memory.h"
-#include "sci/scicore/resource.h"
-
-namespace Sci {
-
-// The following code was originally created by Carl Muckenhoupt for his
-// SCI decoder. It has been ported to the FreeSCI environment by Sergey Lapin.
-
-// TODO: Clean up, re-organize, improve speed-wise */
-
-struct tokenlist {
- uint8 data;
- int16 next;
-} tokens[0x1004];
-
-static int8 stak[0x1014] = {0};
-static int8 lastchar = 0;
-static int16 stakptr = 0;
-static uint16 s_numbits, s_bitstring, lastbits, decryptstart;
-static int16 curtoken, endtoken;
-
-uint32 gbits(int numbits, uint8 * data, int dlen);
-
-int decrypt3(uint8 *dest, uint8 *src, int length, int complength) {
- // Init
- int i;
-
- lastchar = lastbits = s_bitstring = stakptr = 0;
- s_numbits = 9;
- curtoken = 0x102;
- endtoken = 0x1ff;
- decryptstart = 0;
- gbits(0, 0, 0);
-
- for (i = 0;i < 0x1004;i++) {
- tokens[i].next = 0;
- tokens[i].data = 0;
- }
-
- // Start decrypting
-
- static int16 token;
- while (length != 0) {
- switch (decryptstart) {
- case 0:
- case 1:
- s_bitstring = gbits(s_numbits, src, complength);
- if (s_bitstring == 0x101) { // found end-of-data signal
- decryptstart = 4;
- return 0;
- }
- if (decryptstart == 0) { // first char
- decryptstart = 1;
- lastbits = s_bitstring;
- *(dest++) = lastchar = (s_bitstring & 0xff);
- if (--length != 0)
- continue;
- return 0;
- }
- if (s_bitstring == 0x100) { // start-over signal
- s_numbits = 9;
- endtoken = 0x1ff;
- curtoken = 0x102;
- decryptstart = 0;
- continue;
- }
- token = s_bitstring;
- if (token >= curtoken) { // index past current point
- token = lastbits;
- stak[stakptr++] = lastchar;
- }
- while ((token > 0xff) && (token < 0x1004)) { // follow links back in data
- stak[stakptr++] = tokens[token].data;
- token = tokens[token].next;
- }
- lastchar = stak[stakptr++] = token & 0xff;
- case 2:
- while (stakptr > 0) { // put stack in buffer
- *(dest++) = stak[--stakptr];
- length--;
- if (length == 0) {
- decryptstart = 2;
- return 0;
- }
- }
- decryptstart = 1;
- if (curtoken <= endtoken) { // put token into record
- tokens[curtoken].data = lastchar;
- tokens[curtoken].next = lastbits;
- curtoken++;
- if (curtoken == endtoken && s_numbits != 12) {
- s_numbits++;
- endtoken <<= 1;
- endtoken++;
- }
- }
- lastbits = s_bitstring;
- continue; // When are "break" and "continue" synonymous?
- case 4:
- return 0;
- }
- }
-
- return 0;
-}
-
-uint32 gbits(int numbits, uint8 * data, int dlen) {
- int place; // indicates location within byte
- uint32 bitstring;
- static uint32 whichbit = 0;
- int i;
-
- if (numbits == 0) {
- whichbit = 0;
- return 0;
- }
-
- place = whichbit >> 3;
- bitstring = 0;
- for (i = (numbits >> 3) + 1;i >= 0;i--) {
- if (i + place < dlen)
- bitstring |= data[place+i] << (8 * (2 - i));
- }
- //bitstring = data[place + 2] | (long)(data[place + 1]) << 8 | (long)(data[place]) << 16;
- bitstring >>= 24 - (whichbit & 7) - numbits;
- bitstring &= (0xffffffff >> (32 - numbits));
- // Okay, so this could be made faster with a table lookup.
- // It doesn't matter. It's fast enough as it is.
- whichbit += numbits;
-
- return bitstring;
-}
-
-// Carl Muckenhoupt's code ends here
-
-enum {
- PIC_OP_SET_COLOR = 0xf0,
- PIC_OP_DISABLE_VISUAL = 0xf1,
- PIC_OP_SET_PRIORITY = 0xf2,
- PIC_OP_DISABLE_PRIORITY = 0xf3,
- PIC_OP_SHORT_PATTERNS = 0xf4,
- PIC_OP_MEDIUM_LINES = 0xf5,
- PIC_OP_LONG_LINES = 0xf6,
- PIC_OP_SHORT_LINES = 0xf7,
- PIC_OP_FILL = 0xf8,
- PIC_OP_SET_PATTERN = 0xf9,
- PIC_OP_ABSOLUTE_PATTERN = 0xfa,
- PIC_OP_SET_CONTROL = 0xfb,
- PIC_OP_DISABLE_CONTROL = 0xfc,
- PIC_OP_MEDIUM_PATTERNS = 0xfd,
- PIC_OP_OPX = 0xfe,
- PIC_OP_TERMINATE = 0xff
-};
-
-enum {
- PIC_OPX_SET_PALETTE_ENTRIES = 0,
- PIC_OPX_EMBEDDED_VIEW = 1,
- PIC_OPX_SET_PALETTE = 2,
- PIC_OPX_PRIORITY_TABLE_EQDIST = 3,
- PIC_OPX_PRIORITY_TABLE_EXPLICIT = 4
-};
-
-#define PAL_SIZE 1284
-#define CEL_HEADER_SIZE 7
-#define EXTRA_MAGIC_SIZE 15
-
-static void decode_rle(byte **rledata, byte **pixeldata, byte *outbuffer, int size) {
- int pos = 0;
- char nextbyte;
- byte *rd = *rledata;
- byte *ob = outbuffer;
- byte *pd = *pixeldata;
-
- while (pos < size) {
- nextbyte = *(rd++);
- *(ob++) = nextbyte;
- pos ++;
- switch (nextbyte&0xC0) {
- case 0x40 :
- case 0x00 :
- memcpy(ob, pd, nextbyte);
- pd += nextbyte;
- ob += nextbyte;
- pos += nextbyte;
- break;
- case 0xC0 :
- break;
- case 0x80 :
- nextbyte = *(pd++);
- *(ob++) = nextbyte;
- pos ++;
- break;
- }
- }
-
- *rledata = rd;
- *pixeldata = pd;
-}
-
-/*
- * Does the same this as above, only to determine the length of the compressed
- * source data.
- *
- * Yes, this is inefficient.
- */
-static int rle_size(byte *rledata, int dsize) {
- int pos = 0;
- char nextbyte;
- int size = 0;
-
- while (pos < dsize) {
- nextbyte = *(rledata++);
- pos ++;
- size ++;
-
- switch (nextbyte&0xC0) {
- case 0x40 :
- case 0x00 :
- pos += nextbyte;
- break;
- case 0xC0 :
- break;
- case 0x80 :
- pos ++;
- break;
- }
- }
-
- return size;
-}
-
-byte *pic_reorder(byte *inbuffer, int dsize) {
- byte *reorderBuffer;
- int view_size;
- int view_start;
- int cdata_size;
- int i;
- byte *seeker = inbuffer;
- byte *writer;
- char viewdata[CEL_HEADER_SIZE];
- byte *cdata, *cdata_start;
-
- writer = reorderBuffer = (byte *) malloc(dsize);
-
- *(writer++) = PIC_OP_OPX;
- *(writer++) = PIC_OPX_SET_PALETTE;
-
- for (i = 0;i < 256;i++) // Palette translation map
- *(writer++) = i;
-
- WRITE_LE_UINT16(writer, 0); // Palette stamp
- writer += 2;
- WRITE_LE_UINT16(writer, 0);
- writer += 2;
-
- view_size = READ_LE_UINT16(seeker);
- seeker += 2;
- view_start = READ_LE_UINT16(seeker);
- seeker += 2;
- cdata_size = READ_LE_UINT16(seeker);
- seeker += 2;
-
- memcpy(viewdata, seeker, sizeof(viewdata));
- seeker += sizeof(viewdata);
-
- memcpy(writer, seeker, 4 * 256); // Palette
- seeker += 4 * 256;
- writer += 4 * 256;
-
- if (view_start != PAL_SIZE + 2) { // +2 for the opcode
- memcpy(writer, seeker, view_start - PAL_SIZE - 2);
- seeker += view_start - PAL_SIZE - 2;
- writer += view_start - PAL_SIZE - 2;
- }
-
- if (dsize != view_start + EXTRA_MAGIC_SIZE + view_size) {
- memcpy(reorderBuffer + view_size + view_start + EXTRA_MAGIC_SIZE, seeker,
- dsize - view_size - view_start - EXTRA_MAGIC_SIZE);
- seeker += dsize - view_size - view_start - EXTRA_MAGIC_SIZE;
- }
-
- cdata_start = cdata = (byte *)malloc(cdata_size);
- memcpy(cdata, seeker, cdata_size);
- seeker += cdata_size;
-
- writer = reorderBuffer + view_start;
- *(writer++) = PIC_OP_OPX;
- *(writer++) = PIC_OPX_EMBEDDED_VIEW;
- *(writer++) = 0;
- *(writer++) = 0;
- *(writer++) = 0;
- WRITE_LE_UINT16(writer, view_size + 8);
- writer += 2;
-
- memcpy(writer, viewdata, sizeof(viewdata));
- writer += sizeof(viewdata);
-
- *(writer++) = 0;
-
- decode_rle(&seeker, &cdata, writer, view_size);
-
- free(cdata_start);
- free(inbuffer);
-
- return reorderBuffer;
-}
-
-#define VIEW_HEADER_COLORS_8BIT 0x80
-
-static void build_cel_headers(byte **seeker, byte **writer, int celindex, int *cc_lengths, int max) {
- int c, w;
-
- for (c = 0;c < max;c++) {
- w = READ_LE_UINT16(*seeker);
- WRITE_LE_UINT16(*writer, w);
- *seeker += 2;
- *writer += 2;
- w = READ_LE_UINT16(*seeker);
- WRITE_LE_UINT16(*writer, w);
- *seeker += 2;
- *writer += 2;
- w = READ_LE_UINT16(*seeker);
- WRITE_LE_UINT16(*writer, w);
- *seeker += 2;
- *writer += 2;
- w = *((*seeker)++);
- WRITE_LE_UINT16(*writer, w); // Zero extension
- *writer += 2;
-
- *writer += cc_lengths[celindex];
- celindex ++;
- }
-}
-
-byte *view_reorder(byte *inbuffer, int dsize) {
- byte *cellengths;
- int loopheaders;
- int lh_present;
- int lh_mask;
- int pal_offset;
- int cel_total;
- int unknown;
- byte *seeker = inbuffer;
- char celcounts[100];
- byte *outbuffer = (byte *)malloc(dsize);
- byte *writer = outbuffer;
- byte *lh_ptr;
- byte *rle_ptr, *pix_ptr;
- int l, lb, c, celindex, lh_last = -1;
- int chptr;
- int w;
- int *cc_lengths;
- byte **cc_pos;
-
- // Parse the main header
- cellengths = inbuffer + READ_LE_UINT16(seeker) + 2;
- seeker += 2;
- loopheaders = *(seeker++);
- lh_present = *(seeker++);
- lh_mask = READ_LE_UINT16(seeker);
- seeker += 2;
- unknown = READ_LE_UINT16(seeker);
- seeker += 2;
- pal_offset = READ_LE_UINT16(seeker);
- seeker += 2;
- cel_total = READ_LE_UINT16(seeker);
- seeker += 2;
-
- cc_pos = (byte **)malloc(sizeof(byte *) * cel_total);
- cc_lengths = (int *)malloc(sizeof(int) * cel_total);
-
- for (c = 0;c < cel_total;c++)
- cc_lengths[c] = READ_LE_UINT16(cellengths + 2 * c);
-
- *(writer++) = loopheaders;
- *(writer++) = VIEW_HEADER_COLORS_8BIT;
- WRITE_LE_UINT16(writer, lh_mask);
- writer += 2;
- WRITE_LE_UINT16(writer, unknown);
- writer += 2;
- WRITE_LE_UINT16(writer, pal_offset);
- writer += 2;
-
- lh_ptr = writer;
- writer += 2 * loopheaders; // Make room for the loop offset table
-
- pix_ptr = writer;
-
- memcpy(celcounts, seeker, lh_present);
- seeker += lh_present;
-
- lb = 1;
- celindex = 0;
-
- rle_ptr = pix_ptr = cellengths + (2 * cel_total);
- w = 0;
-
- for (l = 0;l < loopheaders;l++) {
- if (lh_mask & lb) { // The loop is _not_ present
- if (lh_last == -1) {
- warning("While reordering view: Loop not present, but can't re-use last loop");
- lh_last = 0;
- }
- WRITE_LE_UINT16(lh_ptr, lh_last);
- lh_ptr += 2;
- } else {
- lh_last = writer - outbuffer;
- WRITE_LE_UINT16(lh_ptr, lh_last);
- lh_ptr += 2;
- WRITE_LE_UINT16(writer, celcounts[w]);
- writer += 2;
- WRITE_LE_UINT16(writer, 0);
- writer += 2;
-
- // Now, build the cel offset table
- chptr = (writer - outbuffer) + (2 * celcounts[w]);
-
- for (c = 0; c < celcounts[w]; c++) {
- WRITE_LE_UINT16(writer, chptr);
- writer += 2;
- cc_pos[celindex + c] = outbuffer + chptr;
- chptr += 8 + READ_LE_UINT16(cellengths + 2 * (celindex + c));
- }
-
- build_cel_headers(&seeker, &writer, celindex, cc_lengths, celcounts[w]);
-
- celindex += celcounts[w];
- w++;
- }
-
- lb = lb << 1;
- }
-
- if (celindex < cel_total) {
- warning("View decompression generated too few (%d / %d) headers", celindex, cel_total);
- return NULL;
- }
-
- // Figure out where the pixel data begins.
- for (c = 0;c < cel_total;c++)
- pix_ptr += rle_size(pix_ptr, cc_lengths[c]);
-
- rle_ptr = cellengths + (2 * cel_total);
- for (c = 0;c < cel_total;c++)
- decode_rle(&rle_ptr, &pix_ptr, cc_pos[c] + 8, cc_lengths[c]);
-
- *(writer++) = 'P';
- *(writer++) = 'A';
- *(writer++) = 'L';
-
- for (c = 0;c < 256;c++)
- *(writer++) = c;
-
- seeker -= 4; // The missing four. Don't ask why.
- memcpy(writer, seeker, 4 * 256 + 4);
-
- free(cc_pos);
- free(cc_lengths);
- free(inbuffer);
-
- return outbuffer;
-}
-
-int decompress01(Resource *result, Common::ReadStream &stream, int sci_version) {
- uint16 compressedLength;
- uint16 compressionMethod;
- uint8 *buffer;
- uint8 type;
-
- result->id = stream.readUint16LE();
- if (stream.err())
- return SCI_ERROR_IO_ERROR;
-
- result->number = result->id & 0x07ff;
- type = result->id >> 11;
-
- result->type = (ResourceType)type;
-
- if ((result->number > sci_max_resource_nr[sci_version]) || (type > kResourceTypeInvalid))
- return SCI_ERROR_DECOMPRESSION_INSANE;
-
- compressedLength = stream.readUint16LE();
- result->size = stream.readUint16LE();
- compressionMethod = stream.readUint16LE();
- if (stream.err())
- return SCI_ERROR_IO_ERROR;
-
- if (result->size > SCI_MAX_RESOURCE_SIZE)
- return SCI_ERROR_RESOURCE_TOO_BIG;
-
- if (compressedLength > 4)
- compressedLength -= 4;
- else { // Object has size zero (e.g. view.000 in sq3) (does this really exist?)
- result->data = 0;
- result->status = SCI_STATUS_NOMALLOC;
- return SCI_ERROR_EMPTY_OBJECT;
- }
-
- buffer = (uint8 *)sci_malloc(compressedLength);
- result->data = (unsigned char *)sci_malloc(result->size);
-
- if (stream.read(buffer, compressedLength) != compressedLength) {
- free(result->data);
- free(buffer);
- result->data = 0;
- return SCI_ERROR_IO_ERROR;
- };
-
-
-#ifdef _SCI_DECOMPRESS_DEBUG
- debug("Resource %s.%03hi encrypted with method SCI01/%hi at %.2f%% ratio",
- sci_resource_types[result->type], result->number, compressionMethod,
- (result->size == 0) ? -1.0 :
- (100.0 * compressedLength / result->size));
- debug(" compressedLength = 0x%hx, actualLength=0x%hx",
- compressedLength, result->size);
-#endif
-
- bool overflow = false;
-
- switch (compressionMethod) {
- case 0: // no compression
- if (result->size != compressedLength)
- overflow = true;
- else
- memcpy(result->data, buffer, compressedLength);
- break;
-
- case 1: // Some huffman encoding
- if (unpackHuffman(result->data, buffer, result->size, compressedLength))
- overflow = true;
- break;
-
- case 2:
- case 3:
- case 4:
- if (decrypt3(result->data, buffer, result->size, compressedLength)) {
- overflow = true;
- } else {
- if (compressionMethod == 3)
- result->data = view_reorder(result->data, result->size);
- if (compressionMethod == 4)
- result->data = pic_reorder(result->data, result->size);
- }
- break;
-
- default:
- warning("Resource %s.%03hi: Compression method SCI1/%hi not supported",
- getResourceTypeName(result->type), result->number,
- compressionMethod);
- free(result->data);
- result->data = 0; // So that we know that it didn't work
- result->status = SCI_STATUS_NOMALLOC;
- free(buffer);
- return SCI_ERROR_UNKNOWN_COMPRESSION;
- }
-
- if (overflow) {
- free(result->data);
- result->data = 0; // So that we know that it didn't work
- result->status = SCI_STATUS_NOMALLOC;
- free(buffer);
- return SCI_ERROR_DECOMPRESSION_OVERFLOW;
- }
-
- result->status = SCI_STATUS_ALLOCATED;
- free(buffer);
- return 0;
-}
-
-} // End of namespace Sci
diff --git a/engines/sci/scicore/decompress1.cpp b/engines/sci/scicore/decompress1.cpp
deleted file mode 100644
index 06b7f05103..0000000000
--- a/engines/sci/scicore/decompress1.cpp
+++ /dev/null
@@ -1,382 +0,0 @@
-/* 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$
- *
- */
-
-// Reads data from a resource file and stores the result in memory
-
-#include "common/debug.h"
-#include "common/stream.h"
-#include "common/util.h"
-
-#include "sci/sci.h"
-#include "sci/sci_memory.h"
-#include "sci/scicore/resource.h"
-
-namespace Sci {
-
-// DEFLATE-DCL
-// Refer to the FreeSCI docs for a full description.
-
-#define HUFFMAN_LEAF 0x40000000
-
-struct bit_read_struct {
- int length;
- int bitpos;
- int bytepos;
- byte *data;
-};
-
-#define BRANCH_SHIFT 12
-#define BRANCH_NODE(pos, left, right) ((left << BRANCH_SHIFT) | (right)),
-#define LEAF_NODE(pos, value) ((value) | HUFFMAN_LEAF),
-
-
-static int length_tree[] = {
-#include "treedef.1"
- 0 // We need something witout a comma at the end
-};
-
-static int distance_tree[] = {
-#include "treedef.2"
- 0 // We need something witout a comma at the end
-};
-
-static int ascii_tree[] = {
-#include "treedef.3"
- 0 // We need something witout a comma at the end
-};
-
-#define CALLC(x) { if ((x) == -SCI_ERROR_DECOMPRESSION_OVERFLOW) return -SCI_ERROR_DECOMPRESSION_OVERFLOW; }
-
-static inline int getbits_msb_first(struct bit_read_struct *inp, int bits) {
- int morebytes = (bits + inp->bitpos - 1) >> 3;
- int result = 0;
- int i;
-
- if (inp->bytepos + morebytes >= inp->length) {
- warning("read out-of-bounds with bytepos %d + morebytes %d >= length %d",
- inp->bytepos, morebytes, inp->length);
- return -SCI_ERROR_DECOMPRESSION_OVERFLOW;
- }
-
- for (i = 0; i <= morebytes; i++)
- result |= (inp->data[inp->bytepos + i]) << (i << 3);
-
- result >>= inp->bitpos;
- result &= ~(~0 << bits);
-
- inp->bitpos += bits - (morebytes << 3);
- inp->bytepos += morebytes;
-
- return result;
-}
-
-static inline int getbits(struct bit_read_struct *inp, int bits) {
- int morebytes = (bits + inp->bitpos - 1) >> 3;
- int result = 0;
- int i;
-
- if (inp->bytepos + morebytes >= inp->length) {
- warning("read out-of-bounds with bytepos %d + morebytes %d >= length %d",
- inp->bytepos, morebytes, inp->length);
- return -SCI_ERROR_DECOMPRESSION_OVERFLOW;
- }
-
- for (i = 0; i <= morebytes; i++)
- result |= (inp->data[inp->bytepos + i]) << (i << 3);
-
- result >>= inp->bitpos;
- result &= ~((~0) << bits);
-
- inp->bitpos += bits - (morebytes << 3);
- inp->bytepos += morebytes;
-
- debugC(kDebugLevelDclInflate, "(%d:%04x)", bits, result);
-
- return result;
-}
-
-static int huffman_lookup(struct bit_read_struct *inp, int *tree) {
- int pos = 0;
- int bit;
-
- while (!(tree[pos] & HUFFMAN_LEAF)) {
- CALLC(bit = getbits(inp, 1));
- debugC(kDebugLevelDclInflate, "[%d]:%d->", pos, bit);
- if (bit)
- pos = tree[pos] & ~(~0 << BRANCH_SHIFT);
- else
- pos = tree[pos] >> BRANCH_SHIFT;
- }
- debugC(kDebugLevelDclInflate, "=%02x\n", tree[pos] & 0xffff);
- return tree[pos] & 0xffff;
-}
-
-#define VALUE_M(i) ((i == 0)? 7 : (VALUE_M(i - 1) + 2**i));
-
-#define DCL_ASCII_MODE 1
-
-int unpackDCL(uint8* dest, uint8* src, int length, int complength) {
- int mode, length_param, value, val_length, val_distance;
- int write_pos = 0;
- struct bit_read_struct reader;
-
- reader.length = complength;
- reader.bitpos = 0;
- reader.bytepos = 0;
- reader.data = src;
-
- CALLC(mode = getbits(&reader, 8));
- CALLC(length_param = getbits(&reader, 8));
-
- if (mode == DCL_ASCII_MODE) {
- warning("DCL-INFLATE: Decompressing ASCII mode (untested)");
- } else if (mode) {
- warning("DCL-INFLATE: Error: Encountered mode %02x, expected 00 or 01\n", mode);
- return -1;
- }
-
- if (Common::isDebugChannelEnabled(kDebugLevelDclInflate)) {
- for (int i = 0; i < reader.length; i++) {
- debugC(kDebugLevelDclInflate, "%02x ", reader.data[i]);
- if (!((i + 1) & 0x1f))
- debugC(kDebugLevelDclInflate, "\n");
- }
-
-
- debugC(kDebugLevelDclInflate, "\n---\n");
- }
-
-
- if (length_param < 3 || length_param > 6)
- warning("Unexpected length_param value %d (expected in [3,6])\n", length_param);
-
- while (write_pos < length) {
- CALLC(value = getbits(&reader, 1));
-
- if (value) { // (length,distance) pair
- CALLC(value = huffman_lookup(&reader, length_tree));
-
- if (value < 8)
- val_length = value + 2;
- else {
- int length_bonus;
-
- val_length = (1 << (value - 7)) + 8;
- CALLC(length_bonus = getbits(&reader, value - 7));
- val_length += length_bonus;
- }
-
- debugC(kDebugLevelDclInflate, " | ");
-
- CALLC(value = huffman_lookup(&reader, distance_tree));
-
- if (val_length == 2) {
- val_distance = value << 2;
-
- CALLC(value = getbits(&reader, 2));
- val_distance |= value;
- } else {
- val_distance = value << length_param;
-
- CALLC(value = getbits(&reader, length_param));
- val_distance |= value;
- }
- ++val_distance;
-
- debugC(kDebugLevelDclInflate, "\nCOPY(%d from %d)\n", val_length, val_distance);
-
- if (val_length + write_pos > length) {
- warning("DCL-INFLATE Error: Write out of bounds while copying %d bytes", val_length);
- return SCI_ERROR_DECOMPRESSION_OVERFLOW;
- }
-
- if (write_pos < val_distance) {
- warning("DCL-INFLATE Error: Attempt to copy from before beginning of input stream");
- return SCI_ERROR_DECOMPRESSION_INSANE;
- }
-
- while (val_length) {
- int copy_length = (val_length > val_distance) ? val_distance : val_length;
-
- memcpy(dest + write_pos, dest + write_pos - val_distance, copy_length);
-
- if (Common::isDebugChannelEnabled(kDebugLevelDclInflate)) {
- for (int i = 0; i < copy_length; i++)
- debugC(kDebugLevelDclInflate, "\33[32;31m%02x\33[37;37m ", dest[write_pos + i]);
- debugC(kDebugLevelDclInflate, "\n");
- }
-
- val_length -= copy_length;
- val_distance += copy_length;
- write_pos += copy_length;
- }
-
- } else { // Copy byte verbatim
- if (mode == DCL_ASCII_MODE) {
- CALLC(value = huffman_lookup(&reader, ascii_tree));
- } else {
- CALLC(value = getbits(&reader, 8));
- }
-
- dest[write_pos++] = value;
-
- debugC(kDebugLevelDclInflate, "\33[32;31m%02x \33[37;37m", value);
- }
- }
-
- return 0;
-}
-
-int decrypt3(uint8* dest, uint8* src, int length, int complength);
-
-int decompress1(Resource *result, Common::ReadStream &stream, int sci_version) {
- uint16 compressedLength;
- uint16 compressionMethod;
- uint8 *buffer;
- uint16 type;
-
- if (sci_version == SCI_VERSION_1_EARLY) {
- result->id = stream.readUint16LE();
- if (stream.err())
- return SCI_ERROR_IO_ERROR;
-
- result->number = result->id & 0x07ff;
- type = result->id >> 11;
-
- result->type = (ResourceType)type;
- } else {
- result->id = stream.readByte();
- if (stream.err())
- return SCI_ERROR_IO_ERROR;
-
- type = result->id & 0x7f;
- result->number = stream.readUint16LE();
- if (stream.err())
- return SCI_ERROR_IO_ERROR;
-
- result->type = (ResourceType)type;
- }
-
- if ((result->number > sci_max_resource_nr[sci_version]) || (type > kResourceTypeInvalid))
- return SCI_ERROR_DECOMPRESSION_INSANE;
-
- compressedLength = stream.readUint16LE();
- result->size = stream.readUint16LE();
- compressionMethod = stream.readUint16LE();
- if (stream.err())
- return SCI_ERROR_IO_ERROR;
-
- if (result->size > SCI_MAX_RESOURCE_SIZE)
- return SCI_ERROR_RESOURCE_TOO_BIG;
-
- if (compressedLength > 4)
- compressedLength -= 4;
- else { // Object has size zero (e.g. view.000 in sq3) (does this really exist?)
- result->data = 0;
- result->status = SCI_STATUS_NOMALLOC;
- return SCI_ERROR_EMPTY_OBJECT;
- }
-
- buffer = (uint8 *)sci_malloc(compressedLength);
- result->data = (unsigned char *)sci_malloc(result->size);
-
- if (stream.read(buffer, compressedLength) != compressedLength) {
- free(result->data);
- free(buffer);
- result->data = 0;
- return SCI_ERROR_IO_ERROR;
- };
-
-
-#ifdef _SCI_DECOMPRESS_DEBUG
- debug("Resource %i.%s encrypted with method SCI1%c/%hi at %.2f%% ratio",
- result->number, sci_resource_type_suffixes[result->type],
- early ? 'e' : 'l',
- compressionMethod,
- (result->size == 0) ? -1.0 :
- (100.0 * compressedLength / result->size));
- debug(" compressedLength = 0x%hx, actualLength=0x%hx",
- compressedLength, result->size);
-#endif
-
- switch (compressionMethod) {
- case 0: // no compression
- if (result->size != compressedLength) {
- free(result->data);
- result->data = NULL;
- result->status = SCI_STATUS_NOMALLOC;
- free(buffer);
- return SCI_ERROR_DECOMPRESSION_OVERFLOW;
- }
- memcpy(result->data, buffer, compressedLength);
- result->status = SCI_STATUS_ALLOCATED;
- break;
-
- case 1: // LZW
- if (unpackHuffman(result->data, buffer, result->size, compressedLength)) {
- free(result->data);
- result->data = 0; // So that we know that it didn't work
- result->status = SCI_STATUS_NOMALLOC;
- free(buffer);
- return SCI_ERROR_DECOMPRESSION_OVERFLOW;
- }
- result->status = SCI_STATUS_ALLOCATED;
- break;
-
- case 2: // ???
- case 3:
- case 4:
- if (decrypt3(result->data, buffer, result->size, compressedLength)) {
- free(result->data);
- result->data = 0; // So that we know that it didn't work
- result->status = SCI_STATUS_NOMALLOC;
- free(buffer);
- return SCI_ERROR_DECOMPRESSION_OVERFLOW;
- }
-
- if (compressionMethod == 3)
- result->data = view_reorder(result->data, result->size);
- if (compressionMethod == 4)
- result->data = pic_reorder(result->data, result->size);
- result->status = SCI_STATUS_ALLOCATED;
- break;
-
- default:
- warning("Resource %s.%03hi: Compression method SCI1/%hi not supported",
- getResourceTypeName(result->type), result->number,
- compressionMethod);
- free(result->data);
- result->data = 0; // So that we know that it didn't work
- result->status = SCI_STATUS_NOMALLOC;
- free(buffer);
- return SCI_ERROR_UNKNOWN_COMPRESSION;
- }
-
- free(buffer);
-
- return 0;
-}
-
-} // End of namespace Sci
diff --git a/engines/sci/scicore/decompress11.cpp b/engines/sci/scicore/decompress11.cpp
deleted file mode 100644
index 114f965f64..0000000000
--- a/engines/sci/scicore/decompress11.cpp
+++ /dev/null
@@ -1,146 +0,0 @@
-/* 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$
- *
- */
-
-// Reads data from a resource file and stores the result in memory
-
-#include "common/stream.h"
-
-#include "sci/sci_memory.h"
-#include "sci/scicore/resource.h"
-
-namespace Sci {
-
-int unpackDCL(uint8* dest, uint8* src, int length, int complength);
-
-int decompress11(Resource *result, Common::ReadStream &stream, int sci_version) {
- uint16 compressedLength;
- uint16 compressionMethod;
- uint8 *buffer;
- uint16 type;
-
- result->id = stream.readByte();
- if (stream.err())
- return SCI_ERROR_IO_ERROR;
-
- type = result->id & 0x7f;
- if (type > kResourceTypeInvalid)
- return SCI_ERROR_DECOMPRESSION_INSANE;
-
- result->type = (ResourceType)type;
-
- result->number = stream.readUint16LE();
- compressedLength = stream.readUint16LE();
- result->size = stream.readUint16LE();
- compressionMethod = stream.readUint16LE();
- if (stream.err())
- return SCI_ERROR_IO_ERROR;
-
- if (result->size > SCI_MAX_RESOURCE_SIZE)
- return SCI_ERROR_RESOURCE_TOO_BIG;
-
- if (compressedLength > 0)
- compressedLength -= 0;
- else { // Object has size zero (e.g. view.000 in sq3) (does this really exist?)
- result->data = 0;
- result->status = SCI_STATUS_NOMALLOC;
- return SCI_ERROR_EMPTY_OBJECT;
- }
-
- buffer = (uint8 *)sci_malloc(compressedLength);
- result->data = (unsigned char *)sci_malloc(result->size);
-
- if (stream.read(buffer, compressedLength) != compressedLength) {
- free(result->data);
- free(buffer);
- result->data = 0;
- return SCI_ERROR_IO_ERROR;
- };
-
- if (!(compressedLength & 1)) { // Align
- stream.readByte();
- }
-
-#ifdef _SCI_DECOMPRESS_DEBUG
- debug("Resource %i.%s encrypted with method SCI1.1/%hi at %.2f%% ratio",
- result->number, getResourceTypeSuffix(result->type),
- compressionMethod,
- (result->size == 0) ? -1.0 :
- (100.0 * compressedLength / result->size));
- debug(" compressedLength = 0x%hx, actualLength=0x%hx",
- compressedLength, result->size);
-#endif
-
- switch (compressionMethod) {
- case 0: // no compression
- if (result->size != compressedLength) {
- free(result->data);
- result->data = NULL;
- result->status = SCI_STATUS_NOMALLOC;
- free(buffer);
- return SCI_ERROR_DECOMPRESSION_OVERFLOW;
- }
- memcpy(result->data, buffer, compressedLength);
- result->status = SCI_STATUS_ALLOCATED;
- break;
-
- case 18:
- case 19:
- case 20:
- if (unpackDCL(result->data, buffer, result->size, compressedLength)) {
- free(result->data);
- result->data = 0; // So that we know that it didn't work
- result->status = SCI_STATUS_NOMALLOC;
- free(buffer);
- return SCI_ERROR_DECOMPRESSION_OVERFLOW;
- }
- result->status = SCI_STATUS_ALLOCATED;
- break;
-
- case 3:
- case 4: // NYI
- warning("Resource %d.%s: Warning: compression type #%d not yet implemented",
- result->number, getResourceTypeSuffix(result->type), compressionMethod);
- free(result->data);
- result->data = NULL;
- result->status = SCI_STATUS_NOMALLOC;
- break;
-
- default:
- warning("Resource %d.%s: Compression method SCI1/%hi not supported",
- result->number, getResourceTypeSuffix(result->type),
- compressionMethod);
- free(result->data);
- result->data = 0; // So that we know that it didn't work
- result->status = SCI_STATUS_NOMALLOC;
- free(buffer);
- return SCI_ERROR_UNKNOWN_COMPRESSION;
- }
-
- free(buffer);
-
- return 0;
-}
-
-} // End of namespace Sci
diff --git a/engines/sci/scicore/decompressor.cpp b/engines/sci/scicore/decompressor.cpp
new file mode 100644
index 0000000000..609698f9c9
--- /dev/null
+++ b/engines/sci/scicore/decompressor.cpp
@@ -0,0 +1,877 @@
+/* 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$
+ *
+ */
+
+// Resource library
+
+#include <common/util.h>
+#include <common/endian.h>
+#include <common/debug.h>
+#include "sci/scicore/decompressor.h"
+#include "sci/sci.h"
+
+namespace Sci {
+
+int Decompressor::unpack(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
+ uint32 nUnpacked) {
+ init(src, dest, nPacked, nUnpacked);
+ byte buff[1024];
+ uint32 chunk;
+ while (_szPacked && !_src->ioFailed() && !_dest->ioFailed()) {
+ chunk = MIN<uint32>(1024, _szPacked);
+ _src->read(buff, chunk);
+ _dest->write(buff, chunk);
+ _szPacked -= chunk;
+ }
+ return _src->ioFailed() || _dest->ioFailed() ? 1 : 0;
+}
+
+void Decompressor::init(Common::ReadStream*src, Common::WriteStream*dest, uint32 nPacked,
+ uint32 nUnpacked) {
+ _src = src;
+ _dest = dest;
+ _szPacked = nPacked;
+ _szUnpacked = nUnpacked;
+ _nBits = 0;
+ _dwRead = _dwWrote = 0;
+ _dwBits = 0;
+}
+
+void Decompressor::fetchBits() {
+ while (_nBits <= 24) {
+ _dwBits |= ((uint32)_src->readByte()) << (24-_nBits);
+ _nBits += 8;
+ _dwRead ++;
+ }
+}
+
+bool Decompressor::getBit() {
+ // fetching more bits to _dwBits buffer
+ if (_nBits == 0)
+ fetchBits();
+ bool b = _dwBits & 0x80000000;
+ _dwBits <<= 1;
+ _nBits--;
+ return b;
+}
+
+uint32 Decompressor::getBits(int n) {
+ // fetching more data to buffer if needed
+ if(_nBits < n)
+ fetchBits();
+ uint32 ret = _dwBits >> (32-n);
+ _dwBits <<= n;
+ _nBits -= n;
+ return ret;
+}
+
+void Decompressor::putByte(byte b) {
+ _dest->writeByte(b);
+ _dwWrote++;
+}
+//-------------------------------
+// Huffman decompressor
+//-------------------------------
+int DecompressorHuffman::unpack(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
+ uint32 nUnpacked) {
+ init(src, dest, nPacked, nUnpacked);
+
+ byte numnodes;
+ int16 c;
+ uint16 terminator;
+
+ numnodes = _src->readByte();
+ terminator = _src->readByte() | 0x100;
+ _nodes = (byte *)malloc(numnodes << 1);
+ _src->read(_nodes, numnodes << 1);
+
+ while ((c = getc2()) != terminator && (c >= 0) && (_szUnpacked-- > 0))
+ putByte(c);
+
+ free(_nodes);
+ return _dwWrote ? 0 : 1;
+}
+
+int16 DecompressorHuffman::getc2() {
+ byte *node = _nodes;
+ int16 next;
+ while (node[1]) {
+ if (getBit()) {
+ next = node[1] & 0x0F; // use lower 4 bits
+ if (next == 0)
+ return getBits(8) | 0x100;
+ } else
+ next = node[1] >> 4; // use higher 4 bits
+ node += next << 1;
+ }
+ return (int16)(*node | (node[1] << 8));
+}
+
+
+//-------------------------------
+// LZW-like Decompressor
+//-------------------------------
+void DecompressorComp3::init(Common::ReadStream*src, Common::WriteStream*dest, uint32 nPacked, uint32 nUnpacked) {
+ Decompressor::init(src, dest, nPacked, nUnpacked);
+
+ _lastchar = _lastbits = _stakptr = 0;
+ _numbits = 9;
+ _curtoken = 0x102;
+ _endtoken = 0x1ff;
+ memset(_tokens, 0, sizeof(_tokens));
+}
+
+int DecompressorComp3::unpack(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
+ uint32 nUnpacked) {
+ byte *buffer = NULL;
+ byte *buffer2 = NULL;
+ Common::MemoryWriteStream *pBuff = NULL;
+
+ switch (_compression) {
+ case kComp3: // Comp3 compression
+ return doUnpack(src, dest, nPacked, nUnpacked);
+ break;
+ case kComp3View:
+ case kComp3Pic:
+ buffer = new byte[nUnpacked];
+ buffer2 = new byte[nUnpacked];
+ pBuff = new Common::MemoryWriteStream(buffer, nUnpacked);
+ doUnpack(src, pBuff, nPacked, nUnpacked);
+ if (_compression == kComp3View)
+ view_reorder(buffer, buffer2);
+ else
+ pic_reorder(buffer, buffer2, nUnpacked);
+ dest->write(buffer2, nUnpacked);
+ delete[] buffer2;
+ delete[] buffer;
+ break;
+ }
+ return 0;
+}
+
+int DecompressorComp3::doUnpack(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
+ uint32 nUnpacked) {
+ init(src, dest, nPacked, nUnpacked);
+
+ byte decryptstart = 0;
+ uint16 bitstring;
+ uint16 token;
+ bool bExit = false;
+
+ while (_szUnpacked && !bExit) {
+ switch (decryptstart) {
+ case 0:
+ bitstring = getBits(_numbits);
+ if (bitstring == 0x101) {// found end-of-data signal
+ bExit = true;
+ continue;
+ }
+ putByte(bitstring);
+ _szUnpacked--;
+ _lastbits = bitstring;
+ _lastchar = (bitstring & 0xff);
+ decryptstart = 1;
+ break;
+
+ case 1:
+ bitstring = getBits(_numbits);
+ if (bitstring == 0x101) { // found end-of-data signal
+ bExit = true;
+ continue;
+ }
+ if (bitstring == 0x100) { // start-over signal
+ _numbits = 9;
+ _curtoken = 0x102;
+ _endtoken = 0x1ff;
+ decryptstart = 0;
+ continue;
+ }
+
+ token = bitstring;
+ if (token >= _curtoken) { // index past current point
+ token = _lastbits;
+ _stak[_stakptr++] = _lastchar;
+ }
+ while ((token > 0xff) && (token < 0x1004)) { // follow links back in data
+ _stak[_stakptr++] = _tokens[token].data;
+ token = _tokens[token].next;
+ }
+ _lastchar = _stak[_stakptr++] = token & 0xff;
+ // put stack in buffer
+ while (_stakptr > 0) {
+ putByte(_stak[--_stakptr]);
+ if (--_szUnpacked == 0) {
+ bExit = true;
+ continue;
+ }
+ }
+ // put token into record
+ if (_curtoken <= _endtoken) {
+ _tokens[_curtoken].data = _lastchar;
+ _tokens[_curtoken].next = _lastbits;
+ _curtoken++;
+ if (_curtoken == _endtoken && _numbits != 12) {
+ _numbits++;
+ _endtoken = (_endtoken << 1) + 1;
+ }
+ }
+ _lastbits = bitstring;
+ break;
+ }
+ }
+ return _dwWrote ? 0 : 1;
+}
+
+enum {
+ PIC_OP_SET_COLOR = 0xf0,
+ PIC_OP_DISABLE_VISUAL = 0xf1,
+ PIC_OP_SET_PRIORITY = 0xf2,
+ PIC_OP_DISABLE_PRIORITY = 0xf3,
+ PIC_OP_SHORT_PATTERNS = 0xf4,
+ PIC_OP_MEDIUM_LINES = 0xf5,
+ PIC_OP_LONG_LINES = 0xf6,
+ PIC_OP_SHORT_LINES = 0xf7,
+ PIC_OP_FILL = 0xf8,
+ PIC_OP_SET_PATTERN = 0xf9,
+ PIC_OP_ABSOLUTE_PATTERN = 0xfa,
+ PIC_OP_SET_CONTROL = 0xfb,
+ PIC_OP_DISABLE_CONTROL = 0xfc,
+ PIC_OP_MEDIUM_PATTERNS = 0xfd,
+ PIC_OP_OPX = 0xfe,
+ PIC_OP_TERMINATE = 0xff
+};
+
+enum {
+ PIC_OPX_SET_PALETTE_ENTRIES = 0,
+ PIC_OPX_EMBEDDED_VIEW = 1,
+ PIC_OPX_SET_PALETTE = 2,
+ PIC_OPX_PRIORITY_TABLE_EQDIST = 3,
+ PIC_OPX_PRIORITY_TABLE_EXPLICIT = 4
+};
+
+#define PAL_SIZE 1284
+#define CEL_HEADER_SIZE 7
+#define EXTRA_MAGIC_SIZE 15
+
+void DecompressorComp3::decode_rle(byte **rledata, byte **pixeldata, byte *outbuffer, int size) {
+ int pos = 0;
+ char nextbyte;
+ byte *rd = *rledata;
+ byte *ob = outbuffer;
+ byte *pd = *pixeldata;
+
+ while (pos < size) {
+ nextbyte = *(rd++);
+ *(ob++) = nextbyte;
+ pos ++;
+ switch (nextbyte&0xC0) {
+ case 0x40 :
+ case 0x00 :
+ memcpy(ob, pd, nextbyte);
+ pd += nextbyte;
+ ob += nextbyte;
+ pos += nextbyte;
+ break;
+ case 0xC0 :
+ break;
+ case 0x80 :
+ nextbyte = *(pd++);
+ *(ob++) = nextbyte;
+ pos ++;
+ break;
+ }
+ }
+
+ *rledata = rd;
+ *pixeldata = pd;
+}
+
+/*
+ * Does the same this as above, only to determine the length of the compressed
+ * source data.
+ *
+ * Yes, this is inefficient.
+ */
+int DecompressorComp3::rle_size(byte *rledata, int dsize) {
+ int pos = 0;
+ char nextbyte;
+ int size = 0;
+
+ while (pos < dsize) {
+ nextbyte = *(rledata++);
+ pos ++;
+ size ++;
+
+ switch (nextbyte&0xC0) {
+ case 0x40 :
+ case 0x00 :
+ pos += nextbyte;
+ break;
+ case 0xC0 :
+ break;
+ case 0x80 :
+ pos ++;
+ break;
+ }
+ }
+
+ return size;
+}
+
+void DecompressorComp3::pic_reorder(byte *inbuffer, byte *outbuffer, int dsize) {
+ int view_size;
+ int view_start;
+ int cdata_size;
+ int i;
+ byte *seeker = inbuffer;
+ byte *writer;
+ char viewdata[CEL_HEADER_SIZE];
+ byte *cdata, *cdata_start;
+
+ writer = outbuffer;
+
+ *(writer++) = PIC_OP_OPX;
+ *(writer++) = PIC_OPX_SET_PALETTE;
+
+ for (i = 0; i < 256; i++) /* Palette translation map */
+ *(writer++) = i;
+
+ WRITE_LE_UINT16(writer, 0); /* Palette stamp */
+ writer += 2;
+ WRITE_LE_UINT16(writer, 0);
+ writer += 2;
+
+ view_size = READ_LE_UINT16(seeker);
+ seeker += 2;
+ view_start = READ_LE_UINT16(seeker);
+ seeker += 2;
+ cdata_size = READ_LE_UINT16(seeker);
+ seeker += 2;
+
+ memcpy(viewdata, seeker, sizeof(viewdata));
+ seeker += sizeof(viewdata);
+
+ memcpy(writer, seeker, 4*256); /* Palette */
+ seeker += 4*256;
+ writer += 4*256;
+
+ if (view_start != PAL_SIZE + 2) { /* +2 for the opcode */
+ memcpy(writer, seeker, view_start-PAL_SIZE-2);
+ seeker += view_start - PAL_SIZE - 2;
+ writer += view_start - PAL_SIZE - 2;
+ }
+
+ if (dsize != view_start+EXTRA_MAGIC_SIZE+view_size) {
+ memcpy(outbuffer+view_size+view_start+EXTRA_MAGIC_SIZE, seeker,
+ dsize-view_size-view_start-EXTRA_MAGIC_SIZE);
+ seeker += dsize-view_size-view_start-EXTRA_MAGIC_SIZE;
+ }
+
+ cdata_start = cdata = (byte *)malloc(cdata_size);
+ memcpy(cdata, seeker, cdata_size);
+ seeker += cdata_size;
+
+ writer = outbuffer + view_start;
+ *(writer++) = PIC_OP_OPX;
+ *(writer++) = PIC_OPX_EMBEDDED_VIEW;
+ *(writer++) = 0;
+ *(writer++) = 0;
+ *(writer++) = 0;
+ WRITE_LE_UINT16(writer, view_size + 8);
+ writer += 2;
+
+ memcpy(writer, viewdata, sizeof(viewdata));
+ writer += sizeof(viewdata);
+
+ *(writer++) = 0;
+
+ decode_rle(&seeker, &cdata, writer, view_size);
+
+ free(cdata_start);
+}
+
+#define VIEW_HEADER_COLORS_8BIT 0x80
+
+void DecompressorComp3::build_cel_headers(byte **seeker, byte **writer, int celindex, int *cc_lengths, int max) {
+ for (int c = 0; c < max; c++) {
+ memcpy(*writer, *seeker, 6);
+ *seeker += 6; *writer += 6;
+ int w = *((*seeker)++);
+ WRITE_LE_UINT16(*writer, w); /* Zero extension */
+ *writer += 2;
+
+ *writer += cc_lengths[celindex];
+ celindex++;
+ }
+}
+
+void DecompressorComp3::view_reorder(byte *inbuffer, byte *outbuffer) {
+ byte *cellengths;
+ int loopheaders;
+ int lh_present;
+ int lh_mask;
+ int pal_offset;
+ int cel_total;
+ int unknown;
+ byte *seeker = inbuffer;
+ char celcounts[100];
+ byte *writer = outbuffer;
+ byte *lh_ptr;
+ byte *rle_ptr,*pix_ptr;
+ int l, lb, c, celindex, lh_last = -1;
+ int chptr;
+ int w;
+ int *cc_lengths;
+ byte **cc_pos;
+
+ /* Parse the main header */
+ cellengths = inbuffer+READ_LE_UINT16(seeker)+2;
+ seeker += 2;
+ loopheaders = *(seeker++);
+ lh_present = *(seeker++);
+ lh_mask = READ_LE_UINT16(seeker);
+ seeker += 2;
+ unknown = READ_LE_UINT16(seeker);
+ seeker += 2;
+ pal_offset = READ_LE_UINT16(seeker);
+ seeker += 2;
+ cel_total = READ_LE_UINT16(seeker);
+ seeker += 2;
+
+ cc_pos = (byte **) malloc(sizeof(byte *)*cel_total);
+ cc_lengths = (int *) malloc(sizeof(int)*cel_total);
+
+ for (c = 0; c < cel_total; c++)
+ cc_lengths[c] = READ_LE_UINT16(cellengths+2*c);
+
+ *(writer++) = loopheaders;
+ *(writer++) = VIEW_HEADER_COLORS_8BIT;
+ WRITE_LE_UINT16(writer, lh_mask);
+ writer += 2;
+ WRITE_LE_UINT16(writer, unknown);
+ writer += 2;
+ WRITE_LE_UINT16(writer, pal_offset);
+ writer += 2;
+
+ lh_ptr = writer;
+ writer += 2*loopheaders; /* Make room for the loop offset table */
+
+ pix_ptr = writer;
+
+ memcpy(celcounts, seeker, lh_present);
+ seeker += lh_present;
+
+ lb = 1;
+ celindex = 0;
+
+ rle_ptr = pix_ptr = cellengths + (2*cel_total);
+ w = 0;
+
+ for (l = 0; l < loopheaders; l++) {
+ if (lh_mask & lb) { /* The loop is _not_ present */
+ if (lh_last == -1) {
+ warning("Error: While reordering view: Loop not present, but can't re-use last loop");
+ lh_last = 0;
+ }
+ WRITE_LE_UINT16(lh_ptr, lh_last);
+ lh_ptr += 2;
+ } else {
+ lh_last = writer-outbuffer;
+ WRITE_LE_UINT16(lh_ptr, lh_last);
+ lh_ptr += 2;
+ WRITE_LE_UINT16(writer, celcounts[w]);
+ writer += 2;
+ WRITE_LE_UINT16(writer, 0);
+ writer += 2;
+
+ /* Now, build the cel offset table */
+ chptr = (writer - outbuffer) + (2*celcounts[w]);
+
+ for (c = 0; c < celcounts[w]; c++) {
+ WRITE_LE_UINT16(writer, chptr);
+ writer += 2;
+ cc_pos[celindex+c] = outbuffer + chptr;
+ chptr += 8 + READ_LE_UINT16(cellengths+2*(celindex+c));
+ }
+
+ build_cel_headers(&seeker, &writer, celindex, cc_lengths, celcounts[w]);
+
+ celindex += celcounts[w];
+ w++;
+ }
+
+ lb = lb << 1;
+ }
+
+ if (celindex < cel_total) {
+ warning("View decompression generated too few (%d / %d) headers", celindex, cel_total);
+ return;
+ }
+
+ /* Figure out where the pixel data begins. */
+ for (c = 0; c < cel_total; c++)
+ pix_ptr += rle_size(pix_ptr, cc_lengths[c]);
+
+ rle_ptr = cellengths + (2*cel_total);
+ for (c = 0; c < cel_total; c++)
+ decode_rle(&rle_ptr, &pix_ptr, cc_pos[c]+8, cc_lengths[c]);
+
+ *(writer++) = 'P';
+ *(writer++) = 'A';
+ *(writer++) = 'L';
+
+ for (c = 0; c < 256; c++)
+ *(writer++) = c;
+
+ seeker -= 4; /* The missing four. Don't ask why. */
+ memcpy(writer, seeker, 4*256+4);
+
+ free(cc_pos);
+ free(cc_lengths);
+}
+
+//----------------------------------------------
+// LZW 9-12 bits decompressor for SCI0
+//----------------------------------------------
+int DecompressorLZW::unpack(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
+ uint32 nUnpacked) {
+ init(src, dest, nPacked, nUnpacked);
+ byte *buffin = new byte[nPacked];
+ byte *buffout = new byte[nUnpacked];
+ src->read(buffin, nPacked);
+
+ doUnpack(buffin, buffout, nUnpacked, nPacked);
+
+ dest->write(buffout, nUnpacked);
+ delete[] buffin;
+ delete[] buffout;
+ return 0;
+}
+
+int DecompressorLZW::doUnpack(byte *src, byte *dest, int length, int complength) {
+ uint16 bitlen = 9; // no. of bits to read (max. 12)
+ uint16 bitmask = 0x01ff;
+ uint16 bitctr = 0; // current bit position
+ uint16 bytectr = 0; // current byte position
+ uint16 token; // The last received value
+ uint16 maxtoken = 0x200; // The biggest token
+
+ uint16 tokenlist[4096]; // pointers to dest[]
+ uint16 tokenlengthlist[4096]; // char length of each token
+ uint16 tokenctr = 0x102; // no. of registered tokens (starts here)
+
+ uint16 tokenlastlength = 0;
+
+ uint16 destctr = 0;
+
+ while (bytectr < complength) {
+
+ uint32 tokenmaker = src[bytectr++] >> bitctr;
+ if (bytectr < complength)
+ tokenmaker |= (src[bytectr] << (8 - bitctr));
+ if (bytectr + 1 < complength)
+ tokenmaker |= (src[bytectr+1] << (16 - bitctr));
+
+ token = tokenmaker & bitmask;
+
+ bitctr += bitlen - 8;
+
+ while (bitctr >= 8) {
+ bitctr -= 8;
+ bytectr++;
+ }
+
+ if (token == 0x101)
+ return 0; // terminator
+ if (token == 0x100) { // reset command
+ maxtoken = 0x200;
+ bitlen = 9;
+ bitmask = 0x01ff;
+ tokenctr = 0x0102;
+ } else {
+ {
+ int i;
+
+ if (token > 0xff) {
+ if (token >= tokenctr) {
+#ifdef _SCI_DECOMPRESS_DEBUG
+ warning("unpackLZW: Bad token %x", token);
+#endif
+ // Well this is really bad
+ // May be it should throw something like SCI_ERROR_DECOMPRESSION_INSANE
+ } else {
+ tokenlastlength = tokenlengthlist[token] + 1;
+ if (destctr + tokenlastlength > length) {
+#ifdef _SCI_DECOMPRESS_DEBUG
+ // For me this seems a normal situation, It's necessary to handle it
+ warning("unpackLZW: Trying to write beyond the end of array(len=%d, destctr=%d, tok_len=%d)",
+ length, destctr, tokenlastlength);
+#endif
+ i = 0;
+ for (; destctr < length; destctr++) {
+ dest[destctr++] = dest [tokenlist[token] + i];
+ i++;
+ }
+ } else
+ for (i = 0; i < tokenlastlength; i++) {
+ dest[destctr++] = dest[tokenlist[token] + i];
+ }
+ }
+ } else {
+ tokenlastlength = 1;
+ if (destctr >= length) {
+#ifdef _SCI_DECOMPRESS_DEBUG
+ warning("unpackLZW: Try to write single byte beyond end of array");
+#endif
+ } else
+ dest[destctr++] = (byte)token;
+ }
+
+ }
+
+ if (tokenctr == maxtoken) {
+ if (bitlen < 12) {
+ bitlen++;
+ bitmask <<= 1;
+ bitmask |= 1;
+ maxtoken <<= 1;
+ } else
+ continue; // no further tokens allowed
+ }
+
+ tokenlist[tokenctr] = destctr - tokenlastlength;
+ tokenlengthlist[tokenctr++] = tokenlastlength;
+ }
+ }
+
+ return 0;
+}
+
+//----------------------------------------------
+// DCL decompressor for SCI1.1
+//----------------------------------------------
+#define HUFFMAN_LEAF 0x40000000
+
+struct bit_read_struct {
+ int length;
+ int bitpos;
+ int bytepos;
+ byte *data;
+};
+
+#define BRANCH_SHIFT 12
+#define BRANCH_NODE(pos, left, right) ((left << BRANCH_SHIFT) | (right)),
+#define LEAF_NODE(pos, value) ((value) | HUFFMAN_LEAF),
+
+
+static int length_tree[] = {
+#include "treedef.1"
+ 0 // We need something witout a comma at the end
+};
+
+static int distance_tree[] = {
+#include "treedef.2"
+ 0 // We need something witout a comma at the end
+};
+
+static int ascii_tree[] = {
+#include "treedef.3"
+ 0 // We need something witout a comma at the end
+};
+
+#define CALLC(x) { if ((x) == -SCI_ERROR_DECOMPRESSION_OVERFLOW) return -SCI_ERROR_DECOMPRESSION_OVERFLOW; }
+
+int DecompressorDCL::unpack(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
+ uint32 nUnpacked) {
+ init(src, dest, nPacked, nUnpacked);
+ byte *buffin = new byte[nPacked];
+ byte *buffout = new byte[nUnpacked];
+ src->read(buffin, nPacked);
+
+ unpackDCL(buffin, buffout, nUnpacked, nPacked);
+
+ dest->write(buffout, nUnpacked);
+ delete[] buffin;
+ delete[] buffout;
+ return 0;
+}
+
+int DecompressorDCL::getbits(struct bit_read_struct *inp, int bits) {
+ int morebytes = (bits + inp->bitpos - 1) >> 3;
+ int result = 0;
+ int i;
+
+ if (inp->bytepos + morebytes >= inp->length) {
+ warning("read out-of-bounds with bytepos %d + morebytes %d >= length %d",
+ inp->bytepos, morebytes, inp->length);
+ return -7;
+ }
+
+ for (i = 0; i <= morebytes; i++)
+ result |= (inp->data[inp->bytepos + i]) << (i << 3);
+
+ result >>= inp->bitpos;
+ result &= ~((~0) << bits);
+
+ inp->bitpos += bits - (morebytes << 3);
+ inp->bytepos += morebytes;
+
+ debugC(kDebugLevelDclInflate, "(%d:%04x)", bits, result);
+
+ return result;
+}
+
+int DecompressorDCL::huffman_lookup(struct bit_read_struct *inp, int *tree) {
+ int pos = 0;
+ int bit;
+
+ while (!(tree[pos] & HUFFMAN_LEAF)) {
+ CALLC(bit = getbits(inp, 1));
+ debugC(kDebugLevelDclInflate, "[%d]:%d->", pos, bit);
+ if (bit)
+ pos = tree[pos] & ~(~0 << BRANCH_SHIFT);
+ else
+ pos = tree[pos] >> BRANCH_SHIFT;
+ }
+ debugC(kDebugLevelDclInflate, "=%02x\n", tree[pos] & 0xffff);
+ return tree[pos] & 0xffff;
+}
+
+#define VALUE_M(i) ((i == 0)? 7 : (VALUE_M(i - 1) + 2**i));
+
+#define DCL_ASCII_MODE 1
+
+int DecompressorDCL::unpackDCL(uint8* src, uint8* dest, int length, int complength) {
+ int mode, length_param, value, val_length, val_distance;
+ int write_pos = 0;
+ struct bit_read_struct reader;
+
+ reader.length = complength;
+ reader.bitpos = 0;
+ reader.bytepos = 0;
+ reader.data = src;
+
+ CALLC(mode = getbits(&reader, 8));
+ CALLC(length_param = getbits(&reader, 8));
+
+ if (mode == DCL_ASCII_MODE) {
+ warning("DCL-INFLATE: Decompressing ASCII mode (untested)");
+ } else if (mode) {
+ warning("DCL-INFLATE: Error: Encountered mode %02x, expected 00 or 01\n", mode);
+ return -1;
+ }
+
+ if (Common::isDebugChannelEnabled(kDebugLevelDclInflate)) {
+ for (int i = 0; i < reader.length; i++) {
+ debugC(kDebugLevelDclInflate, "%02x ", reader.data[i]);
+ if (!((i + 1) & 0x1f))
+ debugC(kDebugLevelDclInflate, "\n");
+ }
+
+
+ debugC(kDebugLevelDclInflate, "\n---\n");
+ }
+
+
+ if (length_param < 3 || length_param > 6)
+ warning("Unexpected length_param value %d (expected in [3,6])\n", length_param);
+
+ while (write_pos < length) {
+ CALLC(value = getbits(&reader, 1));
+
+ if (value) { // (length,distance) pair
+ CALLC(value = huffman_lookup(&reader, length_tree));
+
+ if (value < 8)
+ val_length = value + 2;
+ else {
+ int length_bonus;
+
+ val_length = (1 << (value - 7)) + 8;
+ CALLC(length_bonus = getbits(&reader, value - 7));
+ val_length += length_bonus;
+ }
+
+ debugC(kDebugLevelDclInflate, " | ");
+
+ CALLC(value = huffman_lookup(&reader, distance_tree));
+
+ if (val_length == 2) {
+ val_distance = value << 2;
+
+ CALLC(value = getbits(&reader, 2));
+ val_distance |= value;
+ } else {
+ val_distance = value << length_param;
+
+ CALLC(value = getbits(&reader, length_param));
+ val_distance |= value;
+ }
+ ++val_distance;
+
+ debugC(kDebugLevelDclInflate, "\nCOPY(%d from %d)\n", val_length, val_distance);
+
+ if (val_length + write_pos > length) {
+ warning("DCL-INFLATE Error: Write out of bounds while copying %d bytes", val_length);
+ return SCI_ERROR_DECOMPRESSION_OVERFLOW;
+ }
+
+ if (write_pos < val_distance) {
+ warning("DCL-INFLATE Error: Attempt to copy from before beginning of input stream");
+ return SCI_ERROR_DECOMPRESSION_INSANE;
+ }
+
+ while (val_length) {
+ int copy_length = (val_length > val_distance) ? val_distance : val_length;
+
+ memcpy(dest + write_pos, dest + write_pos - val_distance, copy_length);
+
+ if (Common::isDebugChannelEnabled(kDebugLevelDclInflate)) {
+ for (int i = 0; i < copy_length; i++)
+ debugC(kDebugLevelDclInflate, "\33[32;31m%02x\33[37;37m ", dest[write_pos + i]);
+ debugC(kDebugLevelDclInflate, "\n");
+ }
+
+ val_length -= copy_length;
+ val_distance += copy_length;
+ write_pos += copy_length;
+ }
+
+ } else { // Copy byte verbatim
+ if (mode == DCL_ASCII_MODE) {
+ CALLC(value = huffman_lookup(&reader, ascii_tree));
+ } else {
+ CALLC(value = getbits(&reader, 8));
+ }
+
+ dest[write_pos++] = value;
+
+ debugC(kDebugLevelDclInflate, "\33[32;31m%02x \33[37;37m", value);
+ }
+ }
+
+ return 0;
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/scicore/decompressor.h b/engines/sci/scicore/decompressor.h
new file mode 100644
index 0000000000..3f8bd147c3
--- /dev/null
+++ b/engines/sci/scicore/decompressor.h
@@ -0,0 +1,179 @@
+/* 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$
+ *
+ */
+
+#ifndef SCI_SCICORE_DECOMPRESSOR_H
+#define SCI_SCICORE_DECOMPRESSOR_H
+
+#include "common/file.h"
+
+namespace Sci {
+enum ResourceCompression {
+ kCompUnknown = -1,
+ kCompNone = 0,
+ kCompLZW,
+ kCompHuffman,
+ kComp3, // LZW-like compression used in SCI01 and SCI1
+ kComp3View, // Comp3 + view Post-processing
+ kComp3Pic, // Comp3 + pic Post-processing
+ kCompDCL,
+ kCompSTACpack // ? Used in SCI32
+};
+//----------------------------------------------
+// Base class for decompressors
+// Simply copies nPacked bytes from src to dest
+//----------------------------------------------
+class Decompressor {
+public:
+ Decompressor(){}
+ ~Decompressor(){}
+
+ //! get a number of bits from _src stream
+ /** @param n - number of bits to get
+ @return (uint32) n-bits number
+ */
+ virtual int unpack(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
+ uint32 nUnpacked);
+
+protected:
+ //! Initialize decompressor
+ /** @param src - source stream to read from
+ @param dest - destination stream to write to
+ @param nPacked - size of packed data
+ @param nUnpacket - size of unpacked data
+ @return (int) 0 on success, non-zero on error
+ */
+ virtual void init(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
+ uint32 nUnpacked); //! get one bit from _src stream
+ /** @return (bool) bit;
+ */
+ virtual bool getBit();
+ //! get a number of bits from _src stream
+ /** @param n - number of bits to get
+ @return (uint32) n-bits number
+ */
+ virtual uint32 getBits(int n);
+ //! put byte to _dest stream
+ /** @param b - byte to put
+ */
+ virtual void putByte(byte b);
+ virtual void fetchBits();
+
+ uint32 _dwBits;
+ byte _nBits;
+
+ uint32 _szPacked;
+ uint32 _szUnpacked;
+ uint32 _dwRead;
+ uint32 _dwWrote;
+
+ Common::ReadStream *_src;
+ Common::WriteStream *_dest;
+};
+
+//----------------------------------------------
+// Huffman decompressor
+//----------------------------------------------
+class DecompressorHuffman : public Decompressor {
+public:
+ int unpack(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
+ uint32 nUnpacked);
+
+protected:
+ int16 getc2();
+
+ byte *_nodes;
+};
+
+//----------------------------------------------
+// LZW-like decompressor for SCI01/SCI1
+// TODO: Needs clean-up of post-processing fncs
+//----------------------------------------------
+class DecompressorComp3 : public Decompressor {
+public:
+ DecompressorComp3(int nCompression) {
+ _compression = nCompression;
+ }
+ void init(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked, uint32 nUnpacked);
+ int unpack(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
+ uint32 nUnpacked);
+
+protected:
+ // actual unpacking procedure
+ int doUnpack(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
+ uint32 nUnpacked);
+ // functions to post-process view and pic resources
+ void decode_rle(byte **rledata, byte **pixeldata, byte *outbuffer, int size);
+ int rle_size(byte *rledata, int dsize);
+ void pic_reorder(byte *inbuffer, byte *outbuffer, int dsize);
+ void build_cel_headers(byte **seeker, byte **writer, int celindex, int *cc_lengths, int max);
+ void view_reorder(byte *inbuffer, byte *outbuffer);
+
+ struct tokenlist {
+ byte data;
+ uint16 next;
+ } _tokens[0x1004];
+ byte _stak[0x1014];
+ byte _lastchar;
+ uint16 _stakptr;
+ uint16 _numbits, _lastbits;
+ uint16 _curtoken, _endtoken;
+ int _compression;
+};
+
+//----------------------------------------------
+// LZW 9-12 bits decompressor for SCI0
+// TODO : Needs clean-up of doUnpack()
+//----------------------------------------------
+class DecompressorLZW : public Decompressor {
+public:
+// void init(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked, uint32 nUnpacked);
+ int unpack(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
+ uint32 nUnpacked);
+
+protected:
+ int doUnpack(byte *src, byte *dest, int length, int complength);
+
+};
+
+//----------------------------------------------
+// DCL decompressor for SCI1.1
+// TODO : Needs clean-up of doUnpack()
+//----------------------------------------------
+class DecompressorDCL : public Decompressor {
+public:
+// void init(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked, uint32 nUnpacked);
+ int unpack(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
+ uint32 nUnpacked);
+
+protected:
+ int unpackDCL(byte *src, byte *dest, int length, int complength);
+ int getbits(struct bit_read_struct *inp, int bits);
+ int huffman_lookup(struct bit_read_struct *inp, int *tree);
+
+};
+
+} // End of namespace Sci
+
+#endif // SCI_SCICORE_DECOMPRESSOR_H \ No newline at end of file
diff --git a/engines/sci/scicore/resource.cpp b/engines/sci/scicore/resource.cpp
index cfb7eeaa96..b027fb39e8 100644
--- a/engines/sci/scicore/resource.cpp
+++ b/engines/sci/scicore/resource.cpp
@@ -32,6 +32,7 @@
#include "sci/sci_memory.h"
#include "sci/scicore/resource.h"
#include "sci/scicore/vocabulary.h"
+#include "sci/scicore/decompressor.h"
namespace Sci {
@@ -93,18 +94,6 @@ const char *getResourceTypeSuffix(ResourceType restype) {
typedef int decomp_funct(Resource *result, Common::ReadStream &stream, int sci_version);
typedef void patch_sprintf_funct(char *string, Resource *res);
-static decomp_funct *decompressors[] = {
- NULL,
- &decompress0,
- &decompress01,
- &decompress01,
- &decompress01,
- &decompress1,
- &decompress1,
- &decompress11,
- NULL
-};
-
//-- Resource main functions --
Resource::Resource() {
data = NULL;
@@ -113,7 +102,7 @@ Resource::Resource() {
id = 0;
size = 0;
file_offset = 0;
- status = SCI_STATUS_NOMALLOC;
+ status = kResStatusNoMalloc;
lockers = 0;
source = NULL;
}
@@ -127,7 +116,7 @@ Resource::~Resource() {
void Resource::unalloc() {
delete[] data;
data = NULL;
- status = SCI_STATUS_NOMALLOC;
+ status = kResStatusNoMalloc;
}
//-- Resmgr helper functions --
@@ -213,7 +202,7 @@ bool ResourceManager::loadFromPatchFile(Resource *res) {
if (really_read != res->size) {
error("Read %d bytes from %s but expected %d!", really_read, filename, res->size);
}
- res->status = SCI_STATUS_ALLOCATED;
+ res->status = kResStatusAllocated;
return true;
}
@@ -233,17 +222,13 @@ void ResourceManager::loadResource(Resource *res) {
}
file.seek(res->file_offset, SEEK_SET);
- // Check whether we support this at all
- if (decompressors[_sciVersion] == NULL)
- error("Resource manager's SCI version (%d) is invalid", _sciVersion);
- // Decompress from regular resource file
- int error = decompressors[_sciVersion](res, file, _sciVersion);
-
+ int error = decompress(res, &file);
if (error) {
warning("Error %d occured while reading %s.%03d from resource file: %s\n",
error, getResourceTypeName(res->type), res->number, sci_error_types[error]);
res->unalloc();
}
+
}
Resource *ResourceManager::testResource(ResourceType type, int number) {
@@ -252,7 +237,18 @@ Resource *ResourceManager::testResource(ResourceType type, int number) {
return NULL;
}
-int sci0_get_compression_method(Common::ReadStream &stream);
+int sci0_get_compression_method(Common::ReadStream &stream) {
+ uint16 compressionMethod;
+
+ stream.readUint16LE();
+ stream.readUint16LE();
+ stream.readUint16LE();
+ compressionMethod = stream.readUint16LE();
+ if (stream.err())
+ return SCI_ERROR_IO_ERROR;
+
+ return compressionMethod;
+}
int sci_test_view_type(ResourceManager *mgr) {
Common::File file;
@@ -421,7 +417,7 @@ ResourceManager::ResourceManager(int version, int maxMemory) {
_sciVersion = version = SCI_VERSION_1_EARLY;
loadResource(res);
- if (res->status == SCI_STATUS_NOMALLOC)
+ if (res->status == kResStatusNoMalloc)
version = SCI_VERSION_1_LATE;
break;
}
@@ -469,17 +465,17 @@ ResourceManager::~ResourceManager() {
}
void ResourceManager::removeFromLRU(Resource *res) {
- if (res->status != SCI_STATUS_ENQUEUED) {
+ if (res->status != kResStatusEnqueued) {
sciprintf("Resmgr: Oops: trying to remove resource that isn't enqueued\n");
return;
}
_LRU.remove(res);
_memoryLRU -= res->size;
- res->status = SCI_STATUS_ALLOCATED;
+ res->status = kResStatusAllocated;
}
void ResourceManager::addToLRU(Resource *res) {
- if (res->status != SCI_STATUS_ALLOCATED) {
+ if (res->status != kResStatusAllocated) {
warning("Resmgr: Oops: trying to enqueue resource with state %d", res->status);
return;
}
@@ -491,7 +487,7 @@ void ResourceManager::addToLRU(Resource *res) {
mgr->_memoryLRU);
#endif
- res->status = SCI_STATUS_ENQUEUED;
+ res->status = kResStatusEnqueued;
}
void ResourceManager::printLRU() {
@@ -547,26 +543,26 @@ Resource *ResourceManager::findResource(ResourceType type, int number, int lock)
if (!retval->status)
loadResource(retval);
- else if (retval->status == SCI_STATUS_ENQUEUED)
+ else if (retval->status == kResStatusEnqueued)
removeFromLRU(retval);
// Unless an error occured, the resource is now either
// locked or allocated, but never queued or freed.
if (lock) {
- if (retval->status == SCI_STATUS_ALLOCATED) {
- retval->status = SCI_STATUS_LOCKED;
+ if (retval->status == kResStatusAllocated) {
+ retval->status = kResStatusLocked;
retval->lockers = 0;
_memoryLocked += retval->size;
}
++retval->lockers;
- } else if (retval->status != SCI_STATUS_LOCKED) { // Don't lock it
- if (retval->status == SCI_STATUS_ALLOCATED)
+ } else if (retval->status != kResStatusLocked) { // Don't lock it
+ if (retval->status == kResStatusAllocated)
addToLRU(retval);
}
- freeOldResources(retval->status == SCI_STATUS_ALLOCATED);
+ freeOldResources(retval->status == kResStatusAllocated);
if (retval->data)
return retval;
@@ -585,14 +581,14 @@ void ResourceManager::unlockResource(Resource *res, int resnum, ResourceType res
return;
}
- if (res->status != SCI_STATUS_LOCKED) {
+ if (res->status != kResStatusLocked) {
sciprintf("Resmgr: Warning: Attempt to unlock unlocked resource %s.%03d\n",
getResourceTypeName(res->type), res->number);
return;
}
if (!--res->lockers) { // No more lockers?
- res->status = SCI_STATUS_ALLOCATED;
+ res->status = kResStatusAllocated;
_memoryLocked -= res->size;
addToLRU(res);
}
@@ -677,8 +673,8 @@ int ResourceManager::detectVolVersion() {
}
// SCI0 volume format: {wResId wPacked+4 wUnpacked wCompression} = 8 bytes
// SCI1 volume format: {bResType wResNumber wPacked+4 wUnpacked wCompression} = 9 bytes
- // SCI1.1 volume format: {bResType wResNumber wPacked+4 wUnpacked wCompression} = 9 bytes
- // SCI32 volume format : {bResType wResNumber dwPacked+4 dwUnpacked wCompression} = 13 bytes
+ // SCI1.1 volume format: {bResType wResNumber wPacked wUnpacked wCompression} = 9 bytes
+ // SCI32 volume format : {bResType wResNumber dwPacked dwUnpacked wCompression} = 13 bytes
// Try to parse volume with SCI0 scheme to see if it make sense
// Checking 1MB of data should be enough to determine the version
uint16 resId, wCompression;
@@ -814,7 +810,7 @@ void ResourceManager::processPatch(ResourceSource *source,
// Overwrite everything, because we're patching
newrsc->id = resId;
newrsc->number = resnumber;
- newrsc->status = SCI_STATUS_NOMALLOC;
+ newrsc->status = kResStatusNoMalloc;
newrsc->type = restype;
newrsc->source = source;
newrsc->size = fsize - patch_data_offset - 2;
@@ -899,7 +895,7 @@ int ResourceManager::readResourceMapSCI0(ResourceSource *map) {
// adding a new resource
if (_resMap.contains(resId) == false) {
res = new Resource;
- res->id = id;
+ res->id = resId;//id;
res->file_offset = offset & (((~bMask) << 24) | 0xFFFFFF);
res->number = number;
res->type = type;
@@ -953,7 +949,7 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map, ResourceSource *vo
_resMap.setVal(resId, res);
res->type = (ResourceType)type;
res->number = number;
- res->id = res->number | (res->type << 16);
+ res->id = resId;//res->number | (res->type << 16);
res->source = _mapVersion < SCI_VERSION_1_1 ? getVolume(map, off >> 28) : vol;
if (_mapVersion < SCI_VERSION_32)
res->file_offset = _mapVersion < SCI_VERSION_1_1 ? off & 0x0FFFFFFF : off << 1;
@@ -965,4 +961,149 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map, ResourceSource *vo
return 0;
}
+int ResourceManager::readResourceInfo(Resource *res, Common::File *file,
+ uint32&szPacked, ResourceCompression &compression) {
+ // SCI0 volume format: {wResId wPacked+4 wUnpacked wCompression} = 8 bytes
+ // SCI1 volume format: {bResType wResNumber wPacked+4 wUnpacked wCompression} = 9 bytes
+ // SCI1.1 volume format: {bResType wResNumber wPacked wUnpacked wCompression} = 9 bytes
+ // SCI32 volume format : {bResType wResNumber dwPacked dwUnpacked wCompression} = 13 bytes
+ uint16 w, number, szUnpacked;
+ uint32 wCompression;
+ ResourceType type;
+
+ switch (_volVersion) {
+ case SCI_VERSION_0:
+ w = file->readUint16LE();
+ type = (ResourceType)(w >> 11);
+ number = w & 0x7FF;
+ szPacked = file->readUint16LE() - 4;
+ szUnpacked = file->readUint16LE();
+ wCompression = file->readUint16LE();
+ break;
+ case SCI_VERSION_1:
+ type = (ResourceType)file->readByte();
+ number = file->readUint16LE();
+ szPacked = file->readUint16LE() - 4;
+ szUnpacked = file->readUint16LE();
+ wCompression = file->readUint16LE();
+ break;
+ case SCI_VERSION_1_1:
+ type = (ResourceType)file->readByte();
+ number = file->readUint16LE();
+ szPacked = file->readUint16LE();
+ szUnpacked = file->readUint16LE();
+ wCompression = file->readUint16LE();
+ break;
+ case SCI_VERSION_32:
+ type = (ResourceType)file->readByte();
+ number = file->readUint16LE();
+ szPacked = file->readUint32LE();
+ szUnpacked = file->readUint32LE();
+ wCompression = file->readUint16LE();
+ break;
+ default:
+ return SCI_ERROR_INVALID_RESMAP_ENTRY;
+ }
+ // check if there were errors while reading
+ if (file->ioFailed())
+ return SCI_ERROR_IO_ERROR;
+ res->id = RESOURCE_HASH(type, number);
+ res->type = type;
+ res->number = number;
+ res->size = szUnpacked;
+ // checking compression method
+ if (wCompression == 0)
+ compression = kCompNone;
+ switch (_sciVersion) {
+ case SCI_VERSION_0:
+ if (wCompression == 1)
+ compression = kCompLZW;
+ else if (wCompression == 2)
+ compression = kCompHuffman;
+ break;
+ case SCI_VERSION_01:
+ case SCI_VERSION_01_VGA:
+ case SCI_VERSION_01_VGA_ODD:
+ case SCI_VERSION_1_EARLY:
+ case SCI_VERSION_1_LATE:
+ if (wCompression == 1)
+ compression = kCompHuffman;
+ else if (wCompression == 2)
+ compression = kComp3;
+ else if (wCompression == 3)
+ compression = kComp3View;
+ else if (wCompression == 4)
+ compression = kComp3Pic;
+ break;
+ case SCI_VERSION_1_1:
+ if (wCompression >= 18 && wCompression <= 20)
+ compression = kCompDCL;
+ break;
+ case SCI_VERSION_32:
+ if (wCompression == 32)
+ compression = kCompSTACpack;
+ break;
+ default:
+ compression = kCompUnknown;
+ }
+
+ return compression == kCompUnknown ? SCI_ERROR_UNKNOWN_COMPRESSION : 0;
+}
+
+int ResourceManager::decompress(Resource *res, Common::File *file) {
+ int error;
+ uint32 szPacked = 0;
+ Common::MemoryWriteStream *pDest = NULL;
+ ResourceCompression compression = kCompUnknown;
+
+ // fill resource info
+ error = readResourceInfo(res, file, szPacked, compression);
+ if (error)
+ return error;
+ // getting a decompressor
+ Decompressor *dec = NULL;
+ switch (compression) {
+ case kCompNone:
+ dec = new Decompressor;
+ break;
+ case kCompLZW:
+ dec = new DecompressorLZW;
+ break;
+ case kCompHuffman:
+ dec = new DecompressorHuffman;
+ break;
+ case kComp3:
+ case kComp3View:
+ case kComp3Pic:
+ dec = new DecompressorComp3(compression);
+ break;
+ case kCompDCL:
+ dec = new DecompressorDCL;
+ break;
+ default:
+ warning("Resource %s #%d: Compression method %d not supported",
+ getResourceTypeName(res->type), res->number, compression);
+ break;
+ }
+
+ if (dec) {
+ res->data = new byte[res->size];
+ pDest = new Common::MemoryWriteStream(res->data , res->size);
+ error = dec->unpack(file, pDest, szPacked, res->size);
+ } else
+ error = SCI_ERROR_UNKNOWN_COMPRESSION;
+
+ if (!error)
+ res->status = kResStatusAllocated;
+ else {
+ delete res->data;
+ res->data = 0;
+ res->status = kResStatusNoMalloc;
+ }
+ delete dec;
+ delete pDest;
+
+ return error;
+}
+
} // End of namespace Sci
diff --git a/engines/sci/scicore/resource.h b/engines/sci/scicore/resource.h
index a44ff0f0fa..4cf0de3ad3 100644
--- a/engines/sci/scicore/resource.h
+++ b/engines/sci/scicore/resource.h
@@ -30,6 +30,8 @@
#include "common/file.h"
#include "common/archive.h"
+#include "sci/scicore/decompressor.h"
+
namespace Common {
class ReadStream;
}
@@ -40,10 +42,12 @@ namespace Sci {
#define SCI_MAX_RESOURCE_SIZE 0x0400000
/*** RESOURCE STATUS TYPES ***/
-#define SCI_STATUS_NOMALLOC 0
-#define SCI_STATUS_ALLOCATED 1
-#define SCI_STATUS_ENQUEUED 2 /* In the LRU queue */
-#define SCI_STATUS_LOCKED 3 /* Allocated and in use */
+enum ResourceStatus {
+ kResStatusNoMalloc=0,
+ kResStatusAllocated,
+ kResStatusEnqueued, /* In the LRU queue */
+ kResStatusLocked /* Allocated and in use */
+};
/*** INITIALIZATION RESULT TYPES ***/
#define SCI_ERROR_IO_ERROR 1
@@ -163,12 +167,12 @@ public:
byte *data;
uint16 number;
ResourceType type;
- uint16 id; // contains number and type.
+ uint32 id; // contains number and type.
// TODO: maybe use uint32 and set id = RESOURCE_HASH()
// for all SCI versions
unsigned int size;
unsigned int file_offset; /* Offset in file */
- byte status;
+ ResourceStatus status;
unsigned short lockers; /* Number of places where this resource was locked */
ResourceSource *source;
};
@@ -267,6 +271,8 @@ protected:
void loadResource(Resource *res);
bool loadFromPatchFile(Resource *res);
void freeOldResources(int last_invulnerable);
+ int decompress(Resource *res, Common::File *file);
+ int readResourceInfo(Resource *res, Common::File *file, uint32&szPacked, ResourceCompression &compression);
/**--- Resource map decoding functions ---*/
int detectMapVersion();
@@ -295,57 +301,6 @@ protected:
void removeFromLRU(Resource *res);
};
- /**--- Decompression functions ---**/
- int decompress0(Resource *result, Common::ReadStream &stream, int sci_version);
- /* Decrypts resource data and stores the result for SCI0-style compression.
- ** Parameters : result: The Resource the decompressed data is stored in.
- ** stream: Stream of the resource file
- ** sci_version : Actual SCI resource version
- ** Returns : (int) 0 on success, one of SCI_ERROR_* if a problem was
- ** encountered.
- */
-
- int decompress01(Resource *result, Common::ReadStream &stream, int sci_version);
- /* Decrypts resource data and stores the result for SCI01-style compression.
- ** Parameters : result: The Resource the decompressed data is stored in.
- ** stream: Stream of the resource file
- ** sci_version : Actual SCI resource version
- ** Returns : (int) 0 on success, one of SCI_ERROR_* if a problem was
- ** encountered.
- */
-
- int decompress1(Resource *result, Common::ReadStream &stream, int sci_version);
- /* Decrypts resource data and stores the result for SCI1.1-style compression.
- ** Parameters : result: The Resource the decompressed data is stored in.
- ** sci_version : Actual SCI resource version
- ** stream: Stream of the resource file
- ** Returns : (int) 0 on success, one of SCI_ERROR_* if a problem was
- ** encountered.
- */
-
- int decompress11(Resource *result, Common::ReadStream &stream, int sci_version);
- /* Decrypts resource data and stores the result for SCI1.1-style compression.
- ** Parameters : result: The Resource the decompressed data is stored in.
- ** sci_version : Actual SCI resource version
- ** stream: Stream of the resource file
- ** Returns : (int) 0 on success, one of SCI_ERROR_* if a problem was
- ** encountered.
- */
-
- int unpackHuffman(uint8* dest, uint8* src, int length, int complength);
- /* Huffman token decryptor - defined in decompress0.c and used in decompress01.c
- */
-
- int unpackDCL(uint8* dest, uint8* src, int length, int complength);
- /* DCL inflate- implemented in decompress1.c
- */
-
- byte *view_reorder(byte *inbuffer, int dsize);
- /* SCI1 style view compression */
-
- byte *pic_reorder(byte *inbuffer, int dsize);
- /* SCI1 style pic compression */
-
} // End of namespace Sci
#endif // SCI_SCICORE_RESOURCE_H