aboutsummaryrefslogtreecommitdiff
path: root/engines/sci
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci')
-rw-r--r--engines/sci/scicore/decompressor.cpp110
-rw-r--r--engines/sci/scicore/decompressor.h12
2 files changed, 98 insertions, 24 deletions
diff --git a/engines/sci/scicore/decompressor.cpp b/engines/sci/scicore/decompressor.cpp
index 836d023514..2f146edcb5 100644
--- a/engines/sci/scicore/decompressor.cpp
+++ b/engines/sci/scicore/decompressor.cpp
@@ -8,7 +8,7 @@
* 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
@@ -136,11 +136,11 @@ int DecompressorHuffman::unpack(Common::ReadStream *src, byte *dest, uint32 nPac
_nodes = new byte [numnodes << 1];
_src->read(_nodes, numnodes << 1);
- while ((c = getc2()) != terminator && (c >= 0) && (_szUnpacked-- > 0))
+ while ((c = getc2()) != terminator && (c >= 0) && !isFinished())
putByte(c);
delete[] _nodes;
- return _dwWrote ? 0 : 1;
+ return _dwWrote == _szUnpacked ? 0 : 1;
}
int16 DecompressorHuffman::getc2() {
@@ -205,7 +205,7 @@ int DecompressorLZW::unpackLZW(Common::ReadStream *src, byte *dest, uint32 nPack
uint16 tokenlengthlist[4096]; // char length of each token
uint16 tokenlastlength = 0;
- while (_dwRead < _szPacked || _nBits) {
+ while (!isFinished()) {
token = getBitsLSB(_numbits);
if (token == 0x101)
@@ -250,7 +250,7 @@ int DecompressorLZW::unpackLZW(Common::ReadStream *src, byte *dest, uint32 nPack
}
}
- return 0;
+ return _dwWrote == _szUnpacked ? 0 : SCI_ERROR_DECOMPRESSION_INSANE;
}
int DecompressorLZW::unpackLZW1(Common::ReadStream *src, byte *dest, uint32 nPacked,
@@ -269,7 +269,7 @@ int DecompressorLZW::unpackLZW1(Common::ReadStream *src, byte *dest, uint32 nPac
uint16 token;
bool bExit = false;
- while (_szUnpacked && !bExit) {
+ while (!isFinished() && !bExit) {
switch (decryptstart) {
case 0:
bitstring = getBitsMSB(_numbits);
@@ -278,7 +278,6 @@ int DecompressorLZW::unpackLZW1(Common::ReadStream *src, byte *dest, uint32 nPac
continue;
}
putByte(bitstring);
- _szUnpacked--;
lastbits = bitstring;
lastchar = (bitstring & 0xff);
decryptstart = 1;
@@ -311,7 +310,7 @@ int DecompressorLZW::unpackLZW1(Common::ReadStream *src, byte *dest, uint32 nPac
// put stack in buffer
while (stakptr > 0) {
putByte(stak[--stakptr]);
- if (--_szUnpacked == 0) {
+ if (_dwWrote == _szUnpacked) {
bExit = true;
continue;
}
@@ -330,7 +329,7 @@ int DecompressorLZW::unpackLZW1(Common::ReadStream *src, byte *dest, uint32 nPac
break;
}
}
- return _dwWrote ? 0 : 1;
+ return _dwWrote == _szUnpacked ? 0 : SCI_ERROR_DECOMPRESSION_INSANE;
}
#define PAL_SIZE 1284
@@ -654,7 +653,7 @@ int DecompressorDCL::huffman_lookup(int *tree) {
int DecompressorDCL::unpackDCL(byte* dest) {
int mode, length_param, value;
- uint32 write_pos = 0, val_distance, val_length;
+ uint32 val_distance, val_length;
mode = getByteLSB();
length_param = getByteLSB();
@@ -669,7 +668,7 @@ int DecompressorDCL::unpackDCL(byte* dest) {
if (length_param < 3 || length_param > 6)
warning("Unexpected length_param value %d (expected in [3,6])\n", length_param);
- while (write_pos < _szUnpacked) {
+ while (_dwWrote < _szUnpacked) {
if (getBitLSB()) { // (length,distance) pair
value = huffman_lookup(length_tree);
@@ -690,12 +689,12 @@ int DecompressorDCL::unpackDCL(byte* dest) {
debugC(kDebugLevelDclInflate, "\nCOPY(%d from %d)\n", val_length, val_distance);
- if (val_length + write_pos > _szUnpacked) {
+ if (val_length + _dwWrote > _szUnpacked) {
warning("DCL-INFLATE Error: Write out of bounds while copying %d bytes", val_length);
return SCI_ERROR_DECOMPRESSION_OVERFLOW;
}
- if (write_pos < val_distance) {
+ if (_dwWrote < val_distance) {
warning("DCL-INFLATE Error: Attempt to copy from before beginning of input stream");
return SCI_ERROR_DECOMPRESSION_INSANE;
}
@@ -703,37 +702,102 @@ int DecompressorDCL::unpackDCL(byte* dest) {
while (val_length) {
uint32 copy_length = (val_length > val_distance) ? val_distance : val_length;
assert(val_distance >= copy_length);
- memcpy(dest + write_pos, dest + write_pos - val_distance, copy_length);
+ uint32 pos = _dwWrote - val_distance;
+ for (uint32 i = 0; i < copy_length; i++)
+ putByte(dest[pos + i]);
if (Common::isDebugChannelEnabled(kDebugLevelDclInflate)) {
for (uint32 i = 0; i < copy_length; i++)
- debugC(kDebugLevelDclInflate, "\33[32;31m%02x\33[37;37m ", dest[write_pos + i]);
+ debugC(kDebugLevelDclInflate, "\33[32;31m%02x\33[37;37m ", dest[pos + i]);
debugC(kDebugLevelDclInflate, "\n");
}
val_length -= copy_length;
val_distance += copy_length;
- write_pos += copy_length;
}
} else { // Copy byte verbatim
value = (mode == DCL_ASCII_MODE) ? huffman_lookup(ascii_tree) : getByteLSB();
- dest[write_pos++] = value;
+ putByte(value);
debugC(kDebugLevelDclInflate, "\33[32;31m%02x \33[37;37m", value);
}
}
- return 0;
+ return _dwWrote == _szUnpacked ? 0 : SCI_ERROR_DECOMPRESSION_INSANE;
}
//----------------------------------------------
-// STACpack decompressor for SCI32
+// STACpack/LZS decompressor for SCI32
+// Based on Andre Beck's code from http://micky.ibh.de/~beck/stuff/lzs4i4l/
//----------------------------------------------
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;
+ init(src, dest, nPacked, nUnpacked);
+ return unpackLZS();
+}
+
+int DecompressorLZS::unpackLZS() {
+ uint16 offs = 0, clen;
+
+ while (!isFinished()) {
+ if (getBitMSB()) { // Compressed bytes follow
+ if (getBitMSB()) { // Seven bit offset follows
+ offs = getBitsMSB(7);
+ if (!offs) // This is the end marker - a 7 bit offset of zero
+ break;
+ if (!(clen = getCompLen())) {
+ warning("lzsDecomp: length mismatch");
+ return SCI_ERROR_DECOMPRESSION_INSANE;
+ }
+ copyComp(offs, clen);
+ } else { // Eleven bit offset follows
+ offs = getBitsMSB(11);
+ if (!(clen = getCompLen())) {
+ warning("lzsDecomp: length mismatch");
+ return SCI_ERROR_DECOMPRESSION_INSANE;
+ }
+ copyComp(offs, clen);
+ }
+ } else // Literal byte follows
+ putByte(getByteMSB());
+ } // end of while ()
+ return _dwWrote == _szUnpacked ? 0 : SCI_ERROR_DECOMPRESSION_INSANE;
+}
+
+uint16 DecompressorLZS::getCompLen() {
+ int clen, nibble;
+ // The most probable cases are hardcoded
+ switch (getBitsMSB(2)) {
+ case 0:
+ return 2;
+ case 1:
+ return 3;
+ case 2:
+ return 4;
+ default:
+ switch (getBitsMSB(2)) {
+ case 0:
+ return 5;
+ case 1:
+ return 6;
+ case 2:
+ return 7;
+ default:
+ // Ok, no shortcuts anymore - just get nibbles and add up
+ clen = 8;
+ do {
+ nibble = getBitsMSB(4);
+ clen += nibble;
+ }while (nibble == 0xf);
+ return clen;
+ }
+ }
+}
+
+void DecompressorLZS::copyComp(int offs, int clen) {
+ int hpos = _dwWrote - offs;
+
+ while (clen--)
+ putByte(_dest[hpos++]);
}
} // End of namespace Sci
diff --git a/engines/sci/scicore/decompressor.h b/engines/sci/scicore/decompressor.h
index 5d54212a95..c471b41cec 100644
--- a/engines/sci/scicore/decompressor.h
+++ b/engines/sci/scicore/decompressor.h
@@ -77,12 +77,17 @@ protected:
byte getByteLSB();
void fetchBitsMSB();
- void fetchBitsLSB();
+ void fetchBitsLSB();
//! put byte to _dest stream
/** @param b - byte to put
*/
virtual void putByte(byte b);
+ // Returns true if all expected data has been unpacked to _dest
+ // and there is no more data in _src
+ bool isFinished() {
+ return (_dwWrote == _szUnpacked) && (_dwRead >= _szPacked);
+ }
uint32 _dwBits; // bits buffer
byte _nBits; // # of bits in buffer
@@ -165,7 +170,12 @@ protected:
class DecompressorLZS : public Decompressor {
public:
int unpack(Common::ReadStream *src, byte *dest, uint32 nPacked, uint32 nUnpacked);
+protected:
+ int unpackLZS();
+ uint16 getCompLen();
+ void copyComp(int offs, int clen);
};
+
} // End of namespace Sci
#endif // SCI_SCICORE_DECOMPRESSOR_H