[Scummvm-cvs-logs] SF.net SVN: scummvm:[39383] scummvm/trunk/engines/sci/scicore

gregfrieger at users.sourceforge.net gregfrieger at users.sourceforge.net
Sat Mar 14 05:17:03 CET 2009


Revision: 39383
          http://scummvm.svn.sourceforge.net/scummvm/?rev=39383&view=rev
Author:   gregfrieger
Date:     2009-03-14 04:17:03 +0000 (Sat, 14 Mar 2009)

Log Message:
-----------
Some rewrites and clean-ups in decompressing functions. View and Pic post-processing functions reverted back to FreeSCI ones.  

Modified Paths:
--------------
    scummvm/trunk/engines/sci/scicore/decompressor.cpp
    scummvm/trunk/engines/sci/scicore/decompressor.h
    scummvm/trunk/engines/sci/scicore/resource.cpp

Modified: scummvm/trunk/engines/sci/scicore/decompressor.cpp
===================================================================
--- scummvm/trunk/engines/sci/scicore/decompressor.cpp	2009-03-14 01:52:14 UTC (rev 39382)
+++ scummvm/trunk/engines/sci/scicore/decompressor.cpp	2009-03-14 04:17:03 UTC (rev 39383)
@@ -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 @@
 	_dwBits = 0;
 }
 
-void Decompressor::fetchBits() {
+void Decompressor::fetchBitsMSB() {
 	while (_nBits <= 24) {
 		_dwBits |= ((uint32)_src->readByte()) << (24 - _nBits);
 		_nBits += 8;
@@ -69,54 +62,84 @@
 	}
 }
 
-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 @@
 	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 @@
 	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 kComp3View:
-	case kComp3Pic:
+	case kCompLZW1: // SCI01/1 LZW compression
+		return unpackLZW1(src, dest, nPacked, nUnpacked);
+		break;
+	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 @@
 	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 @@
 
 			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 @@
 			}
 			// 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 @@
 #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 @@
  *
  * 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 @@
 	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;
+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;
 
-	// Setting palette
-	dest->writeByte(PIC_OP_OPX);
-	dest->writeByte(PIC_OPX_SET_PALETTE);
+	for (i = 0; i < 256; i++) /* Palette translation map */
+		*writer++ = i;
 
-	for (int i = 0; i < 256; i++) // Palette translation map
-		dest->writeByte(i);
-	dest->writeUint32LE(0);  //Palette timestamp
+	WRITE_LE_UINT32(writer, 0); /* Palette stamp */
+	writer += 4;
 
-	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
+	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::view_reorder(byte *inbuffer, byte *outbuffer) {
+void DecompressorLZW::reorderView(byte *src, byte *dest) {
 	byte *cellengths;
 	int loopheaders;
 	int lh_present;
@@ -417,9 +490,9 @@
 	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 @@
 	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 @@
 			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 @@
 			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 @@
 
 	/* 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 @@
 }
 
 //----------------------------------------------
-// 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 @@
 	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 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 @@
 		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 @@
 			}
 
 		} 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 @@
 	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

Modified: scummvm/trunk/engines/sci/scicore/decompressor.h
===================================================================
--- scummvm/trunk/engines/sci/scicore/decompressor.h	2009-03-14 01:52:14 UTC (rev 39382)
+++ scummvm/trunk/engines/sci/scicore/decompressor.h	2009-03-14 04:17:03 UTC (rev 39383)
@@ -34,9 +34,9 @@
 	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,14 +48,8 @@
 public:
 	Decompressor() {}
 	virtual ~Decompressor() {}
+	virtual int unpack(Common::ReadStream *src, byte *dest, uint32 nPacked, uint32 nUnpacked);
 
-	//! get a number of bits from _src stream
-	/** @param n - number of bits to get
-		@return (uint32) n-bits number
-	  */
-	virtual int unpack(Common::ReadStream *src, Common::WriteStream *dest, uint32 nPacked,
-	                   uint32 nUnpacked);
-
 protected:
 	//! Initialize decompressor
 	/** @param src - source stream to read from
@@ -64,34 +58,40 @@
 		@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 @@
 //----------------------------------------------
 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 @@
 // 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 @@
 		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

Modified: scummvm/trunk/engines/sci/scicore/resource.cpp
===================================================================
--- scummvm/trunk/engines/sci/scicore/resource.cpp	2009-03-14 01:52:14 UTC (rev 39382)
+++ scummvm/trunk/engines/sci/scicore/resource.cpp	2009-03-14 04:17:03 UTC (rev 39383)
@@ -1046,7 +1046,7 @@
 		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,37 +1063,30 @@
 	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::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 @@
 	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;
 }
 


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list