From 44f12117f2f3d842f455d3bea1554904199b73e1 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Tue, 3 Aug 2010 14:58:57 +0000 Subject: SCI: Add support for SCI2.1 chunk resources And if no scripts are present, but chunk 0 is present, load resources from there. This fixes the Lighthouse SCI2.1 demo. svn-id: r51696 --- engines/sci/resource.cpp | 109 ++++++++++++++++++++++++++++++++++++++--- engines/sci/resource.h | 17 ++++++- engines/sci/resource_audio.cpp | 2 +- engines/sci/resource_intern.h | 28 ++++++++++- 4 files changed, 146 insertions(+), 10 deletions(-) (limited to 'engines') diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index d59b21eef6..a6899e4ef0 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -182,7 +182,7 @@ ResourceType ResourceManager::convertResType(byte type) { } //-- Resource main functions -- -Resource::Resource(ResourceId id) : _id(id) { +Resource::Resource(ResourceManager *resMan, ResourceId id) : _resMan(resMan), _id(id) { data = NULL; size = 0; _fileOffset = 0; @@ -705,6 +705,86 @@ void IntMapResourceSource::scanSource(ResourceManager *resMan) { resMan->readAudioMapSCI11(this); } +#ifdef ENABLE_SCI32 + +// Chunk resources are resources that hold other resources. They are normally called +// when using the kLoadChunk SCI2.1 kernel function. However, for example, the Lighthouse +// SCI2.1 demo has a chunk but no scripts outside of the chunk. + +// A chunk resource is pretty straightforward in terms of layout +// It begins with 11-byte entries in the header: +// ========= +// b resType +// w nEntry +// dw offset +// dw length + +ChunkResourceSource::ChunkResourceSource(const Common::String &name, uint16 number) + : ResourceSource(kSourceChunk, name) { + + _number = 0; +} + +void ChunkResourceSource::scanSource(ResourceManager *resMan) { + Resource *chunk = resMan->findResource(ResourceId(kResourceTypeChunk, _number), false); + + if (!chunk) + error("Trying to load non-existent chunk"); + + byte *ptr = chunk->data; + uint32 firstOffset = 0; + + for (;;) { + ResourceType type = resMan->convertResType(*ptr); + uint16 number = READ_LE_UINT16(ptr + 1); + ResourceId id(type, number); + + ResourceEntry entry; + entry.offset = READ_LE_UINT32(ptr + 3); + entry.length = READ_LE_UINT32(ptr + 7); + + _resMap[id] = entry; + ptr += 11; + + debugC(kDebugLevelResMan, 2, "Found %s in chunk %d", id.toString().c_str(), _number); + + resMan->updateResource(id, this, entry.length); + + // There's no end marker to the data table, but the first resource + // begins directly after the entry table. So, when we hit the first + // resource, we're at the end of the entry table. + + if (!firstOffset) + firstOffset = entry.offset; + + if ((ptr - chunk->data) >= firstOffset) + break; + } +} + +void ChunkResourceSource::loadResource(ResourceManager *resMan, Resource *res) { + Resource *chunk = resMan->findResource(ResourceId(kResourceTypeChunk, _number), false); + + if (!_resMap.contains(res->_id)) + error("Trying to load non-existent resource from chunk %d: %s %d", _number, getResourceTypeName(res->_id.getType()), res->_id.getNumber()); + + ResourceEntry entry = _resMap[res->_id]; + res->data = new byte[entry.length]; + res->size = entry.length; + res->_header = 0; + res->_headerSize = 0; + res->_status = kResStatusAllocated; + + // Copy the resource data over + memcpy(res->data, chunk->data + entry.offset, entry.length); +} + +void ResourceManager::addResourcesFromChunk(uint16 id) { + addSource(new ChunkResourceSource(Common::String::printf("Chunk %d", id), id)); + scanNewSources(); +} + +#endif void ResourceManager::freeResourceSources() { for (Common::List::iterator it = _sources.begin(); it != _sources.end(); ++it) @@ -770,6 +850,21 @@ void ResourceManager::init() { default: error("resMan: Couldn't determine view type"); } + +#ifdef ENABLE_SCI32 + if (getSciVersion() >= SCI_VERSION_2_1) { + // If we have no scripts, but chunk 0 is present, open up the chunk + // to try to get to any scripts in there. The Lighthouse SCI2.1 demo + // does exactly this. + + Common::List *scriptList = listResources(kResourceTypeScript); + + if (scriptList->empty() && testResource(ResourceId(kResourceTypeChunk, 0))) + addResourcesFromChunk(0); + + delete scriptList; + } +#endif } ResourceManager::~ResourceManager() { @@ -1544,7 +1639,7 @@ void MacResourceForkResourceSource::scanSource(ResourceManager *resMan) { void ResourceManager::addResource(ResourceId resId, ResourceSource *src, uint32 offset, uint32 size) { // Adding new resource only if it does not exist if (_resMap.contains(resId) == false) { - Resource *res = new Resource(resId); + Resource *res = new Resource(this, resId); _resMap.setVal(resId, res); res->_source = src; res->_fileOffset = offset; @@ -1559,7 +1654,7 @@ Resource *ResourceManager::updateResource(ResourceId resId, ResourceSource *src, if (_resMap.contains(resId)) { res = _resMap.getVal(resId); } else { - res = new Resource(resId); + res = new Resource(this, resId); _resMap.setVal(resId, res); } @@ -1585,21 +1680,21 @@ int Resource::readResourceInfo(ResVersion volVersion, Common::SeekableReadStream case kResVersionSci0Sci1Early: case kResVersionSci1Middle: w = file->readUint16LE(); - type = (ResourceType)(w >> 11); + type = _resMan->convertResType(w >> 11); number = w & 0x7FF; szPacked = file->readUint16LE() - 4; szUnpacked = file->readUint16LE(); wCompression = file->readUint16LE(); break; case kResVersionSci1Late: - type = (ResourceType)(file->readByte() & 0x7F); + type = _resMan->convertResType(file->readByte()); number = file->readUint16LE(); szPacked = file->readUint16LE() - 4; szUnpacked = file->readUint16LE(); wCompression = file->readUint16LE(); break; case kResVersionSci11: - type = (ResourceType)(file->readByte() & 0x7F); + type = _resMan->convertResType(file->readByte()); number = file->readUint16LE(); szPacked = file->readUint16LE(); szUnpacked = file->readUint16LE(); @@ -1616,7 +1711,7 @@ int Resource::readResourceInfo(ResVersion volVersion, Common::SeekableReadStream break; #ifdef ENABLE_SCI32 case kResVersionSci32: - type = (ResourceType)(file->readByte() & 0x7F); + type = _resMan->convertResType(file->readByte()); number = file->readUint16LE(); szPacked = file->readUint32LE(); szUnpacked = file->readUint32LE(); diff --git a/engines/sci/resource.h b/engines/sci/resource.h index f1ea2f15f9..48210b835f 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -193,6 +193,9 @@ class Resource { friend class WaveResourceSource; friend class AudioVolumeResourceSource; friend class MacResourceForkResourceSource; +#ifdef ENABLE_SCI32 + friend class ChunkResourceSource; +#endif // NOTE : Currently most member variables lack the underscore prefix and have // public visibility to let the rest of the engine compile without changes. @@ -203,7 +206,7 @@ public: uint32 _headerSize; public: - Resource(ResourceId id); + Resource(ResourceManager *resMan, ResourceId id); ~Resource(); void unalloc(); @@ -227,6 +230,7 @@ protected: ResourceStatus _status; uint16 _lockers; /**< Number of places where this resource was locked */ ResourceSource *_source; + ResourceManager *_resMan; bool loadPatch(Common::SeekableReadStream *file); bool loadFromPatchFile(); @@ -251,6 +255,9 @@ class ResourceManager { friend class ExtAudioMapResourceSource; friend class WaveResourceSource; friend class MacResourceForkResourceSource; +#ifdef ENABLE_SCI32 + friend class ChunkResourceSource; +#endif public: /** @@ -324,6 +331,14 @@ public: */ void addNewGMPatch(SciGameId gameId); +#ifdef ENABLE_SCI32 + /** + * Parses all resources from a SCI2.1 chunk resource and adds them to the + * resource manager. + */ + void addResourcesFromChunk(uint16 id); +#endif + bool detectHires(); // Detects, if standard font of current game includes extended characters (>0x80) bool detectFontExtended(); diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp index 2c7a63b363..8c7fe9eca4 100644 --- a/engines/sci/resource_audio.cpp +++ b/engines/sci/resource_audio.cpp @@ -99,7 +99,7 @@ bool Resource::loadFromAudioVolumeSCI11(Common::SeekableReadStream *file) { } file->seek(-4, SEEK_CUR); - ResourceType type = (ResourceType)(file->readByte() & 0x7f); + ResourceType type = _resMan->convertResType(file->readByte()); if (((getType() == kResourceTypeAudio || getType() == kResourceTypeAudio36) && (type != kResourceTypeAudio)) || ((getType() == kResourceTypeSync || getType() == kResourceTypeSync36) && (type != kResourceTypeSync))) { warning("Resource type mismatch loading %s", _id.toString().c_str()); diff --git a/engines/sci/resource_intern.h b/engines/sci/resource_intern.h index 73986444a4..14f872b46e 100644 --- a/engines/sci/resource_intern.h +++ b/engines/sci/resource_intern.h @@ -43,7 +43,8 @@ enum ResSourceType { kSourceAudioVolume, kSourceExtAudioMap, kSourceWave, - kSourceMacResourceFork + kSourceMacResourceFork, + kSourceChunk }; @@ -188,6 +189,31 @@ public: virtual void loadResource(ResourceManager *resMan, Resource *res); }; +#ifdef ENABLE_SCI32 + +/** + * Reads resources from SCI2.1+ chunk resources + */ +class ChunkResourceSource : public ResourceSource { +public: + ChunkResourceSource(const Common::String &name, uint16 number); + + virtual void scanSource(ResourceManager *resMan); + virtual void loadResource(ResourceManager *resMan, Resource *res); + +protected: + uint16 _number; + + struct ResourceEntry { + uint32 offset; + uint32 length; + }; + + Common::HashMap _resMap; +}; + +#endif + } // End of namespace Sci #endif // SCI_RESOURCE_INTERN_H -- cgit v1.2.3