diff options
-rw-r--r-- | engines/sci/resource.cpp | 120 | ||||
-rw-r--r-- | engines/sci/resource_intern.h | 9 |
2 files changed, 118 insertions, 11 deletions
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 60251ae54b..3362259402 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -393,14 +393,120 @@ void MacResourceForkResourceSource::loadResource(ResourceManager *resMan, Resour 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 @@ void ResourceManager::detectSciVersion() { // 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")) - s_sciVersion = SCI_VERSION_2_1; else - s_sciVersion = SCI_VERSION_2; + s_sciVersion = SCI_VERSION_2_1; return; } diff --git a/engines/sci/resource_intern.h b/engines/sci/resource_intern.h index 14f872b46e..f7b04b644a 100644 --- a/engines/sci/resource_intern.h +++ b/engines/sci/resource_intern.h @@ -177,9 +177,6 @@ public: * 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 @@ public: 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 |