mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-12 12:09:15 +00:00
Started rewriting the SCI engine to use FSNode instead of file names. This is the proper solution for removing the hack in the fallback detector, but it still needs work. Also, reduced the things needed to be initialized a bit, so that the detection is a bit faster
svn-id: r43510
This commit is contained in:
parent
766cdac9f3
commit
db0cd620f6
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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(); }
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
||||
/**
|
||||
@ -305,6 +308,11 @@ protected:
|
||||
ResVersion _mapVersion; //!< RESOURCE.MAP version
|
||||
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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user