aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Frieger2009-03-11 04:38:54 +0000
committerGreg Frieger2009-03-11 04:38:54 +0000
commit17664dce40ddc2c7a12579383760df5df8a49fcc (patch)
treea90d9f61d5a69dffa0af4afdc6546516c81ae135
parent862c9547c6580dece7e0d1f12707ccb0a97f5dda (diff)
downloadscummvm-rg350-17664dce40ddc2c7a12579383760df5df8a49fcc.tar.gz
scummvm-rg350-17664dce40ddc2c7a12579383760df5df8a49fcc.tar.bz2
scummvm-rg350-17664dce40ddc2c7a12579383760df5df8a49fcc.zip
More clean-ups in decompression classes
svn-id: r39329
-rw-r--r--engines/sci/scicore/decompressor.cpp244
-rw-r--r--engines/sci/scicore/decompressor.h15
-rw-r--r--engines/sci/scicore/resource.cpp4
3 files changed, 101 insertions, 162 deletions
diff --git a/engines/sci/scicore/decompressor.cpp b/engines/sci/scicore/decompressor.cpp
index 1bb83bf1d2..2214265e40 100644
--- a/engines/sci/scicore/decompressor.cpp
+++ b/engines/sci/scicore/decompressor.cpp
@@ -31,6 +31,7 @@
#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,
@@ -88,6 +89,10 @@ uint32 Decompressor::getBits(int n) {
return ret;
}
+byte Decompressor::getByte() {
+ return getBits(8);
+}
+
void Decompressor::putByte(byte b) {
_dest->writeByte(b);
_dwWrote++;
@@ -122,7 +127,7 @@ int16 DecompressorHuffman::getc2() {
if (getBit()) {
next = node[1] & 0x0F; // use lower 4 bits
if (next == 0)
- return getBits(8) | 0x100;
+ return getByte() | 0x100;
} else
next = node[1] >> 4; // use higher 4 bits
node += next << 1;
@@ -285,10 +290,10 @@ void DecompressorComp3::decode_rle(byte **rledata, byte **pixeldata, byte *outbu
byte *pd = *pixeldata;
while (pos < size) {
- nextbyte = *(rd++);
- *(ob++) = nextbyte;
+ nextbyte = *rd++;
+ *ob++ = nextbyte;
pos++;
- switch (nextbyte&0xC0) {
+ switch (nextbyte & 0xC0) {
case 0x40 :
case 0x00 :
memcpy(ob, pd, nextbyte);
@@ -299,8 +304,8 @@ void DecompressorComp3::decode_rle(byte **rledata, byte **pixeldata, byte *outbu
case 0xC0 :
break;
case 0x80 :
- nextbyte = *(pd++);
- *(ob++) = nextbyte;
+ nextbyte = *pd++;
+ *ob++ = nextbyte;
pos++;
break;
}
@@ -425,8 +430,8 @@ void DecompressorComp3::view_reorder(byte *inbuffer, byte *outbuffer) {
/* Parse the main header */
cellengths = inbuffer + READ_LE_UINT16(seeker) + 2;
seeker += 2;
- loopheaders = *(seeker++);
- lh_present = *(seeker++);
+ loopheaders = *seeker++;
+ lh_present = *seeker++;
lh_mask = READ_LE_UINT16(seeker);
seeker += 2;
unknown = READ_LE_UINT16(seeker);
@@ -534,62 +539,51 @@ void DecompressorComp3::view_reorder(byte *inbuffer, byte *outbuffer) {
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);
-
+ int error = unpackLZW(buffout);
dest->write(buffout, nUnpacked);
- delete[] buffin;
delete[] buffout;
- return 0;
+ return error;
+}
+
+void DecompressorLZW::fetchBits() {
+ while (_nBits <= 24) {
+ _dwBits |= ((uint32)_src->readByte()) << (_nBits);
+ _nBits += 8;
+ _dwRead++;
+ }
}
-int DecompressorLZW::doUnpack(byte *src, byte *dest, int length, int complength) {
+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 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;
+ uint32 destctr = 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++;
- }
+ while (_dwRead < _szPacked || _nBits) {
+ token = getBits(bitlen);
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
@@ -599,14 +593,14 @@ int DecompressorLZW::doUnpack(byte *src, byte *dest, int length, int complength)
// May be it should throw something like SCI_ERROR_DECOMPRESSION_INSANE
} else {
tokenlastlength = tokenlengthlist[token] + 1;
- if (destctr + tokenlastlength > length) {
+ 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)",
- length, destctr, tokenlastlength);
+ _szUnpacked, destctr, tokenlastlength);
#endif
i = 0;
- for (; destctr < length; destctr++) {
+ for (; destctr < _szUnpacked; destctr++) {
dest[destctr++] = dest [tokenlist[token] + i];
i++;
}
@@ -617,7 +611,7 @@ int DecompressorLZW::doUnpack(byte *src, byte *dest, int length, int complength)
}
} else {
tokenlastlength = 1;
- if (destctr >= length) {
+ if (destctr >= _szUnpacked) {
#ifdef _SCI_DECOMPRESS_DEBUG
warning("unpackLZW: Try to write single byte beyond end of array");
#endif
@@ -630,8 +624,6 @@ int DecompressorLZW::doUnpack(byte *src, byte *dest, int length, int complength)
if (tokenctr == maxtoken) {
if (bitlen < 12) {
bitlen++;
- bitmask <<= 1;
- bitmask |= 1;
maxtoken <<= 1;
} else
continue; // no further tokens allowed
@@ -641,7 +633,6 @@ int DecompressorLZW::doUnpack(byte *src, byte *dest, int length, int complength)
tokenlengthlist[tokenctr++] = tokenlastlength;
}
}
-
return 0;
}
@@ -649,19 +640,10 @@ int DecompressorLZW::doUnpack(byte *src, byte *dest, int length, int complength)
// 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
@@ -677,80 +659,66 @@ static int ascii_tree[] = {
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);
+ byte *buffout = new byte[nUnpacked];
+ int error = unpackDCL(buffout);
dest->write(buffout, nUnpacked);
- delete[] buffin;
delete[] buffout;
- return 0;
+ return error;
}
-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;
+void DecompressorDCL::fetchBits() {
+ while (_nBits <= 24) {
+ _dwBits |= ((uint32)_src->readByte()) << _nBits;
+ _nBits += 8;
+ _dwRead++;
}
+}
- 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);
+bool DecompressorDCL::getBit() {
+ // fetching more bits to _dwBits buffer
+ if (_nBits == 0)
+ fetchBits();
+ bool b = _dwBits & 0x1;
+ _dwBits >>= 1;
+ _nBits--;
+ return b;
+}
- return result;
+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(struct bit_read_struct *inp, int *tree) {
+int DecompressorDCL::huffman_lookup(int *tree) {
int pos = 0;
int bit;
while (!(tree[pos] & HUFFMAN_LEAF)) {
- CALLC(bit = getbits(inp, 1));
+ bit = getBit();
debugC(kDebugLevelDclInflate, "[%d]:%d->", pos, bit);
- if (bit)
- pos = tree[pos] & ~(~0 << BRANCH_SHIFT);
- else
- pos = tree[pos] >> BRANCH_SHIFT;
+ pos = bit ? tree[pos] & 0xFFF : tree[pos] >> BRANCH_SHIFT;
}
debugC(kDebugLevelDclInflate, "=%02x\n", tree[pos] & 0xffff);
- return 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;
+int DecompressorDCL::unpackDCL(byte* dest) {
+ int mode, length_param, value;
+ uint32 write_pos = 0, val_distance, val_length;
- CALLC(mode = getbits(&reader, 8));
- CALLC(length_param = getbits(&reader, 8));
+ mode = getByte();
+ length_param = getByte();
if (mode == DCL_ASCII_MODE) {
warning("DCL-INFLATE: Decompressing ASCII mode (untested)");
@@ -759,57 +727,31 @@ int DecompressorDCL::unpackDCL(uint8* src, uint8* dest, int length, int compleng
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));
+ while (write_pos < _szUnpacked) {
+ if (getBit()) { // (length,distance) pair
+ value = huffman_lookup(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;
- }
+ else
+ val_length = 8 + (1 << (value - 7)) + getBits(value - 7);
debugC(kDebugLevelDclInflate, " | ");
- CALLC(value = huffman_lookup(&reader, distance_tree));
-
- if (val_length == 2) {
- val_distance = value << 2;
+ value = huffman_lookup(distance_tree);
- 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;
+ if (val_length == 2)
+ val_distance = (value << 2) | getBits(2);
+ else
+ val_distance = (value << length_param) | getBits(length_param);
+ val_distance ++;
debugC(kDebugLevelDclInflate, "\nCOPY(%d from %d)\n", val_length, val_distance);
- if (val_length + write_pos > length) {
+ if (val_length + write_pos > _szUnpacked) {
warning("DCL-INFLATE Error: Write out of bounds while copying %d bytes", val_length);
return SCI_ERROR_DECOMPRESSION_OVERFLOW;
}
@@ -820,12 +762,12 @@ int DecompressorDCL::unpackDCL(uint8* src, uint8* dest, int length, int compleng
}
while (val_length) {
- int copy_length = (val_length > val_distance) ? val_distance : 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);
if (Common::isDebugChannelEnabled(kDebugLevelDclInflate)) {
- for (int i = 0; i < copy_length; i++)
+ for (uint32 i = 0; i < copy_length; i++)
debugC(kDebugLevelDclInflate, "\33[32;31m%02x\33[37;37m ", dest[write_pos + i]);
debugC(kDebugLevelDclInflate, "\n");
}
@@ -836,14 +778,8 @@ int DecompressorDCL::unpackDCL(uint8* src, uint8* dest, int length, int compleng
}
} else { // Copy byte verbatim
- if (mode == DCL_ASCII_MODE) {
- CALLC(value = huffman_lookup(&reader, ascii_tree));
- } else {
- CALLC(value = getbits(&reader, 8));
- }
-
+ value = (mode == DCL_ASCII_MODE) ? huffman_lookup(ascii_tree) : getByte();
dest[write_pos++] = value;
-
debugC(kDebugLevelDclInflate, "\33[32;31m%02x \33[37;37m", value);
}
}
diff --git a/engines/sci/scicore/decompressor.h b/engines/sci/scicore/decompressor.h
index b5493d2630..ac42fd6867 100644
--- a/engines/sci/scicore/decompressor.h
+++ b/engines/sci/scicore/decompressor.h
@@ -77,6 +77,7 @@ protected:
//! 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);
@@ -156,13 +157,14 @@ protected:
//----------------------------------------------
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);
+ int unpackLZW(byte *dest);
+ void fetchBits();
+ uint32 getBits(int n);
};
//----------------------------------------------
@@ -171,15 +173,16 @@ protected:
//----------------------------------------------
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);
+ int unpackDCL(byte *dest);
+ int huffman_lookup(int *tree);
+ void fetchBits();
+ bool getBit();
+ uint32 getBits(int n);
};
} // End of namespace Sci
diff --git a/engines/sci/scicore/resource.cpp b/engines/sci/scicore/resource.cpp
index 2658648d5e..dba8ad1a7e 100644
--- a/engines/sci/scicore/resource.cpp
+++ b/engines/sci/scicore/resource.cpp
@@ -990,14 +990,14 @@ int ResourceManager::readResourceInfo(Resource *res, Common::File *file,
wCompression = file->readUint16LE();
break;
case SCI_VERSION_1:
- type = (ResourceType)file->readByte();
+ type = (ResourceType)(file->readByte() & 0x7F);
number = file->readUint16LE();
szPacked = file->readUint16LE() - 4;
szUnpacked = file->readUint16LE();
wCompression = file->readUint16LE();
break;
case SCI_VERSION_1_1:
- type = (ResourceType)file->readByte();
+ type = (ResourceType)(file->readByte() & 0x7F);
number = file->readUint16LE();
szPacked = file->readUint16LE();
szUnpacked = file->readUint16LE();