diff options
-rw-r--r-- | engines/sci/detection.cpp | 8 | ||||
-rw-r--r-- | engines/sci/detection_tables.h | 17 | ||||
-rw-r--r-- | engines/sci/resource.cpp | 145 | ||||
-rw-r--r-- | engines/sci/resource.h | 15 |
4 files changed, 172 insertions, 13 deletions
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index 3c526dd1cd..b574484319 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -223,7 +223,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl Common::String filename = file->getName(); filename.toLowercase(); - if (filename.contains("resource.map") || filename.contains("resmap.00")) { + if (filename.contains("resource.map") || filename.contains("resmap.00") || filename.contains("Data1")) { // HACK: resource.map is located in the same directory as the other resource files, // therefore add the directory here, so that the game files can be opened later on // We now add the parent directory temporary to our SearchMan so the engine code @@ -259,6 +259,12 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl || filename.contains("ressci.000") || filename.contains("ressci.001")) foundRes000 = true; + // Data1 contains both map and volume for SCI1.1+ Mac games + if (filename.contains("Data1")) { + foundResMap = foundRes000 = true; + s_fallbackDesc.platform = Common::kPlatformMacintosh; + } + // Determine the game platform // The existence of any of these files indicates an Amiga game if (filename.contains("9.pat") || filename.contains("spal") || diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h index 4a67960875..dba4d879aa 100644 --- a/engines/sci/detection_tables.h +++ b/engines/sci/detection_tables.h @@ -1088,6 +1088,14 @@ static const struct ADGameDescription SciGameDescriptions[] = { {NULL, 0, NULL, 0}}, Common::ES_ESP, Common::kPlatformPC, 0, GUIO_NONE }, + // King's Quest 6 - English Macintosh Floppy + // VERSION file reports "1.0" + {"kq6", "", { + {"Data1", 0, "f3c38a33c94293b8ff0337c1090a4973", 3916479}, + {"Data2", 0, "b255edf327d7b366dce816b7debf3b94", 15046256}, + {NULL, 0, NULL, 0}}, + Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK, GUIO_NOSPEECH }, + #ifdef ENABLE_SCI32 @@ -2243,6 +2251,15 @@ static const struct ADGameDescription SciGameDescriptions[] = { Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH }, + // Quest for Glory 1 VGA Remake - English Macintosh Floppy + // VERSION file reports "2.0" + {"qfg1", "VGA Remake", { + {"Data1", 0, "14f26bc75f24bb1ecc94532df17b5371", 1768155}, + {"Data2", 0, "a7aee8bd46fc9cef7fd3bea93ef173e0", 6586422}, + {NULL, 0, NULL, 0}}, + Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK, GUIO_NOSPEECH + }, + // Quest for Glory 2 - English Amiga // Executable scanning reports "1.003.004" // SCI interpreter version 0.001.010 diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 20943c8f06..767dab8d66 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -26,6 +26,7 @@ // Resource library #include "common/file.h" +#include "common/macresman.h" #include "sci/resource.h" @@ -52,6 +53,7 @@ struct ResourceSource { ResourceSource *associated_map; uint32 audioCompressionType; int32 *audioCompressionOffsetMapping; + Common::MacResManager macResMan; }; ////////////////////////////////////////////////////////////////////// @@ -435,12 +437,29 @@ Common::File *ResourceManager::getVolumeFile(const char *filename) { return NULL; } -void ResourceManager::loadResource(Resource *res) { - Common::File *file; +static const uint32 resTypeToMacTag(ResourceType type); +void ResourceManager::loadResource(Resource *res) { if (res->_source->source_type == kSourcePatch && loadFromPatchFile(res)) return; + if (res->_source->source_type == kSourceMacResourceFork) { + //error("ResourceManager::loadResource(): TODO: Mac resource fork ;)"); + Common::SeekableReadStream *stream = res->_source->macResMan.getResource(resTypeToMacTag(res->_id.type), res->_id.number); + + if (!stream) + error("Could not get Mac resource fork resource"); + + int error = decompress(res, stream); + if (error) { + warning("Error %d occured while reading %s from Mac resource file: %s", + error, res->_id.toString().c_str(), sci_error_types[error]); + res->unalloc(); + } + return; + } + + Common::File *file; // Either loading from volume or patch loading failed file = getVolumeFile(res->_source->location_name.c_str()); if (!file) { @@ -549,11 +568,19 @@ int ResourceManager::addAppropriateSources() { addSource(map, kSourceVolume, name.c_str(), number); } #ifdef ENABLE_SCI32 - // GK1CD hires content - if (Common::File::exists("ALT.MAP") && Common::File::exists("RESOURCE.ALT")) { + if (Common::File::exists("ALT.MAP") && Common::File::exists("RESOURCE.ALT")) addSource(addExternalMap("ALT.MAP", 10), kSourceVolume, "RESOURCE.ALT", 10); +#endif + } else if (Common::File::exists("Data1")) { + // Mac SCI1.1+ file naming scheme + SearchMan.listMatchingMembers(files, "Data?"); + + for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) { + Common::String filename = (*x)->getName(); + addSource(0, kSourceMacResourceFork, filename.c_str(), atoi(filename.c_str() + 4)); } +#ifdef ENABLE_SCI32 } else { // SCI2.1-SCI3 file naming scheme Common::ArchiveMemberList mapFiles; @@ -712,6 +739,9 @@ void ResourceManager::scanNewSources() { case kSourceIntMap: readAudioMapSCI11(source); break; + case kSourceMacResourceFork: + readMacResourceFork(source); + break; default: break; } @@ -720,8 +750,11 @@ void ResourceManager::scanNewSources() { } void ResourceManager::freeResourceSources() { - for (Common::List<ResourceSource *>::iterator it = _sources.begin(); it != _sources.end(); ++it) + for (Common::List<ResourceSource *>::iterator it = _sources.begin(); it != _sources.end(); ++it) { + if ((*it)->source_type == kSourceMacResourceFork) + (*it)->macResMan.close(); delete *it; + } _sources.clear(); } @@ -939,6 +972,8 @@ const char *ResourceManager::versionDescription(ResVersion version) const { return "Late SCI1"; case kResVersionSci11: return "SCI1.1"; + case kResVersionSci11Mac: + return "Mac SCI1.1+"; case kResVersionSci32: return "SCI32"; } @@ -965,7 +1000,8 @@ ResourceManager::ResVersion ResourceManager::detectMapVersion() { fileStream = file; } break; - } + } else if (rsrc->source_type == kSourceMacResourceFork) + return kResVersionSci11Mac; } if (!fileStream) @@ -1054,8 +1090,10 @@ ResourceManager::ResVersion ResourceManager::detectVolVersion() { fileStream = file; } break; - } + } else if (rsrc->source_type == kSourceMacResourceFork) + return kResVersionSci11Mac; } + if (!fileStream) { error("Failed to open volume file - if you got resource.p01/resource.p02/etc. files, merge them together into resource.000"); // resource.p01/resource.p02/etc. may be there when directly copying the files from the original floppies @@ -1414,6 +1452,70 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) { return 0; } +static const uint32 resourceTypeMacTags[] = { + 'V56 ', 'P56 ', 'SCR ', 'TEX ', 'SND ', + 0, 'VOC ', 'FON ', 0, 'Pat ', // 'CURS is a mac cursor, not sure if it goes in + 0, 'PAL ', 0, 0, 0, + 'MSG ', 0, 'HEP ' +}; + +static const uint32 resTypeToMacTag(ResourceType type) { + if (type >= ARRAYSIZE(resourceTypeMacTags)) + return 0; + + return resourceTypeMacTags[type]; +} + +int ResourceManager::readMacResourceFork(ResourceSource *source) { + if (!source->macResMan.open(source->location_name.c_str())) + error("%s is not a valid Mac resource fork", source->location_name.c_str()); + + Common::MacResTagArray tagArray = source->macResMan.getResTagArray(); + + for (uint32 i = 0; i < tagArray.size(); i++) { + ResourceType type = kResourceTypeInvalid; + + // Map the Mac tags to our ResourceType + for (uint32 j = 0; j < ARRAYSIZE(resourceTypeMacTags); j++) + if (tagArray[i] == resourceTypeMacTags[j]) { + type = (ResourceType)j; + break; + } + + if (type == kResourceTypeInvalid) + continue; + + Common::MacResIDArray idArray = source->macResMan.getResIDArray(tagArray[i]); + + for (uint32 j = 0; j < idArray.size(); j++) { + ResourceId resId = ResourceId(type, idArray[j]); + + Resource *newrsc = NULL; + + // Prepare destination, if neccessary + if (!_resMap.contains(resId)) { + newrsc = new Resource; + _resMap.setVal(resId, newrsc); + } else + newrsc = _resMap.getVal(resId); + + // Get the size of the file + Common::SeekableReadStream *stream = source->macResMan.getResource(tagArray[i], idArray[j]);; + uint32 fileSize = stream->size(); + delete stream; + + // Overwrite everything, because we're patching + newrsc->_id = resId; + newrsc->_status = kResStatusNoMalloc; + newrsc->_source = source; + newrsc->size = fileSize; + newrsc->_headerSize = 0; + } + } + + return 0; +} + 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) { @@ -1681,7 +1783,7 @@ int ResourceManager::getAudioLanguage() const { return (_audioMapSCI1 ? _audioMapSCI1->volume_number : 0); } -int ResourceManager::readResourceInfo(Resource *res, Common::File *file, +int ResourceManager::readResourceInfo(Resource *res, Common::SeekableReadStream *file, uint32&szPacked, ResourceCompression &compression) { // SCI0 volume format: {wResId wPacked+4 wUnpacked wCompression} = 8 bytes // SCI1 volume format: {bResType wResNumber wPacked+4 wUnpacked wCompression} = 9 bytes @@ -1715,6 +1817,15 @@ int ResourceManager::readResourceInfo(Resource *res, Common::File *file, szUnpacked = file->readUint16LE(); wCompression = file->readUint16LE(); break; + case kResVersionSci11Mac: + // Doesn't store this data in the resource. Fortunately, + // we already have this data. + type = res->_id.type; + number = res->_id.number; + szPacked = file->size(); + szUnpacked = file->size(); + wCompression = 0; + break; #ifdef ENABLE_SCI32 case kResVersionSci32: type = (ResourceType)(file->readByte() & 0x7F); @@ -1727,11 +1838,14 @@ int ResourceManager::readResourceInfo(Resource *res, Common::File *file, default: return SCI_ERROR_INVALID_RESMAP_ENTRY; } + // check if there were errors while reading if ((file->eos() || file->err())) return SCI_ERROR_IO_ERROR; + res->_id = ResourceId(type, number); res->size = szUnpacked; + // checking compression method switch (wCompression) { case 0: @@ -1766,7 +1880,7 @@ int ResourceManager::readResourceInfo(Resource *res, Common::File *file, return compression == kCompUnknown ? SCI_ERROR_UNKNOWN_COMPRESSION : 0; } -int ResourceManager::decompress(Resource *res, Common::File *file) { +int ResourceManager::decompress(Resource *res, Common::SeekableReadStream *file) { int error; uint32 szPacked = 0; ResourceCompression compression = kCompUnknown; @@ -1775,6 +1889,7 @@ int ResourceManager::decompress(Resource *res, Common::File *file) { error = readResourceInfo(res, file, szPacked, compression); if (error) return error; + // getting a decompressor Decompressor *dec = NULL; switch (compression) { @@ -1930,6 +2045,7 @@ void ResourceManager::detectSciVersion() { // Set view type if (viewCompression == kCompDCL || _volVersion == kResVersionSci11 // pq4demo + || _volVersion == kResVersionSci11Mac // FIXME: Is this right? #ifdef ENABLE_SCI32 || viewCompression == kCompSTACpack || _volVersion == kResVersionSci32 // kq7 @@ -1941,6 +2057,17 @@ void ResourceManager::detectSciVersion() { // Otherwise we detect it from a view _viewType = detectViewType(); } + + if (_volVersion == kResVersionSci11Mac) { + // SCI32 doesn't have the resource.cfg file, so we can figure out + // which of the games are SCI1.1. + // TODO: Decide between SCI2 and SCI2.1 + if (Common::File::exists("resource.cfg")) + s_sciVersion = SCI_VERSION_1_1; + else + s_sciVersion = SCI_VERSION_2; + return; + } // Handle SCI32 versions here if (_volVersion == kResVersionSci32) { diff --git a/engines/sci/resource.h b/engines/sci/resource.h index 64e3cb4a12..1704336f2d 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -80,7 +80,8 @@ enum ResSourceType { kSourceIntMap, kSourceAudioVolume, kSourceExtAudioMap, - kSourceWave + kSourceWave, + kSourceMacResourceFork }; enum ResourceType { @@ -205,6 +206,7 @@ public: kResVersionSci1Middle, kResVersionSci1Late, kResVersionSci11, + kResVersionSci11Mac, kResVersionSci32 }; @@ -367,8 +369,8 @@ protected: bool loadFromAudioVolumeSCI1(Resource *res, Common::File &file); bool loadFromAudioVolumeSCI11(Resource *res, Common::File &file); void freeOldResources(); - int decompress(Resource *res, Common::File *file); - int readResourceInfo(Resource *res, Common::File *file, uint32&szPacked, ResourceCompression &compression); + int decompress(Resource *res, Common::SeekableReadStream *file); + int readResourceInfo(Resource *res, Common::SeekableReadStream *file, uint32&szPacked, ResourceCompression &compression); void addResource(ResourceId resId, ResourceSource *src, uint32 offset, uint32 size = 0); void removeAudioResource(ResourceId resId); @@ -389,6 +391,13 @@ protected: * @return 0 on success, an SCI_ERROR_* code otherwise */ int readResourceMapSCI1(ResourceSource *map); + + /** + * Reads the SCI1.1+ resource file from a Mac resource fork. + * @param source The source + * @return 0 on success, an SCI_ERROR_* code otherwise + */ + int readMacResourceFork(ResourceSource *source); /** * Reads SCI1.1 audio map resources |