aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/scicore
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/scicore')
-rw-r--r--engines/sci/scicore/decompressor.cpp550
-rw-r--r--engines/sci/scicore/decompressor.h117
-rw-r--r--engines/sci/scicore/resource.cpp85
3 files changed, 332 insertions, 420 deletions
diff --git a/engines/sci/scicore/decompressor.cpp b/engines/sci/scicore/decompressor.cpp
index ff8fa4a445..836d023514 100644
--- a/engines/sci/scicore/decompressor.cpp
+++ b/engines/sci/scicore/decompressor.cpp
@@ -31,26 +31,19 @@
#include "sci/scicore/decompressor.h"
#include "sci/sci.h"
-#define _SCI_DECOMPRESS_DEBUG
namespace Sci {
-
-int Decompressor::unpack(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
- uint32 nUnpacked) {
- return copyBytes(src, dest, nPacked);
-}
-
-int Decompressor::copyBytes(Common::ReadStream *src, Common::WriteStream *dest, uint32 nSize) {
- byte buff[1024];
+int Decompressor::unpack(Common::ReadStream *src, byte *dest, uint32 nPacked, uint32 nUnpacked) {
uint32 chunk;
- while (nSize && !src->ioFailed() && !dest->ioFailed()) {
- chunk = MIN<uint32>(1024, nSize);
- src->read(buff, chunk);
- dest->write(buff, chunk);
- nSize -= chunk;
+ while (nPacked && !src->ioFailed()) {
+ chunk = MIN<uint32>(1024, nPacked);
+ src->read(dest, chunk);
+ nPacked -= chunk;
+ dest += chunk;
}
- return src->ioFailed() || dest->ioFailed() ? 1 : 0;
+ return src->ioFailed() ? 1 : 0;
}
-void Decompressor::init(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
+
+void Decompressor::init(Common::ReadStream *src, byte *dest, uint32 nPacked,
uint32 nUnpacked) {
_src = src;
_dest = dest;
@@ -61,7 +54,7 @@ void Decompressor::init(Common::ReadStream *src, Common::WriteStream *dest, uint
_dwBits = 0;
}
-void Decompressor::fetchBits() {
+void Decompressor::fetchBitsMSB() {
while (_nBits <= 24) {
_dwBits |= ((uint32)_src->readByte()) << (24 - _nBits);
_nBits += 8;
@@ -69,54 +62,84 @@ void Decompressor::fetchBits() {
}
}
-bool Decompressor::getBit() {
+bool Decompressor::getBitMSB() {
// fetching more bits to _dwBits buffer
if (_nBits == 0)
- fetchBits();
+ fetchBitsMSB();
bool b = _dwBits & 0x80000000;
_dwBits <<= 1;
_nBits--;
return b;
}
-uint32 Decompressor::getBits(int n) {
+uint32 Decompressor::getBitsMSB(int n) {
// fetching more data to buffer if needed
if (_nBits < n)
- fetchBits();
+ fetchBitsMSB();
uint32 ret = _dwBits >> (32 - n);
_dwBits <<= n;
_nBits -= n;
return ret;
}
-byte Decompressor::getByte() {
- return getBits(8);
+byte Decompressor::getByteMSB() {
+ return getBitsMSB(8);
+}
+
+void Decompressor::fetchBitsLSB() {
+ while (_nBits <= 24) {
+ _dwBits |= ((uint32)_src->readByte()) << _nBits;
+ _nBits += 8;
+ _dwRead++;
+ }
+}
+
+bool Decompressor::getBitLSB() {
+ // fetching more bits to _dwBits buffer
+ if (_nBits == 0)
+ fetchBitsLSB();
+ bool b = _dwBits & 0x1;
+ _dwBits >>= 1;
+ _nBits--;
+ return b;
+}
+
+uint32 Decompressor::getBitsLSB(int n) {
+ // fetching more data to buffer if needed
+ if (_nBits < n)
+ fetchBitsLSB();
+ uint32 ret = (_dwBits & ~((~0) << n));
+ _dwBits >>= n;
+ _nBits -= n;
+ return ret;
+}
+
+byte Decompressor::getByteLSB() {
+ return getBitsLSB(8);
}
void Decompressor::putByte(byte b) {
- _dest->writeByte(b);
- _dwWrote++;
+ _dest[_dwWrote++] = b;
}
//-------------------------------
// Huffman decompressor
//-------------------------------
-int DecompressorHuffman::unpack(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
- uint32 nUnpacked) {
+int DecompressorHuffman::unpack(Common::ReadStream *src, byte *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);
+ _nodes = new byte [numnodes << 1];
_src->read(_nodes, numnodes << 1);
while ((c = getc2()) != terminator && (c >= 0) && (_szUnpacked-- > 0))
putByte(c);
- free(_nodes);
+ delete[] _nodes;
return _dwWrote ? 0 : 1;
}
@@ -124,10 +147,10 @@ int16 DecompressorHuffman::getc2() {
byte *node = _nodes;
int16 next;
while (node[1]) {
- if (getBit()) {
+ if (getBitMSB()) {
next = node[1] & 0x0F; // use lower 4 bits
if (next == 0)
- return getByte() | 0x100;
+ return getByteMSB() | 0x100;
} else
next = node[1] >> 4; // use higher 4 bits
node += next << 1;
@@ -135,57 +158,112 @@ int16 DecompressorHuffman::getc2() {
return (int16)(*node | (node[1] << 8));
}
-
//-------------------------------
-// LZW-like Decompressor
+// LZW Decompressor for SCI0/01/1
//-------------------------------
-void DecompressorComp3::init(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked, uint32 nUnpacked) {
+void DecompressorLZW::init(Common::ReadStream *src, byte *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) {
+int DecompressorLZW::unpack(Common::ReadStream *src, byte *dest, uint32 nPacked,
+ uint32 nUnpacked) {
byte *buffer = NULL;
- byte *buffer2 = NULL;
- Common::MemoryWriteStream *pBuff = NULL;
- Common::MemoryReadStream *pBuffIn = NULL;
switch (_compression) {
- case kComp3: // Comp3 compression
- return doUnpack(src, dest, nPacked, nUnpacked);
+ case kCompLZW: // SCI0 LZW compression
+ return unpackLZW(src, dest, nPacked, nUnpacked);
+ break;
+ case kCompLZW1: // SCI01/1 LZW compression
+ return unpackLZW1(src, dest, nPacked, nUnpacked);
break;
- case kComp3View:
- case kComp3Pic:
+ case kCompLZW1View:
buffer = new byte[nUnpacked];
- pBuff = new Common::MemoryWriteStream(buffer, nUnpacked);
- doUnpack(src, pBuff, nPacked, nUnpacked);
- if (_compression == kComp3View) {
- buffer2 = new byte[nUnpacked];
- view_reorder(buffer, buffer2);
- dest->write(buffer2, nUnpacked);
+ unpackLZW1(src, buffer, nPacked, nUnpacked);
+ reorderView(buffer, dest);
+ break;
+ case kCompLZW1Pic:
+ buffer = new byte[nUnpacked];
+ unpackLZW1(src, buffer, nPacked, nUnpacked);
+ reorderPic(buffer, dest, nUnpacked);
+ break;
+ }
+ delete[] buffer;
+ return 0;
+}
+
+int DecompressorLZW::unpackLZW(Common::ReadStream *src, byte *dest, uint32 nPacked,
+ uint32 nUnpacked) {
+ init(src, dest, nPacked, nUnpacked);
+
+ uint16 token; // The last received value
+
+ uint16 tokenlist[4096]; // pointers to dest[]
+ uint16 tokenlengthlist[4096]; // char length of each token
+ uint16 tokenlastlength = 0;
+
+ while (_dwRead < _szPacked || _nBits) {
+ token = getBitsLSB(_numbits);
+
+ if (token == 0x101)
+ return 0; // terminator
+ if (token == 0x100) { // reset command
+ _numbits = 9;
+ _endtoken = 0x1FF;
+ _curtoken = 0x0102;
} else {
- pBuffIn = new Common::MemoryReadStream(buffer, nUnpacked);
- reorderPic(pBuffIn, dest, nUnpacked);
+ if (token > 0xff) {
+ if (token >= _curtoken) {
+ warning("unpackLZW: Bad token %x", token);
+ return SCI_ERROR_DECOMPRESSION_INSANE;
+ }
+ tokenlastlength = tokenlengthlist[token] + 1;
+ if (_dwWrote + tokenlastlength > _szUnpacked) {
+ // 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)",
+ _szUnpacked, _dwWrote, tokenlastlength);
+ for (int i = 0; _dwWrote < _szUnpacked; i++)
+ putByte(dest [tokenlist[token] + i]);
+ } else
+ for (int i = 0; i < tokenlastlength; i++)
+ putByte(dest[tokenlist[token] + i]);
+ } else {
+ tokenlastlength = 1;
+ if (_dwWrote >= _szUnpacked)
+ warning("unpackLZW: Try to write single byte beyond end of array");
+ else
+ putByte(token);
+ }
+ if (_curtoken > _endtoken && _numbits < 12) {
+ _numbits++;
+ _endtoken = (_endtoken << 1) + 1;
+ }
+ if (_curtoken <= _endtoken) {
+ tokenlist[_curtoken] = _dwWrote - tokenlastlength;
+ tokenlengthlist[_curtoken] = tokenlastlength;
+ _curtoken++;
+ }
+
}
- delete[] buffer2;
- delete[] buffer;
- delete pBuff;
- delete pBuffIn;
- break;
}
+
return 0;
}
-int DecompressorComp3::doUnpack(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
+int DecompressorLZW::unpackLZW1(Common::ReadStream *src, byte *dest, uint32 nPacked,
uint32 nUnpacked) {
init(src, dest, nPacked, nUnpacked);
+ byte stak[0x1014];
+ byte lastchar = 0;
+ uint16 stakptr = 0, lastbits = 0;
+ tokenlist tokens[0x1004];
+ memset(tokens, 0, sizeof(tokens));
+
+
byte decryptstart = 0;
uint16 bitstring;
uint16 token;
@@ -194,20 +272,20 @@ int DecompressorComp3::doUnpack(Common::ReadStream *src, Common::WriteStream *de
while (_szUnpacked && !bExit) {
switch (decryptstart) {
case 0:
- bitstring = getBits(_numbits);
+ bitstring = getBitsMSB(_numbits);
if (bitstring == 0x101) {// found end-of-data signal
bExit = true;
continue;
}
putByte(bitstring);
_szUnpacked--;
- _lastbits = bitstring;
- _lastchar = (bitstring & 0xff);
+ lastbits = bitstring;
+ lastchar = (bitstring & 0xff);
decryptstart = 1;
break;
case 1:
- bitstring = getBits(_numbits);
+ bitstring = getBitsMSB(_numbits);
if (bitstring == 0x101) { // found end-of-data signal
bExit = true;
continue;
@@ -222,17 +300,17 @@ int DecompressorComp3::doUnpack(Common::ReadStream *src, Common::WriteStream *de
token = bitstring;
if (token >= _curtoken) { // index past current point
- token = _lastbits;
- _stak[_stakptr++] = _lastchar;
+ token = lastbits;
+ stak[stakptr++] = lastchar;
}
while ((token > 0xff) && (token < 0x1004)) { // follow links back in data
- _stak[_stakptr++] = _tokens[token].data;
- token = _tokens[token].next;
+ stak[stakptr++] = tokens[token].data;
+ token = tokens[token].next;
}
- _lastchar = _stak[_stakptr++] = token & 0xff;
+ lastchar = stak[stakptr++] = token & 0xff;
// put stack in buffer
- while (_stakptr > 0) {
- putByte(_stak[--_stakptr]);
+ while (stakptr > 0) {
+ putByte(stak[--stakptr]);
if (--_szUnpacked == 0) {
bExit = true;
continue;
@@ -240,15 +318,15 @@ int DecompressorComp3::doUnpack(Common::ReadStream *src, Common::WriteStream *de
}
// put token into record
if (_curtoken <= _endtoken) {
- _tokens[_curtoken].data = _lastchar;
- _tokens[_curtoken].next = _lastbits;
+ tokens[_curtoken].data = lastchar;
+ tokens[_curtoken].next = lastbits;
_curtoken++;
- if (_curtoken == _endtoken && _numbits != 12) {
+ if (_curtoken == _endtoken && _numbits < 12) {
_numbits++;
_endtoken = (_endtoken << 1) + 1;
}
}
- _lastbits = bitstring;
+ lastbits = bitstring;
break;
}
}
@@ -259,33 +337,9 @@ int DecompressorComp3::doUnpack(Common::ReadStream *src, Common::WriteStream *de
#define EXTRA_MAGIC_SIZE 15
#define VIEW_HEADER_COLORS_8BIT 0x80
-void DecompressorComp3::decodeRLE(Common::ReadStream *src, Common::WriteStream *dest, byte *pixeldata, uint16 size) {
+void DecompressorLZW::decodeRLE(byte **rledata, byte **pixeldata, byte *outbuffer, int size) {
int pos = 0;
byte nextbyte;
- while (pos < size) {
- nextbyte = src->readByte();
- dest->writeByte(nextbyte);
- pos ++;
- switch (nextbyte & 0xC0) {
- case 0x40:
- case 0x00:
- dest->write(pixeldata, nextbyte);
- pixeldata += nextbyte;
- pos += nextbyte;
- break;
- case 0xC0:
- break;
- case 0x80:
- dest->writeByte(*pixeldata++);
- pos++;
- break;
- }
- }
-}
-
-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;
@@ -322,9 +376,9 @@ void DecompressorComp3::decode_rle(byte **rledata, byte **pixeldata, byte *outbu
*
* Yes, this is inefficient.
*/
-int DecompressorComp3::rle_size(byte *rledata, int dsize) {
+int DecompressorLZW::getRLEsize(byte *rledata, int dsize) {
int pos = 0;
- char nextbyte;
+ byte nextbyte;
int size = 0;
while (pos < dsize) {
@@ -348,54 +402,73 @@ int DecompressorComp3::rle_size(byte *rledata, int dsize) {
return size;
}
-void DecompressorComp3::reorderPic(Common::ReadStream *src, Common::WriteStream *dest, int dsize) {
- int view_size, view_start, cdata_size;
- byte viewdata[7];
- byte *cdata = NULL;
- byte *extra = NULL;
-
- // Setting palette
- dest->writeByte(PIC_OP_OPX);
- dest->writeByte(PIC_OPX_SET_PALETTE);
-
- for (int i = 0; i < 256; i++) // Palette translation map
- dest->writeByte(i);
- dest->writeUint32LE(0); //Palette timestamp
-
- view_size = src->readUint16LE();
- view_start = src->readUint16LE();
- cdata_size = src->readUint16LE();
- src->read(viewdata, sizeof(viewdata));
- // Copy palette colors
- copyBytes(src, dest, 1024);
- // copy drawing opcodes
- if (view_start != PAL_SIZE + 2)
- copyBytes(src, dest, view_start - PAL_SIZE - 2);
- // storing extra opcodes to be pasted after the cel
+void DecompressorLZW::reorderPic(byte *src, byte *dest, int dsize) {
+ uint16 view_size, view_start, cdata_size;
+ int i;
+ byte *seeker = src;
+ byte *writer = dest;
+ char viewdata[7];
+ byte *cdata, *cdata_start;
+
+ *writer++ = PIC_OP_OPX;
+ *writer++ = PIC_OPX_SET_PALETTE;
+
+ for (i = 0; i < 256; i++) /* Palette translation map */
+ *writer++ = i;
+
+ WRITE_LE_UINT32(writer, 0); /* Palette stamp */
+ writer += 4;
+
+ 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) {
- extra = new byte[dsize - view_size - view_start - EXTRA_MAGIC_SIZE];
- src->read(extra, dsize - view_size - view_start - EXTRA_MAGIC_SIZE);
+ memcpy(dest + 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;
}
- // Writing picture cel opcode and header
- dest->writeByte(PIC_OP_OPX);
- dest->writeByte(PIC_OPX_EMBEDDED_VIEW);
- dest->writeByte(0);
- dest->writeUint16LE(0);
- dest->writeUint16LE(view_size + 8);
- dest->write(viewdata, sizeof(viewdata));
- dest->writeByte(0);
- // Unpacking RLE cel data
- cdata = new byte[cdata_size];
- src->read(cdata, cdata_size);
- decodeRLE(src, dest, cdata, view_size);
- // writing stored extra opcodes
- if (extra)
- dest->write(extra, dsize - view_size - view_start - EXTRA_MAGIC_SIZE);
- delete[] extra;
- delete[] cdata;
+
+ cdata_start = cdata = (byte *)malloc(cdata_size);
+ memcpy(cdata, seeker, cdata_size);
+ seeker += cdata_size;
+
+ writer = dest + 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;
+
+ decodeRLE(&seeker, &cdata, writer, view_size);
+
+ free(cdata_start);
}
-void DecompressorComp3::build_cel_headers(byte **seeker, byte **writer, int celindex, int *cc_lengths, int max) {
+void DecompressorLZW::buildCelHeaders(byte **seeker, byte **writer, int celindex, int *cc_lengths, int max) {
for (int c = 0; c < max; c++) {
memcpy(*writer, *seeker, 6);
*seeker += 6;
@@ -409,7 +482,7 @@ void DecompressorComp3::build_cel_headers(byte **seeker, byte **writer, int celi
}
}
-void DecompressorComp3::view_reorder(byte *inbuffer, byte *outbuffer) {
+void DecompressorLZW::reorderView(byte *src, byte *dest) {
byte *cellengths;
int loopheaders;
int lh_present;
@@ -417,9 +490,9 @@ void DecompressorComp3::view_reorder(byte *inbuffer, byte *outbuffer) {
int pal_offset;
int cel_total;
int unknown;
- byte *seeker = inbuffer;
+ byte *seeker = src;
char celcounts[100];
- byte *writer = outbuffer;
+ byte *writer = dest;
byte *lh_ptr;
byte *rle_ptr, *pix_ptr;
int l, lb, c, celindex, lh_last = -1;
@@ -429,7 +502,7 @@ void DecompressorComp3::view_reorder(byte *inbuffer, byte *outbuffer) {
byte **cc_pos;
/* Parse the main header */
- cellengths = inbuffer + READ_LE_UINT16(seeker) + 2;
+ cellengths = src + READ_LE_UINT16(seeker) + 2;
seeker += 2;
loopheaders = *seeker++;
lh_present = *seeker++;
@@ -480,7 +553,7 @@ void DecompressorComp3::view_reorder(byte *inbuffer, byte *outbuffer) {
WRITE_LE_UINT16(lh_ptr, lh_last);
lh_ptr += 2;
} else {
- lh_last = writer - outbuffer;
+ lh_last = writer - dest;
WRITE_LE_UINT16(lh_ptr, lh_last);
lh_ptr += 2;
WRITE_LE_UINT16(writer, celcounts[w]);
@@ -489,16 +562,16 @@ void DecompressorComp3::view_reorder(byte *inbuffer, byte *outbuffer) {
writer += 2;
/* Now, build the cel offset table */
- chptr = (writer - outbuffer) + (2 * celcounts[w]);
+ chptr = (writer - dest) + (2 * celcounts[w]);
for (c = 0; c < celcounts[w]; c++) {
WRITE_LE_UINT16(writer, chptr);
writer += 2;
- cc_pos[celindex+c] = outbuffer + chptr;
+ cc_pos[celindex+c] = dest + chptr;
chptr += 8 + READ_LE_UINT16(cellengths + 2 * (celindex + c));
}
- build_cel_headers(&seeker, &writer, celindex, cc_lengths, celcounts[w]);
+ buildCelHeaders(&seeker, &writer, celindex, cc_lengths, celcounts[w]);
celindex += celcounts[w];
w++;
@@ -514,11 +587,11 @@ void DecompressorComp3::view_reorder(byte *inbuffer, byte *outbuffer) {
/* Figure out where the pixel data begins. */
for (c = 0; c < cel_total; c++)
- pix_ptr += rle_size(pix_ptr, cc_lengths[c]);
+ pix_ptr += getRLEsize(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]);
+ decodeRLE(&rle_ptr, &pix_ptr, cc_pos[c] + 8, cc_lengths[c]);
*writer++ = 'P';
*writer++ = 'A';
@@ -535,109 +608,6 @@ void DecompressorComp3::view_reorder(byte *inbuffer, byte *outbuffer) {
}
//----------------------------------------------
-// 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 *buffout = new byte[nUnpacked];
- int error = unpackLZW(buffout);
- dest->write(buffout, nUnpacked);
- delete[] buffout;
- return error;
-}
-
-void DecompressorLZW::fetchBits() {
- while (_nBits <= 24) {
- _dwBits |= ((uint32)_src->readByte()) << (_nBits);
- _nBits += 8;
- _dwRead++;
- }
-}
-
-uint32 DecompressorLZW::getBits(int n) {
- if (_nBits < n)
- fetchBits();
- uint32 ret = (_dwBits & ~((~0) << n));
- _dwBits >>= n;
- _nBits -= n;
- return ret;
-}
-int DecompressorLZW::unpackLZW(byte *dest) {
- uint16 bitlen = 9; // no. of bits to read (max. 12)
- 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;
- uint32 destctr = 0;
-
- while (_dwRead < _szPacked || _nBits) {
- token = getBits(bitlen);
-
- if (token == 0x101)
- return 0; // terminator
- if (token == 0x100) { // reset command
- maxtoken = 0x200;
- bitlen = 9;
- 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 > _szUnpacked) {
-#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)",
- _szUnpacked, destctr, tokenlastlength);
-#endif
- i = 0;
- for (; destctr < _szUnpacked; 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 >= _szUnpacked) {
-#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++;
- 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
@@ -660,51 +630,19 @@ static int ascii_tree[] = {
0 // We need something witout a comma at the end
};
-int DecompressorDCL::unpack(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
+int DecompressorDCL::unpack(Common::ReadStream *src, byte *dest, uint32 nPacked,
uint32 nUnpacked) {
init(src, dest, nPacked, nUnpacked);
-
- byte *buffout = new byte[nUnpacked];
- int error = unpackDCL(buffout);
- dest->write(buffout, nUnpacked);
- delete[] buffout;
- return error;
+ return unpackDCL(dest);
}
-void DecompressorDCL::fetchBits() {
- while (_nBits <= 24) {
- _dwBits |= ((uint32)_src->readByte()) << _nBits;
- _nBits += 8;
- _dwRead++;
- }
-}
-
-bool DecompressorDCL::getBit() {
- // fetching more bits to _dwBits buffer
- if (_nBits == 0)
- fetchBits();
- bool b = _dwBits & 0x1;
- _dwBits >>= 1;
- _nBits--;
- return b;
-}
-
-uint32 DecompressorDCL::getBits(int n) {
- // fetching more data to buffer if needed
- if (_nBits < n)
- fetchBits();
- uint32 ret = (_dwBits & ~((~0) << n));
- _dwBits >>= n;
- _nBits -= n;
- return ret;
-}
int DecompressorDCL::huffman_lookup(int *tree) {
int pos = 0;
int bit;
while (!(tree[pos] & HUFFMAN_LEAF)) {
- bit = getBit();
+ bit = getBitLSB();
debugC(kDebugLevelDclInflate, "[%d]:%d->", pos, bit);
pos = bit ? tree[pos] & 0xFFF : tree[pos] >> BRANCH_SHIFT;
}
@@ -718,8 +656,8 @@ int DecompressorDCL::unpackDCL(byte* dest) {
int mode, length_param, value;
uint32 write_pos = 0, val_distance, val_length;
- mode = getByte();
- length_param = getByte();
+ mode = getByteLSB();
+ length_param = getByteLSB();
if (mode == DCL_ASCII_MODE) {
warning("DCL-INFLATE: Decompressing ASCII mode (untested)");
@@ -732,22 +670,22 @@ int DecompressorDCL::unpackDCL(byte* dest) {
warning("Unexpected length_param value %d (expected in [3,6])\n", length_param);
while (write_pos < _szUnpacked) {
- if (getBit()) { // (length,distance) pair
+ if (getBitLSB()) { // (length,distance) pair
value = huffman_lookup(length_tree);
if (value < 8)
val_length = value + 2;
else
- val_length = 8 + (1 << (value - 7)) + getBits(value - 7);
+ val_length = 8 + (1 << (value - 7)) + getBitsLSB(value - 7);
debugC(kDebugLevelDclInflate, " | ");
value = huffman_lookup(distance_tree);
if (val_length == 2)
- val_distance = (value << 2) | getBits(2);
+ val_distance = (value << 2) | getBitsLSB(2);
else
- val_distance = (value << length_param) | getBits(length_param);
+ val_distance = (value << length_param) | getBitsLSB(length_param);
val_distance ++;
debugC(kDebugLevelDclInflate, "\nCOPY(%d from %d)\n", val_length, val_distance);
@@ -779,7 +717,7 @@ int DecompressorDCL::unpackDCL(byte* dest) {
}
} else { // Copy byte verbatim
- value = (mode == DCL_ASCII_MODE) ? huffman_lookup(ascii_tree) : getByte();
+ value = (mode == DCL_ASCII_MODE) ? huffman_lookup(ascii_tree) : getByteLSB();
dest[write_pos++] = value;
debugC(kDebugLevelDclInflate, "\33[32;31m%02x \33[37;37m", value);
}
@@ -788,4 +726,14 @@ int DecompressorDCL::unpackDCL(byte* dest) {
return 0;
}
+//----------------------------------------------
+// STACpack decompressor for SCI32
+//----------------------------------------------
+int DecompressorLZS::unpack(Common::ReadStream *src, byte *dest, uint32 nPacked, uint32 nUnpacked) {
+ // TODO : Implement LZS decompression
+ // (from RFC1974 and http://micky.ibh.de/~beck/stuff/lzs4i4l/isdn_lzscomp.c)
+ warning("LZS decompression not yet implemented");
+ return SCI_ERROR_UNKNOWN_COMPRESSION;
+}
+
} // End of namespace Sci
diff --git a/engines/sci/scicore/decompressor.h b/engines/sci/scicore/decompressor.h
index ac42fd6867..5d54212a95 100644
--- a/engines/sci/scicore/decompressor.h
+++ b/engines/sci/scicore/decompressor.h
@@ -34,9 +34,9 @@ enum ResourceCompression {
kCompNone = 0,
kCompLZW,
kCompHuffman,
- kComp3, // LZW-like compression used in SCI01 and SCI1
- kComp3View, // Comp3 + view Post-processing
- kComp3Pic, // Comp3 + pic Post-processing
+ kCompLZW1, // LZW-like compression used in SCI01 and SCI1
+ kCompLZW1View, // Comp3 + view Post-processing
+ kCompLZW1Pic, // Comp3 + pic Post-processing
kCompDCL,
kCompSTACpack // ? Used in SCI32
};
@@ -48,13 +48,7 @@ class Decompressor {
public:
Decompressor() {}
virtual ~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);
+ virtual int unpack(Common::ReadStream *src, byte *dest, uint32 nPacked, uint32 nUnpacked);
protected:
//! Initialize decompressor
@@ -64,34 +58,40 @@ protected:
@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
+ virtual void init(Common::ReadStream *src, byte *dest, uint32 nPacked, uint32 nUnpacked);
+ //! get one bit from _src stream
/** @return (bool) bit;
*/
- virtual bool getBit();
+ bool getBitMSB();
+ bool getBitLSB();
//! 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);
+ uint32 getBitsMSB(int n);
+ uint32 getBitsLSB(int n);
+ //! get one byte from _src stream
+ /** @return (byte) byte
+ */
+ byte getByteMSB();
+ byte getByteLSB();
+
+ void fetchBitsMSB();
+ void fetchBitsLSB();
+
//! put byte to _dest stream
/** @param b - byte to put
*/
- virtual byte getByte();
virtual void putByte(byte b);
- virtual void fetchBits();
- int copyBytes(Common::ReadStream *src, Common::WriteStream *dest, uint32 nSize);
-
- uint32 _dwBits;
- byte _nBits;
+ uint32 _dwBits; // bits buffer
+ byte _nBits; // # of bits in buffer
uint32 _szPacked;
uint32 _szUnpacked;
- uint32 _dwRead;
+ uint32 _dwRead; // # of bytes read from _src
uint32 _dwWrote;
-
Common::ReadStream *_src;
- Common::WriteStream *_dest;
+ byte *_dest;
};
//----------------------------------------------
@@ -99,8 +99,7 @@ protected:
//----------------------------------------------
class DecompressorHuffman : public Decompressor {
public:
- int unpack(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
- uint32 nUnpacked);
+ int unpack(Common::ReadStream *src, byte *dest, uint32 nPacked, uint32 nUnpacked);
protected:
int16 getc2();
@@ -112,14 +111,13 @@ protected:
// LZW-like decompressor for SCI01/SCI1
// TODO: Needs clean-up of post-processing fncs
//----------------------------------------------
-class DecompressorComp3 : public Decompressor {
+class DecompressorLZW : public Decompressor {
public:
- DecompressorComp3(int nCompression) {
+ DecompressorLZW(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);
+ void init(Common::ReadStream *src, byte *dest, uint32 nPacked, uint32 nUnpacked);
+ int unpack(Common::ReadStream *src, byte *dest, uint32 nPacked, uint32 nUnpacked);
protected:
enum {
@@ -127,64 +125,47 @@ protected:
PIC_OPX_SET_PALETTE = 2,
PIC_OP_OPX = 0xfe
};
- // actual unpacking procedure
- int doUnpack(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
- uint32 nUnpacked);
+ // unpacking procedures
+ // TODO: unpackLZW and unpackLZW1 are similar and should be merged
+ int unpackLZW1(Common::ReadStream *src, byte *dest, uint32 nPacked, uint32 nUnpacked);
+ int unpackLZW(Common::ReadStream *src, byte *dest, uint32 nPacked, uint32 nUnpacked);
+
// functions to post-process view and pic resources
- void decodeRLE(Common::ReadStream *src, Common::WriteStream *dest, byte *pixeldata, uint16 size);
- void reorderPic(Common::ReadStream *src, Common::WriteStream *dest, int dsize);
- //
- void decode_rle(byte **rledata, byte **pixeldata, byte *outbuffer, int size);
- int rle_size(byte *rledata, int dsize);
- void build_cel_headers(byte **seeker, byte **writer, int celindex, int *cc_lengths, int max);
- void view_reorder(byte *inbuffer, byte *outbuffer);
+ void reorderPic(byte *src, byte *dest, int dsize);
+ void reorderView(byte *src, byte *dest);
+ void decodeRLE(byte **rledata, byte **pixeldata, byte *outbuffer, int size);
+ int getRLEsize(byte *rledata, int dsize);
+ void buildCelHeaders(byte **seeker, byte **writer, int celindex, int *cc_lengths, int max);
+
// decompressor data
struct tokenlist {
byte data;
uint16 next;
- } _tokens[0x1004];
- byte _stak[0x1014];
- byte _lastchar;
- uint16 _stakptr;
- uint16 _numbits, _lastbits;
+ };
+ uint16 _numbits;
uint16 _curtoken, _endtoken;
int _compression;
};
//----------------------------------------------
-// LZW 9-12 bits decompressor for SCI0
-// TODO : Needs clean-up of doUnpack()
-//----------------------------------------------
-class DecompressorLZW : public Decompressor {
-public:
- int unpack(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
- uint32 nUnpacked);
-
-protected:
- int unpackLZW(byte *dest);
-
- void fetchBits();
- uint32 getBits(int n);
-};
-
-//----------------------------------------------
// DCL decompressor for SCI1.1
-// TODO : Needs clean-up of doUnpack()
//----------------------------------------------
class DecompressorDCL : public Decompressor {
public:
- int unpack(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
- uint32 nUnpacked);
+ int unpack(Common::ReadStream *src, byte *dest, uint32 nPacked, uint32 nUnpacked);
protected:
int unpackDCL(byte *dest);
int huffman_lookup(int *tree);
-
- void fetchBits();
- bool getBit();
- uint32 getBits(int n);
};
+//----------------------------------------------
+// STACpack decompressor for SCI32
+//----------------------------------------------
+class DecompressorLZS : public Decompressor {
+public:
+ int unpack(Common::ReadStream *src, byte *dest, uint32 nPacked, uint32 nUnpacked);
+};
} // End of namespace Sci
#endif // SCI_SCICORE_DECOMPRESSOR_H
diff --git a/engines/sci/scicore/resource.cpp b/engines/sci/scicore/resource.cpp
index 533aa51e2a..810cd8f150 100644
--- a/engines/sci/scicore/resource.cpp
+++ b/engines/sci/scicore/resource.cpp
@@ -1046,7 +1046,7 @@ int ResourceManager::readResourceInfo(Resource *res, Common::File *file,
wCompression = file->readUint16LE();
break;
case SCI_VERSION_32:
- type = (ResourceType)file->readByte();
+ type = (ResourceType)(file->readByte() &0x7F);
number = file->readUint16LE();
szPacked = file->readUint32LE();
szUnpacked = file->readUint32LE();
@@ -1063,36 +1063,29 @@ int ResourceManager::readResourceInfo(Resource *res, Common::File *file,
res->number = number;
res->size = szUnpacked;
// checking compression method
- if (wCompression == 0)
+ switch (wCompression) {
+ case 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;
+ case 1:
+ compression = (_sciVersion == SCI_VERSION_0) ? kCompLZW : kCompHuffman;
break;
- case SCI_VERSION_1_1:
- if (wCompression >= 18 && wCompression <= 20)
- compression = kCompDCL;
+ case 2:
+ compression = (_sciVersion == SCI_VERSION_0) ? kCompHuffman : kCompLZW1;
break;
- case SCI_VERSION_32:
- if (wCompression == 32)
- compression = kCompSTACpack;
+ case 3:
+ compression = kCompLZW1View;
+ break;
+ case 4:
+ compression = kCompLZW1Pic;
+ break;
+ case 18:
+ case 19:
+ case 20:
+ compression = kCompDCL;
+ break;
+ case 32:
+ compression = kCompSTACpack;
break;
default:
compression = kCompUnknown;
@@ -1104,7 +1097,6 @@ int ResourceManager::readResourceInfo(Resource *res, Common::File *file,
int ResourceManager::decompress(Resource *res, Common::File *file) {
int error;
uint32 szPacked = 0;
- Common::MemoryWriteStream *pDest = NULL;
ResourceCompression compression = kCompUnknown;
// fill resource info
@@ -1117,43 +1109,34 @@ int ResourceManager::decompress(Resource *res, Common::File *file) {
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);
+ case kCompLZW:
+ case kCompLZW1:
+ case kCompLZW1View:
+ case kCompLZW1Pic:
+ dec = new DecompressorLZW(compression);
break;
case kCompDCL:
dec = new DecompressorDCL;
break;
+ case kCompSTACpack:
+ dec = new DecompressorLZS;
+ break;
default:
warning("Resource %s #%d: Compression method %d not supported",
getResourceTypeName(res->type), res->number, compression);
- break;
+ return SCI_ERROR_UNKNOWN_COMPRESSION;
}
- 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;
+ res->data = new byte[res->size];
+ res->status = kResStatusAllocated;
+ error = res->data ? dec->unpack(file, res->data, szPacked, res->size) : SCI_ERROR_RESOURCE_TOO_BIG;
+ if (error)
+ res->unalloc();
- if (!error)
- res->status = kResStatusAllocated;
- else {
- delete res->data;
- res->data = 0;
- res->status = kResStatusNoMalloc;
- }
delete dec;
- delete pDest;
-
return error;
}