[Scummvm-cvs-logs] SF.net SVN: scummvm:[43510] scummvm/trunk/engines/sci

thebluegr at users.sourceforge.net thebluegr at users.sourceforge.net
Tue Aug 18 16:10:31 CEST 2009


Revision: 43510
          http://scummvm.svn.sourceforge.net/scummvm/?rev=43510&view=rev
Author:   thebluegr
Date:     2009-08-18 14:10:31 +0000 (Tue, 18 Aug 2009)

Log Message:
-----------
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

Modified Paths:
--------------
    scummvm/trunk/engines/sci/detection.cpp
    scummvm/trunk/engines/sci/engine/kernel.cpp
    scummvm/trunk/engines/sci/engine/kernel.h
    scummvm/trunk/engines/sci/resource.cpp
    scummvm/trunk/engines/sci/resource.h

Modified: scummvm/trunk/engines/sci/detection.cpp
===================================================================
--- scummvm/trunk/engines/sci/detection.cpp	2009-08-18 12:49:34 UTC (rev 43509)
+++ scummvm/trunk/engines/sci/detection.cpp	2009-08-18 14:10:31 UTC (rev 43510)
@@ -3123,9 +3123,8 @@
 			// 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 @@
 	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;
 

Modified: scummvm/trunk/engines/sci/engine/kernel.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/kernel.cpp	2009-08-18 12:49:34 UTC (rev 43509)
+++ scummvm/trunk/engines/sci/engine/kernel.cpp	2009-08-18 14:10:31 UTC (rev 43510)
@@ -363,11 +363,15 @@
 	"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();

Modified: scummvm/trunk/engines/sci/engine/kernel.h
===================================================================
--- scummvm/trunk/engines/sci/engine/kernel.h	2009-08-18 12:49:34 UTC (rev 43509)
+++ scummvm/trunk/engines/sci/engine/kernel.h	2009-08-18 14:10:31 UTC (rev 43510)
@@ -65,7 +65,12 @@
 
 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(); }

Modified: scummvm/trunk/engines/sci/resource.cpp
===================================================================
--- scummvm/trunk/engines/sci/resource.cpp	2009-08-18 12:49:34 UTC (rev 43509)
+++ scummvm/trunk/engines/sci/resource.cpp	2009-08-18 14:10:31 UTC (rev 43510)
@@ -112,6 +112,7 @@
 
 	newsrc->source_type = kSourceExtMap;
 	newsrc->location_name = file_name;
+	newsrc->resourceFile = 0;
 	newsrc->scanned = false;
 	newsrc->associated_map = NULL;
 
@@ -119,12 +120,26 @@
 	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;
+
+	_sources.push_back(newsrc);
+	return newsrc;
+}
+
 ResourceSource *ResourceManager::addSource(ResourceSource *map, ResSourceType type, const char *filename, int number) {
 	ResourceSource *newsrc = new ResourceSource();
 
 	newsrc->source_type = type;
 	newsrc->scanned = false;
 	newsrc->location_name = filename;
+	newsrc->resourceFile = 0;
 	newsrc->volume_number = number;
 	newsrc->associated_map = map;
 
@@ -132,6 +147,20 @@
 	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;
+
+	_sources.push_back(newsrc);
+	return newsrc;
+}
+
 ResourceSource *ResourceManager::addPatchDir(const char *dirname) {
 	ResourceSource *newsrc = new ResourceSource();
 
@@ -342,6 +371,48 @@
 	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 @@
 }
 
 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 @@
 }
 
 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 @@
 		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 @@
 	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 @@
 			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 @@
 	// "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 @@
 	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 @@
 				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;
 

Modified: scummvm/trunk/engines/sci/resource.h
===================================================================
--- scummvm/trunk/engines/sci/resource.h	2009-08-18 12:49:34 UTC (rev 43509)
+++ scummvm/trunk/engines/sci/resource.h	2009-08-18 14:10:31 UTC (rev 43510)
@@ -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 @@
 	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 @@
 	 * Creates a new SCI resource manager.
 	 */
 	ResourceManager();
+	ResourceManager(const Common::FSList &fslist);
 	~ResourceManager();
 
 	/**
@@ -306,6 +309,11 @@
 	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 @@
 	 */
 	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 @@
 	 */
 	void scanNewSources();
 	int addAppropriateSources();
+	int addAppropriateSources(const Common::FSList &fslist);
 	int addInternalSources();
 	void freeResourceSources();
 


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list