diff options
| -rw-r--r-- | engines/scumm/plugin.cpp | 373 | 
1 files changed, 192 insertions, 181 deletions
diff --git a/engines/scumm/plugin.cpp b/engines/scumm/plugin.cpp index a0bb8d4ab0..5d37a8609c 100644 --- a/engines/scumm/plugin.cpp +++ b/engines/scumm/plugin.cpp @@ -755,7 +755,7 @@ static int compareMD5Table(const void *a, const void *b) {  	return strcmp(key, elem->md5);  } -const MD5Table *findInMD5Table(const char *md5) { +static const MD5Table *findInMD5Table(const char *md5) {  #ifdef PALMOS_68K  	uint32 arraySize = MemPtrSize((void *)md5table) / sizeof(MD5Table) - 1;  #else @@ -845,7 +845,7 @@ Common::String ScummEngine::generateFilename(const int room) const {  	return buf;  } -Common::String generateFilenameForDetection(const GameFilenamePattern &gfp) { +static Common::String generateFilenameForDetection(const GameFilenamePattern &gfp) {  	char buf[128];  	switch (gfp.genMethod) { @@ -884,8 +884,11 @@ struct DetectorDesc {  	const MD5Table *md5Entry;	// Entry of the md5 table corresponding to this file, if any.  }; -void detectGames(const FSList &fslist, Common::List<DetectorResult> &results, const char *gameid) { -	typedef Common::HashMap<Common::String, DetectorDesc, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> DescMap; +typedef Common::HashMap<Common::String, DetectorDesc, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> DescMap; + +static bool testGame(const GameSettings *g, const DescMap &fileMD5Map, const Common::String &file); + +static void detectGames(const FSList &fslist, Common::List<DetectorResult> &results, const char *gameid) {  	DescMap fileMD5Map;  	const GameSettings *g;  	DetectorResult dr; @@ -994,7 +997,6 @@ void detectGames(const FSList &fslist, Common::List<DetectorResult> &results, co  			continue; -  		//  ____            _     ____    		// |  _ \ __ _ _ __| |_  |___ \ *  		// | |_) / _` | '__| __|   __) | @@ -1031,191 +1033,200 @@ void detectGames(const FSList &fslist, Common::List<DetectorResult> &results, co  				continue;  			} -			// At this point, we know that the gameid matches, but no variant -			// was specified, yet there are multiple ones. So we try our best -			// to distinguish between the variants. -			// To do this, we take a close look at the detection file and -			// try to filter out some cases. - -			Common::File tmp; -			if (!tmp.open(d.path.c_str())) { -				warning("SCUMM detectGames: failed to open '%s' for read access", d.path.c_str()); -				continue; +			 +			// Add the game/variant to the candidates list if it is consistent +			// with the file(s) we are seeing. +			if (testGame(g, fileMD5Map, file)) +				results.push_back(dr); +		} +	} +} + +static bool testGame(const GameSettings *g, const DescMap &fileMD5Map, const Common::String &file) { +	const DetectorDesc &d = fileMD5Map[file]; + +	// At this point, we know that the gameid matches, but no variant +	// was specified, yet there are multiple ones. So we try our best +	// to distinguish between the variants. +	// To do this, we take a close look at the detection file and +	// try to filter out some cases. + +	Common::File tmp; +	if (!tmp.open(d.path.c_str())) { +		warning("SCUMM detectGames: failed to open '%s' for read access", d.path.c_str()); +		return false; +	} +	 +	if (file == "00.LFL") { +		// Used in V1, V2, V3 games. +		if (g->version > 3) +			return false; + +		// Read a few bytes to narrow down the game.				 +		byte buf[6]; +		tmp.read(buf, 6); +		 +		if (buf[0] == 0xbc && buf[1] == 0xb9) { +			// The NES version of MM +			if (g->id == GID_MANIAC && g->platform == Common::kPlatformNES) { +				// perfect match +				return true;  			} +		} else if (buf[0] == 0xCE && buf[1] == 0xF5) { +			// Looks like V1. +			// Candidates: maniac classic, zak classic -			if (file == "00.LFL") { -				// Used in V1, V2, V3 games. -				if (g->version > 3) -					continue; - -				// Read a few bytes to narrow down the game.				 -				byte buf[6]; -				tmp.read(buf, 6); -				 -				if (buf[0] == 0xbc && buf[1] == 0xb9) { -					// The NES version of MM -					if (g->id == GID_MANIAC && g->platform == Common::kPlatformNES) { -						// perfect match -						results.push_back(dr); -						break; -					} -				} else if (buf[0] == 0xCE && buf[1] == 0xF5) { -					// Looks like V1. -					// Candidates: maniac classic, zak classic -					 -					if (g->version != 1) -						continue; - -					// Zak has 58.LFL, Maniac doesn't have it. -					const bool has58LFL = fileMD5Map.contains("58.LFL"); -					if (g->id == GID_MANIAC && !has58LFL) { -					} else if (g->id == GID_ZAK && has58LFL) { -					} else -						continue; -				} else if (buf[0] == 0xFF && buf[1] == 0xFE) { -					// GF_OLD_BUNDLE: could be V2 or old V3. -					// Candidates: maniac enhanced, zak enhanced, indy3ega, loom - -					if (g->version != 2 && g->version != 3  || !(g->features & GF_OLD_BUNDLE)) -						continue; - -					/* We distinguish the games by the presence/absence of -					   certain files. In the following, '+' means the file -					   present, '-' means the file is absent. - -					   maniac:    -58.LFL, -84.LFL,-86.LFL, -98.LFL - -					   zak:       +58.LFL, -84.LFL,-86.LFL, -98.LFL -					   zakdemo:   +58.LFL, -84.LFL,-86.LFL, -98.LFL - -					   loom:      +58.LFL, -84.LFL,+86.LFL, -98.LFL -					   loomdemo:  -58.LFL, +84.LFL,-86.LFL, -98.LFL - -					   indy3:     +58.LFL, +84.LFL,+86.LFL, +98.LFL -					   indy3demo: -58.LFL, +84.LFL,-86.LFL, +98.LFL -					*/ -					const bool has58LFL = fileMD5Map.contains("58.LFL"); -					const bool has84LFL = fileMD5Map.contains("84.LFL"); -					const bool has86LFL = fileMD5Map.contains("86.LFL"); -					const bool has98LFL = fileMD5Map.contains("98.LFL"); - -					if (g->id == GID_INDY3         && has98LFL && has84LFL) { -					} else if (g->id == GID_ZAK    && !has98LFL && !has86LFL && !has84LFL && has58LFL) { -					} else if (g->id == GID_MANIAC && !has98LFL && !has86LFL && !has84LFL && !has58LFL) { -					} else if (g->id == GID_LOOM   && !has98LFL && (has86LFL != has84LFL)) { -					} else -						continue; -				} else if (buf[4] == '0' && buf[5] == 'R') { -					// newer V3 game -					// Candidates: indy3, indy3Towns, zakTowns, loomTowns - -					if (g->version != 3 || (g->features & GF_OLD_BUNDLE)) -						continue; - -					/* -					Considering that we know about *all* TOWNS versions, -					and know their MD5s, we could simply rely on this and -					if we find something which has an unknown MD5, assume -					that it is an (so far unknown) version of Indy3. +			if (g->version != 1) +				return false; + +			// Zak has 58.LFL, Maniac doesn't have it. +			const bool has58LFL = fileMD5Map.contains("58.LFL"); +			if (g->id == GID_MANIAC && !has58LFL) { +			} else if (g->id == GID_ZAK && has58LFL) { +			} else +				return false; +		} else if (buf[0] == 0xFF && buf[1] == 0xFE) { +			// GF_OLD_BUNDLE: could be V2 or old V3. +			// Candidates: maniac enhanced, zak enhanced, indy3ega, loom + +			if (g->version != 2 && g->version != 3  || !(g->features & GF_OLD_BUNDLE)) +				return false; + +			/* We distinguish the games by the presence/absence of +			   certain files. In the following, '+' means the file +			   present, '-' means the file is absent. + +			   maniac:    -58.LFL, -84.LFL,-86.LFL, -98.LFL + +			   zak:       +58.LFL, -84.LFL,-86.LFL, -98.LFL +			   zakdemo:   +58.LFL, -84.LFL,-86.LFL, -98.LFL + +			   loom:      +58.LFL, -84.LFL,+86.LFL, -98.LFL +			   loomdemo:  -58.LFL, +84.LFL,-86.LFL, -98.LFL + +			   indy3:     +58.LFL, +84.LFL,+86.LFL, +98.LFL +			   indy3demo: -58.LFL, +84.LFL,-86.LFL, +98.LFL +			*/ +			const bool has58LFL = fileMD5Map.contains("58.LFL"); +			const bool has84LFL = fileMD5Map.contains("84.LFL"); +			const bool has86LFL = fileMD5Map.contains("86.LFL"); +			const bool has98LFL = fileMD5Map.contains("98.LFL"); + +			if (g->id == GID_INDY3         && has98LFL && has84LFL) { +			} else if (g->id == GID_ZAK    && !has98LFL && !has86LFL && !has84LFL && has58LFL) { +			} else if (g->id == GID_MANIAC && !has98LFL && !has86LFL && !has84LFL && !has58LFL) { +			} else if (g->id == GID_LOOM   && !has98LFL && (has86LFL != has84LFL)) { +			} else +				return false; +		} else if (buf[4] == '0' && buf[5] == 'R') { +			// newer V3 game +			// Candidates: indy3, indy3Towns, zakTowns, loomTowns + +			if (g->version != 3 || (g->features & GF_OLD_BUNDLE)) +				return false; + +			/* +			Considering that we know about *all* TOWNS versions, +			and know their MD5s, we could simply rely on this and +			if we find something which has an unknown MD5, assume +			that it is an (so far unknown) version of Indy3. + +			We can combine this with a look at the resource headers: + +			Indy3: +			_numGlobalObjects 1000 +			_numRooms 99 +			_numCostumes 129 +			_numScripts 139 +			_numSounds 84 + +			Indy3Towns, ZakTowns, ZakLoom demo: +			_numGlobalObjects 1000 +			_numRooms 99 +			_numCostumes 199 +			_numScripts 199 +			_numSounds 199 + +			Assuming that all the town variants look like the latter, we can +			do the check like this: +			  if (numScripts == 139) +				assume Indy3 +			  else if (numScripts == 199) +				assume towns game +			  else +				unknown, do not accept it +			*/ +		} else { +			// TODO: Unknown file header, deal with it. Maybe an unencrypted +			// variant... +			// Anyway, we don't know to deal with the file, so we +			// just skip it. +		} +	} else if (file == "000.LFL") { +		// Used in V4 +		// Candidates: monkeyEGA, pass, monkeyVGA, loomcd + +		if (g->version != 4) +			return false; + +		/* +		For all of them, we have: +		_numGlobalObjects 1000 +		_numRooms 99 +		_numCostumes 199 +		_numScripts 199 +		_numSounds 199 -					We can combine this with a look at the resource headers: +		Any good ideas to distinguish those? Maybe by the presence / absence +		of some files? +		At least PASS and the monkeyEGA demo differ by 903.LFL missing... +		And the count of DISK??.LEC files differs depending on what version +		you have (4 or 8 floppy versions).  +		loomcd of course shipped on only one "disc". -					Indy3: -					_numGlobalObjects 1000 -					_numRooms 99 -					_numCostumes 129 -					_numScripts 139 -					_numSounds 84 +		pass: 000.LFL, 901.LFL, 902.LFL, 904.LFL, disk01.lec +		monkeyEGA:  000.LFL, 901-904.LFL, DISK01-09.LEC +		monkeyEGA DEMO: 000.LFL, 901.LFL, 902.LFL, 904.LFL, disk01.lec +		monkeyVGA: 000.LFL, 901-904.LFL, DISK01-04.LEC +		loomcd: 000.LFL, 901-904.LFL, DISK01.LEC +		*/ + +		const bool has903LFL = fileMD5Map.contains("903.LFL"); +		const bool hasDisk02 = fileMD5Map.contains("DISK02.LEC"); -					Indy3Towns, ZakTowns, ZakLoom demo: -					_numGlobalObjects 1000 -					_numRooms 99 -					_numCostumes 199 -					_numScripts 199 -					_numSounds 199 +		// There is not much we can do based on the presence / absence +		// of files. Only that if 903.LFL is present, it can't be PASS; +		// and if DISK02.LEC is present, it can't be LoomCD +		if (g->id == GID_PASS              && !has903LFL && !hasDisk02) { +		} else if (g->id == GID_LOOM       &&  has903LFL && !hasDisk02) { +		} else if (g->id == GID_MONKEY_VGA) { +		} else if (g->id == GID_MONKEY_EGA) { +		} else +			return false; +	} else { +		// Must be a V5+ game +		if (g->version < 5) +			return false; + +		// So at this point the gameid is determined, but not necessarily +		// the variant! -					Assuming that all the town variants look like the latter, we can -					do the check like this: -					  if (numScripts == 139) -						assume Indy3 -					  else if (numScripts == 199) -						assume towns game -					  else -						unknown, do not accept it -					*/ -				} else { -					// TODO: Unknown file header, deal with it. Maybe an unencrypted -					// variant... -					// Anyway, we don't know to deal with the file, so we -					// just skip it. -				} -			} else if (file == "000.LFL") { -				// Used in V4 -				// Candidates: monkeyEGA, pass, monkeyVGA, loomcd - -				if (g->version != 4) -					continue; - -				/* -				For all of them, we have: -				_numGlobalObjects 1000 -				_numRooms 99 -				_numCostumes 199 -				_numScripts 199 -				_numSounds 199 -				 -				Any good ideas to distinguish those? Maybe by the presence / absence -				of some files? -				At least PASS and the monkeyEGA demo differ by 903.LFL missing... -				And the count of DISK??.LEC files differs depending on what version -				you have (4 or 8 floppy versions).  -				loomcd of course shipped on only one "disc". -				 -				pass: 000.LFL, 901.LFL, 902.LFL, 904.LFL, disk01.lec -				monkeyEGA:  000.LFL, 901-904.LFL, DISK01-09.LEC -				monkeyEGA DEMO: 000.LFL, 901.LFL, 902.LFL, 904.LFL, disk01.lec -				monkeyVGA: 000.LFL, 901-904.LFL, DISK01-04.LEC -				loomcd: 000.LFL, 901-904.LFL, DISK01.LEC -				*/ - -				const bool has903LFL = fileMD5Map.contains("903.LFL"); -				const bool hasDisk02 = fileMD5Map.contains("DISK02.LEC"); -				 -				// There is not much we can do based on the presence / absence -				// of files. Only that if 903.LFL is present, it can't be PASS; -				// and if DISK02.LEC is present, it can't be LoomCD -				if (g->id == GID_PASS              && !has903LFL && !hasDisk02) { -				} else if (g->id == GID_LOOM       &&  has903LFL && !hasDisk02) { -				} else if (g->id == GID_MONKEY_VGA) { -				} else if (g->id == GID_MONKEY_EGA) { -				} else -					continue; -			} else { -				// Must be a V5+ game -				if (g->version < 5) -					continue; - -				// So at this point the gameid is determined, but not necessarily -				// the variant! -				 -				// TODO: Add code that handles this, at least for the non-HE games. -				// Note sure how realistic it is to correctly detect HE-game -				// variants, would require me to look at a sufficiently large -				// sample collection of HE games (assuming I had the time :). -				 -				 -				// TODO: For Mac versions in container file, we can sometimes -				// distinguish the demo from the regular version by looking -				// at the content of the container file and then looking for -				// the *.000 file in there. -			} -			 -			// Add the file to the candidate list -			results.push_back(dr); -		} +		// TODO: Add code that handles this, at least for the non-HE games. +		// Note sure how realistic it is to correctly detect HE-game +		// variants, would require me to look at a sufficiently large +		// sample collection of HE games (assuming I had the time :). +		 +		 +		// TODO: For Mac versions in container file, we can sometimes +		// distinguish the demo from the regular version by looking +		// at the content of the container file and then looking for +		// the *.000 file in there.  	} + +	return true;  } +  } // End of namespace Scumm  #pragma mark -  | 
