aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/sci/detection.cpp21
-rw-r--r--engines/sci/engine/kernel.cpp6
-rw-r--r--engines/sci/engine/kernel.h7
-rw-r--r--engines/sci/resource.cpp173
-rw-r--r--engines/sci/resource.h16
5 files changed, 178 insertions, 45 deletions
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index 959f18739b..ee9fd5fb18 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -3123,9 +3123,8 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
// therefore add the directory here, so that the game files can be opened later on
// TODO/FIXME: This should be removed, as it will cause problems with game detection:
// if we got a game A, and then try to detect another game B, adding a default
- // directory here means that game A's files will be opened first. We either need to
- // remove the directory added here, or rewrite all the functions which access game
- // files
+ // directory here means that game A's files will be opened first. We need to rewrite
+ // all the functions that access game files to use FSNodes instead
Common::File::addDefaultDirectory(file->getParent().getPath());
foundResMap = true;
}
@@ -3167,20 +3166,22 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
s_fallbackDesc.desc.flags = ADGF_NO_FLAGS;
// Determine the game id
- ResourceManager *resMgr = new ResourceManager();
+ ResourceManager *resMgr = new ResourceManager(fslist);
SciVersion version = resMgr->sciVersion();
- Kernel *kernel = new Kernel(resMgr);
- SegManager *segManager = new SegManager(resMgr, version, kernel->hasOldScriptHeader());
- if (!script_instantiate(resMgr, segManager, version, kernel->hasOldScriptHeader(), 0)) {
+ Kernel *kernel = new Kernel(resMgr, true);
+ bool hasOldScriptHeader = kernel->hasOldScriptHeader();
+ delete kernel;
+
+ SegManager *segManager = new SegManager(resMgr, version, hasOldScriptHeader);
+ if (!script_instantiate(resMgr, segManager, version, hasOldScriptHeader, 0)) {
warning("fallbackDetect(): Could not instantiate script 0");
return 0;
}
reg_t game_obj = script_lookup_export(segManager, 0, 0);
- Common::String gameName = obj_get_name(segManager,version, game_obj);
- debug(2, " \"%s\" at %04x:%04x", gameName.c_str(), PRINT_REG(game_obj));
+ Common::String gameName = obj_get_name(segManager, version, game_obj);
+ debug(2, "Detected ID: \"%s\" at %04x:%04x", gameName.c_str(), PRINT_REG(game_obj));
gameName.toLowercase();
s_fallbackDesc.desc.gameid = strdup(convertSierraGameId(gameName).c_str());
- delete kernel;
delete segManager;
delete resMgr;
diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp
index 09d342b7fe..223e7fc1e9 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -363,11 +363,15 @@ static const char *argtype_description[] = {
"Arithmetic"
};
-Kernel::Kernel(ResourceManager *resmgr) : _resmgr(resmgr) {
+Kernel::Kernel(ResourceManager *resmgr, bool minimalLoad) : _resmgr(resmgr) {
memset(&_selectorMap, 0, sizeof(_selectorMap)); // FIXME: Remove this once/if we C++ify selector_map_t
loadSelectorNames();
detectSciFeatures();
+
+ if (minimalLoad) // If we're only asked to detect game features, stop here
+ return;
+
mapSelectors(); // Map a few special selectors for later use
loadOpcodes();
loadKernelNames();
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index 8be51549f6..997cdaea77 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -65,7 +65,12 @@ enum AutoDetectedFeatures {
class Kernel {
public:
- Kernel(ResourceManager *resmgr);
+ /**
+ * Initializes the SCI kernel
+ * @param minimalLoad If true, only the selector names are loaded, to detect game features.
+ * It's set to true by the advanced game detector to speed it up
+ */
+ Kernel(ResourceManager *resmgr, bool minimalLoad = false);
~Kernel();
uint getOpcodesSize() const { return _opcodes.size(); }
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index 2ca198954a..9b9c9ee26c 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -112,6 +112,20 @@ ResourceSource *ResourceManager::addExternalMap(const char *file_name) {
newsrc->source_type = kSourceExtMap;
newsrc->location_name = file_name;
+ newsrc->resourceFile = 0;
+ newsrc->scanned = false;
+ newsrc->associated_map = NULL;
+
+ _sources.push_back(newsrc);
+ return newsrc;
+}
+
+ResourceSource *ResourceManager::addExternalMap(const Common::FSNode *mapFile) {
+ ResourceSource *newsrc = new ResourceSource();
+
+ newsrc->source_type = kSourceExtMap;
+ newsrc->location_name = mapFile->getName();
+ newsrc->resourceFile = mapFile;
newsrc->scanned = false;
newsrc->associated_map = NULL;
@@ -125,6 +139,21 @@ ResourceSource *ResourceManager::addSource(ResourceSource *map, ResSourceType ty
newsrc->source_type = type;
newsrc->scanned = false;
newsrc->location_name = filename;
+ newsrc->resourceFile = 0;
+ newsrc->volume_number = number;
+ newsrc->associated_map = map;
+
+ _sources.push_back(newsrc);
+ return newsrc;
+}
+
+ResourceSource *ResourceManager::addSource(ResourceSource *map, ResSourceType type, const Common::FSNode *resFile, int number) {
+ ResourceSource *newsrc = new ResourceSource();
+
+ newsrc->source_type = type;
+ newsrc->scanned = false;
+ newsrc->location_name = resFile->getName();
+ newsrc->resourceFile = resFile;
newsrc->volume_number = number;
newsrc->associated_map = map;
@@ -342,6 +371,48 @@ int ResourceManager::addAppropriateSources() {
return 1;
}
+int ResourceManager::addAppropriateSources(const Common::FSList &fslist) {
+ ResourceSource *map = 0;
+
+ // First, find resource.map
+ for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
+ if (file->isDirectory())
+ continue;
+
+ Common::String filename = file->getName();
+ filename.toLowercase();
+
+ if (filename.contains("resource.map") || filename.contains("resmap.000")) {
+ map = addExternalMap(file);
+ break;
+ }
+ }
+
+ if (!map)
+ return 0;
+
+ // Now find all the resource.0?? files
+ for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
+ if (file->isDirectory())
+ continue;
+
+ Common::String filename = file->getName();
+ filename.toLowercase();
+
+ if (filename.contains("resource.0") || filename.contains("ressci.0")) {
+ const char *dot = strrchr(filename.c_str(), '.');
+ int number = atoi(dot + 1);
+
+ addSource(map, kSourceVolume, file, number);
+ }
+ }
+
+ // This function is only called by the advanced detector, and we don't really need
+ // to add a patch directory or message.map here
+
+ return 1;
+}
+
int ResourceManager::addInternalSources() {
Common::List<ResourceId> *resources = listResources(kResourceTypeMap);
Common::List<ResourceId>::iterator itr = resources->begin();
@@ -397,14 +468,22 @@ void ResourceManager::freeResourceSources() {
}
ResourceManager::ResourceManager() {
+ addAppropriateSources();
+ init();
+}
+
+ResourceManager::ResourceManager(const Common::FSList &fslist) {
+ addAppropriateSources(fslist);
+ init();
+}
+
+void ResourceManager::init() {
_memoryLocked = 0;
_memoryLRU = 0;
_LRU.clear();
_resMap.clear();
_audioMapSCI1 = NULL;
- addAppropriateSources();
-
// FIXME: put this in an Init() function, so that we can error out if detection fails completely
_mapVersion = detectMapVersion();
@@ -601,7 +680,8 @@ const char *ResourceManager::versionDescription(ResVersion version) const {
}
ResourceManager::ResVersion ResourceManager::detectMapVersion() {
- Common::File file;
+ Common::SeekableReadStream *fileStream = 0;
+ Common::File *file = 0;
byte buff[6];
ResourceSource *rsrc= 0;
@@ -609,23 +689,30 @@ ResourceManager::ResVersion ResourceManager::detectMapVersion() {
rsrc = *it;
if (rsrc->source_type == kSourceExtMap) {
- file.open(rsrc->location_name);
+ if (rsrc->resourceFile) {
+ fileStream = rsrc->resourceFile->createReadStream();
+ } else {
+ file = new Common::File();
+ file->open(rsrc->location_name);
+ if (file->isOpen())
+ fileStream = file;
+ }
break;
}
}
- if (file.isOpen() == false) {
+ if (!fileStream) {
error("Failed to open resource map file");
return kResVersionUnknown;
}
// detection
// SCI0 and SCI01 maps have last 6 bytes set to FF
- file.seek(-4, SEEK_END);
- uint32 uEnd = file.readUint32LE();
+ fileStream->seek(-4, SEEK_END);
+ uint32 uEnd = fileStream->readUint32LE();
if (uEnd == 0xFFFFFFFF) {
// check if 0 or 01 - try to read resources in SCI0 format and see if exists
- file.seek(0, SEEK_SET);
- while (file.read(buff, 6) == 6 && !(buff[0] == 0xFF && buff[1] == 0xFF && buff[2] == 0xFF)) {
+ fileStream->seek(0, SEEK_SET);
+ while (fileStream->read(buff, 6) == 6 && !(buff[0] == 0xFF && buff[1] == 0xFF && buff[2] == 0xFF)) {
if (getVolume(rsrc, (buff[5] & 0xFC) >> 2) == NULL)
return kResVersionSci1Middle;
}
@@ -639,14 +726,15 @@ ResourceManager::ResVersion ResourceManager::detectMapVersion() {
uint16 lastDirectoryOffset = 0;
uint16 directorySize = 0;
ResVersion mapDetected = kResVersionUnknown;
- file.seek(0, SEEK_SET);
- while (!file.eos()) {
- directoryType = file.readByte();
- directoryOffset = file.readUint16LE();
+ fileStream->seek(0, SEEK_SET);
+
+ while (!fileStream->eos()) {
+ directoryType = fileStream->readByte();
+ directoryOffset = fileStream->readUint16LE();
if ((directoryType < 0x80) || ((directoryType > 0xA0) && (directoryType != 0xFF)))
break;
// Offset is above file size? -> definitely not SCI1/SCI1.1
- if (directoryOffset > file.size())
+ if (directoryOffset > fileStream->size())
break;
if (lastDirectoryOffset) {
directorySize = directoryOffset - lastDirectoryOffset;
@@ -655,11 +743,14 @@ ResourceManager::ResVersion ResourceManager::detectMapVersion() {
if ((directorySize % 5 == 0) && (directorySize % 6))
mapDetected = kResVersionSci11;
}
- if (directoryType==0xFF) {
+ if (directoryType == 0xFF) {
// FFh entry needs to point to EOF
- if (directoryOffset != file.size())
+ if (directoryOffset != fileStream->size())
break;
- if (mapDetected)
+
+ delete fileStream;
+
+ if (mapDetected)
return mapDetected;
return kResVersionSci1Late;
}
@@ -675,29 +766,41 @@ ResourceManager::ResVersion ResourceManager::detectMapVersion() {
// "lastDirectoryOffset". This is probably not the correct fix, since before r43000
// the loop above could not prematurely terminate and thus this would always check the
// last directory entry instead of the last checked directory entry.
- file.seek(lastDirectoryOffset - 7, SEEK_SET);
- if (file.readByte() == 0xFF && file.readUint16LE() == file.size())
+ fileStream->seek(lastDirectoryOffset - 7, SEEK_SET);
+ if (fileStream->readByte() == 0xFF && fileStream->readUint16LE() == fileStream->size())
return kResVersionSci32; // TODO : check if there is a difference between these maps
#endif
+ delete fileStream;
+
return kResVersionUnknown;
}
ResourceManager::ResVersion ResourceManager::detectVolVersion() {
- Common::File file;
+ Common::SeekableReadStream *fileStream = 0;
+ Common::File *file = 0;
ResourceSource *rsrc;
+
for (Common::List<ResourceSource *>::iterator it = _sources.begin(); it != _sources.end(); ++it) {
rsrc = *it;
if (rsrc->source_type == kSourceVolume) {
- file.open(rsrc->location_name);
+ if (rsrc->resourceFile) {
+ fileStream = rsrc->resourceFile->createReadStream();
+ } else {
+ file = new Common::File();
+ file->open(rsrc->location_name);
+ if (file->isOpen())
+ fileStream = file;
+ }
break;
}
}
- if (file.isOpen() == false) {
+ if (!fileStream) {
error("Failed to open volume file");
return kResVersionUnknown;
}
+
// SCI0 volume format: {wResId wPacked+4 wUnpacked wCompression} = 8 bytes
// SCI1 volume format: {bResType wResNumber wPacked+4 wUnpacked wCompression} = 9 bytes
// SCI1.1 volume format: {bResType wResNumber wPacked wUnpacked wCompression} = 9 bytes
@@ -710,15 +813,17 @@ ResourceManager::ResVersion ResourceManager::detectVolVersion() {
bool failed = false;
// Check for SCI0, SCI1, SCI1.1 and SCI32 v2 (Gabriel Knight 1 CD) formats
- while (!file.eos() && file.pos() < 0x100000) {
+ while (!fileStream->eos() && fileStream->pos() < 0x100000) {
if (curVersion > kResVersionSci0Sci1Early)
- file.readByte();
- resId = file.readUint16LE();
- dwPacked = (curVersion < kResVersionSci32) ? file.readUint16LE() : file.readUint32LE();
- dwUnpacked = (curVersion < kResVersionSci32) ? file.readUint16LE() : file.readUint32LE();
- wCompression = (curVersion < kResVersionSci32) ? file.readUint16LE() : file.readUint32LE();
- if (file.eos())
+ fileStream->readByte();
+ resId = fileStream->readUint16LE();
+ dwPacked = (curVersion < kResVersionSci32) ? fileStream->readUint16LE() : fileStream->readUint32LE();
+ dwUnpacked = (curVersion < kResVersionSci32) ? fileStream->readUint16LE() : fileStream->readUint32LE();
+ wCompression = (curVersion < kResVersionSci32) ? fileStream->readUint16LE() : fileStream->readUint32LE();
+ if (fileStream->eos()) {
+ delete fileStream;
return curVersion;
+ }
int chk = (curVersion == kResVersionSci0Sci1Early) ? 4 : 20;
int offs = curVersion < kResVersionSci11 ? 4 : 0;
@@ -740,18 +845,20 @@ ResourceManager::ResVersion ResourceManager::detectVolVersion() {
break;
}
- file.seek(0, SEEK_SET);
+ fileStream->seek(0, SEEK_SET);
continue;
}
if (curVersion < kResVersionSci11)
- file.seek(dwPacked - 4, SEEK_CUR);
+ fileStream->seek(dwPacked - 4, SEEK_CUR);
else if (curVersion == kResVersionSci11)
- file.seek((9 + dwPacked) % 2 ? dwPacked + 1 : dwPacked, SEEK_CUR);
+ fileStream->seek((9 + dwPacked) % 2 ? dwPacked + 1 : dwPacked, SEEK_CUR);
else if (curVersion == kResVersionSci32)
- file.seek(dwPacked, SEEK_CUR);//(9 + wPacked) % 2 ? wPacked + 1 : wPacked, SEEK_CUR);
+ fileStream->seek(dwPacked, SEEK_CUR);//(9 + wPacked) % 2 ? wPacked + 1 : wPacked, SEEK_CUR);
}
+ delete fileStream;
+
if (!failed)
return curVersion;
diff --git a/engines/sci/resource.h b/engines/sci/resource.h
index 8ab740f463..4250225ffe 100644
--- a/engines/sci/resource.h
+++ b/engines/sci/resource.h
@@ -28,6 +28,7 @@
#include "common/str.h"
#include "common/file.h"
+#include "common/fs.h"
#include "common/archive.h"
#include "sound/audiostream.h"
@@ -136,6 +137,7 @@ struct ResourceSource {
ResSourceType source_type;
bool scanned;
Common::String location_name; // FIXME: Replace by FSNode ?
+ const Common::FSNode *resourceFile;
int volume_number;
ResourceSource *associated_map;
};
@@ -247,6 +249,7 @@ public:
* Creates a new SCI resource manager.
*/
ResourceManager();
+ ResourceManager(const Common::FSList &fslist);
~ResourceManager();
/**
@@ -306,6 +309,11 @@ protected:
SciVersion _sciVersion; //!< Detected SCI version */
/**
+ * Initializes the resource manager
+ */
+ void init();
+
+ /**
* Add a path to the resource manager's list of sources.
* @return a pointer to the added source structure, or NULL if an error occurred.
*/
@@ -322,12 +330,19 @@ protected:
*/
ResourceSource *addSource(ResourceSource *map, ResSourceType type, const char *filename,
int number);
+
+ ResourceSource *addSource(ResourceSource *map, ResSourceType type,
+ const Common::FSNode *resFile, int number);
+
/**
* Add an external (i.e., separate file) map resource to the resource manager's list of sources.
* @param file_name The name of the volume to add
* @return A pointer to the added source structure, or NULL if an error occurred.
*/
ResourceSource *addExternalMap(const char *file_name);
+
+ ResourceSource *addExternalMap(const Common::FSNode *mapFile);
+
/**
* Add an internal (i.e., resource) map to the resource manager's list of sources.
* @param name The name of the resource to add
@@ -344,6 +359,7 @@ protected:
*/
void scanNewSources();
int addAppropriateSources();
+ int addAppropriateSources(const Common::FSList &fslist);
int addInternalSources();
void freeResourceSources();