aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorMatthew Hoops2010-05-10 18:29:13 +0000
committerMatthew Hoops2010-05-10 18:29:13 +0000
commit7344ac20d7461245103279a8b48f853371018a79 (patch)
treee102b3a50960e5c4845f8ef2e3a1e30868e93897 /engines
parentb9813063ad3cfca5f7ff7a731eccca0bb32159e0 (diff)
downloadscummvm-rg350-7344ac20d7461245103279a8b48f853371018a79.tar.gz
scummvm-rg350-7344ac20d7461245103279a8b48f853371018a79.tar.bz2
scummvm-rg350-7344ac20d7461245103279a8b48f853371018a79.zip
Add support for loading SCI games from Mac resource forks. The games themselves do not work yet as some (not all) of the data is in BE order instead of LE. They currently error out because it thinks the relocation block is outside of the script.
svn-id: r48998
Diffstat (limited to 'engines')
-rw-r--r--engines/sci/detection.cpp8
-rw-r--r--engines/sci/detection_tables.h17
-rw-r--r--engines/sci/resource.cpp145
-rw-r--r--engines/sci/resource.h15
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