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

mthreepwood at users.sourceforge.net mthreepwood at users.sourceforge.net
Mon Jan 31 23:45:51 CET 2011


Revision: 55696
          http://scummvm.svn.sourceforge.net/scummvm/?rev=55696&view=rev
Author:   mthreepwood
Date:     2011-01-31 22:45:51 +0000 (Mon, 31 Jan 2011)

Log Message:
-----------
SCI: Add support for Mac SCI1.1+ resource compression

Mac SCI1.1+ games should now start up. QFG1 and Hoyle4 are playable. GK1 starts its scripts, but errors out soon after. There are still some View bugs with each (somehow, view decompression seems to be adding a blank line after each line?).

*Much* thanks to Walter for his help.

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

Modified: scummvm/trunk/engines/sci/resource.cpp
===================================================================
--- scummvm/trunk/engines/sci/resource.cpp	2011-01-31 21:02:13 UTC (rev 55695)
+++ scummvm/trunk/engines/sci/resource.cpp	2011-01-31 22:45:51 UTC (rev 55696)
@@ -393,14 +393,120 @@
 	if (!stream)
 		error("Could not get Mac resource fork resource: %s %d", getResourceTypeName(res->getType()), res->getNumber());
 
-	int error = res->decompress(resMan->getVolVersion(), stream);
-	if (error) {
-		warning("Error %d occurred while reading %s from Mac resource file: %s",
-				error, res->_id.toString().c_str(), sci_error_types[error]);
-		res->unalloc();
+	decompressResource(stream, res);
+}
+
+bool MacResourceForkResourceSource::isCompressableResource(ResourceType type) const {
+	// Any types that were not originally an SCI format are not compressed, it seems.
+	// (Audio being Mac snd resources here)
+	return type != kResourceTypeMacPict && type != kResourceTypeAudio &&
+			type != kResourceTypeMacIconBarPictN && type != kResourceTypeMacIconBarPictS;
+}
+
+#define OUTPUT_LITERAL() \
+	while (literalLength--) \
+		*ptr++ = stream->readByte();
+
+#define OUTPUT_COPY() \
+	while (copyLength--) { \
+		byte value = ptr[-offset]; \
+		*ptr++ = value; \
 	}
+
+void MacResourceForkResourceSource::decompressResource(Common::SeekableReadStream *stream, Resource *resource) const {	
+	// KQ6 Mac is the only game not compressed. It's not worth writing a
+	// heuristic just for that game. Also, skip over any resource that cannot
+	// be compressed.
+	bool canBeCompressed = !(g_sci && g_sci->getGameId() == GID_KQ6) && isCompressableResource(resource->_id.getType()); 
+	uint32 uncompressedSize = 0;
+
+	// Get the uncompressed size from the end of the resource
+	if (canBeCompressed && stream->size() > 4) {
+		stream->seek(stream->size() - 4);
+		uncompressedSize = stream->readUint32BE();
+		stream->seek(0);
+	}
+
+	if (uncompressedSize == 0) {
+		// Not compressed
+		resource->size = stream->size();
+
+		// Cut out the 'non-compressed marker' (four zeroes) at the end
+		if (canBeCompressed)
+			resource->size -= 4;
+
+		resource->data = new byte[resource->size];
+		stream->read(resource->data, resource->size);
+	} else {
+		// Decompress
+		resource->size = uncompressedSize;
+		resource->data = new byte[uncompressedSize];
+
+		byte *ptr = resource->data;
+
+		while (stream->pos() < stream->size()) {
+			byte code = stream->readByte();
+
+			int literalLength = 0, offset = 0, copyLength = 0;
+			byte extraByte1 = 0, extraByte2 = 0;
+
+			if (code == 0xFF) {
+				// End of stream marker
+				break;
+			}
+
+			switch (code & 0xC0) {
+			case 0x80:
+				// Copy chunk expanded
+				extraByte1 = stream->readByte();
+				extraByte2 = stream->readByte();
+ 
+				literalLength = extraByte2 & 3;
+
+				OUTPUT_LITERAL()
+
+				offset = ((code & 0x3f) | ((extraByte1 & 0xe0) << 1) | ((extraByte2 & 0xfc) << 7)) + 1;
+				copyLength = (extraByte1 & 0x1f) + 3;
+
+				OUTPUT_COPY()
+				break;
+			case 0xC0:
+				// Literal chunk
+				if (code >= 0xD0) {
+					// These codes cannot be used
+					if (code == 0xD0 || code > 0xD3)
+						error("Bad Mac compression code %02x", code);
+
+					literalLength = code & 3;
+				} else
+					literalLength = (code & 0xf) * 4 + 4;
+
+				OUTPUT_LITERAL()
+				break;
+			default:
+				// Copy chunk
+				extraByte1 = stream->readByte();
+
+				literalLength = (extraByte1 >> 3) & 0x3;
+
+				OUTPUT_LITERAL()
+
+				offset = (code + ((extraByte1 & 0xE0) << 2)) + 1;
+				copyLength = (extraByte1 & 0x7) + 3;
+
+				OUTPUT_COPY()
+				break;
+			}
+		}
+	}
+
+	resource->_status = kResStatusAllocated;
+	delete stream;
 }
 
+#undef OUTPUT_LITERAL
+#undef OUTPUT_COPY
+
 Common::SeekableReadStream *ResourceSource::getVolumeFile(ResourceManager *resMan, Resource *res) {
 	Common::SeekableReadStream *fileStream = resMan->getVolumeFile(this);
 
@@ -2082,10 +2188,8 @@
 		// TODO: Decide between SCI2 and SCI2.1
 		if (Common::File::exists("resource.cfg"))
 			s_sciVersion = SCI_VERSION_1_1;
-		else if (Common::File::exists("Patches"))
+		else
 			s_sciVersion = SCI_VERSION_2_1;
-		else
-			s_sciVersion = SCI_VERSION_2;
 		return;
 	}
 

Modified: scummvm/trunk/engines/sci/resource_intern.h
===================================================================
--- scummvm/trunk/engines/sci/resource_intern.h	2011-01-31 21:02:13 UTC (rev 55695)
+++ scummvm/trunk/engines/sci/resource_intern.h	2011-01-31 22:45:51 UTC (rev 55696)
@@ -177,9 +177,6 @@
  * Reads SCI1.1+ resources from a Mac resource fork.
  */
 class MacResourceForkResourceSource : public ResourceSource {
-protected:
-	Common::MacResManager *_macResMan;
-
 public:
 	MacResourceForkResourceSource(const Common::String &name, int volNum);
 	~MacResourceForkResourceSource();
@@ -187,6 +184,12 @@
 	virtual void scanSource(ResourceManager *resMan);
 
 	virtual void loadResource(ResourceManager *resMan, Resource *res);
+
+protected:
+	Common::MacResManager *_macResMan;
+
+	bool isCompressableResource(ResourceType type) const;
+	void decompressResource(Common::SeekableReadStream *stream, Resource *resource) const;
 };
 
 #ifdef ENABLE_SCI32


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