diff options
Diffstat (limited to 'engines/sci/scicore')
-rw-r--r-- | engines/sci/scicore/decompressor.cpp | 550 | ||||
-rw-r--r-- | engines/sci/scicore/decompressor.h | 117 | ||||
-rw-r--r-- | engines/sci/scicore/resource.cpp | 85 |
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; } |