[Scummvm-cvs-logs] CVS: scummvm/scumm resource.cpp,1.230,1.231 scumm.cpp,1.108,1.109 scumm.h,1.432,1.433 sound.cpp,1.357,1.358

Max Horn fingolfin at users.sourceforge.net
Mon Jul 26 10:16:16 CEST 2004


Update of /cvsroot/scummvm/scummvm/scumm
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18188

Modified Files:
	resource.cpp scumm.cpp scumm.h sound.cpp 
Log Message:
Add support for the mac (rescumm) container file format used by Sam&Max and DOTT, making it possible to play those directly from the original CDs (no game detector support yet, so you have to add them to your config file manually for now)

Index: resource.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/resource.cpp,v
retrieving revision 1.230
retrieving revision 1.231
diff -u -d -r1.230 -r1.231
--- resource.cpp	26 Jul 2004 04:03:11 -0000	1.230
+++ resource.cpp	26 Jul 2004 17:14:56 -0000	1.231
@@ -37,6 +37,167 @@
 static uint16 newTag2Old(uint32 oldTag);
 static const char *resTypeFromId(int id);
 
+
+
+ScummFile::ScummFile() : _encbyte(0), _subFileStart(0), _subFileLen(0) {
+}
+
+void ScummFile::setEnc(byte value) {
+	_encbyte = value;
+}
+
+void ScummFile::setSubfileRange(uint32 start, uint32 len) {
+	// TODO: Add sanity checks
+	const uint32 fileSize = File::size();
+	assert(start <= fileSize);
+	assert(start + len <= fileSize);
+	_subFileStart = start;
+	_subFileLen = len;
+	seek(0, SEEK_SET);
+}
+
+void ScummFile::resetSubfile() {
+	_subFileStart = 0;
+	_subFileLen = 0;
+	seek(0, SEEK_SET);
+}
+
+bool ScummFile::open(const char *filename, AccessMode mode, const char *directory) {
+	if (File::open(filename, mode, directory)) {
+		resetSubfile();
+		return true;
+	} else {
+		return false;
+	}
+}
+
+bool ScummFile::openSubFile(const char *filename) {
+	assert(isOpen());
+
+	// Disable the XOR encryption and reset any current subfile range
+	setEnc(0);
+	resetSubfile();
+
+	// Read in the filename table and look for the specified file
+
+	unsigned long file_off, file_len;
+	char file_name[0x20+1];
+	unsigned long i;
+
+	// Get the length of the data file to use for consistency checks
+	const uint32 data_file_len = size();
+	
+	// Read offset and length to the file records */
+	const uint32 file_record_off = readUint32BE();
+	const uint32 file_record_len = readUint32BE();
+
+	// Do a quick check to make sure the offset and length are good
+	if (file_record_off + file_record_len > data_file_len) {
+		return false;
+	}
+
+	// Do a little consistancy check on file_record_length
+	if (file_record_len % 0x28) {
+		return false;
+	}
+
+	// Scan through the files
+	for (i = 0; i < file_record_len; i += 0x28) {
+		// read a file record
+		seek(file_record_off + i, SEEK_SET);
+		file_off = readUint32BE();
+		file_len = readUint32BE();
+		read(file_name, 0x20);
+		file_name[0x20] = 0;
+
+		assert(file_name[0]);
+		//debug(0, "extracting \'%s\'", file_name);
+		
+		// Consistency check. make sure the file data is in the file
+		if (file_off + file_len > data_file_len) {
+			return false;
+		}
+		
+		if (scumm_stricmp(file_name, filename) == 0) {
+			// We got a match!
+			_subFileName = file_name;
+			setSubfileRange(file_off, file_len);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+
+bool ScummFile::eof() {
+	return _subFileLen ? (pos() >= _subFileLen) : File::eof();
+}
+
+uint32 ScummFile::pos() {
+	return File::pos() - _subFileStart;
+}
+
+uint32 ScummFile::size() {
+	return _subFileLen ? _subFileLen : File::size();
+}
+
+void ScummFile::seek(int32 offs, int whence) {
+	if (_subFileLen) {
+		// Constrain the seek to the subfile
+		switch (whence) {
+		case SEEK_END:
+			offs = _subFileStart + _subFileLen - offs;
+			break;
+		case SEEK_SET:
+			offs += _subFileStart;
+			break;
+		case SEEK_CUR:
+			offs += File::pos();
+			break;
+		}
+		assert((int32)_subFileStart <= offs && offs <= (int32)(_subFileStart + _subFileLen));
+		whence = SEEK_SET;
+	}
+	File::seek(offs, whence);
+}
+
+uint32 ScummFile::read(void *ptr, uint32 len) {
+	uint32 realLen;
+	
+	if (_subFileLen) {
+		// Limit the amount we read by the subfile boundaries.
+		const uint32 curPos = pos();
+		assert(_subFileLen >= curPos);
+		uint32 newPos = curPos + len;
+		if (newPos > _subFileLen) {
+			len = _subFileLen - curPos;
+			_ioFailed = true;
+		}
+	}
+	
+	realLen = File::read(ptr, len);
+	
+	
+	// If an encryption byte was specified, XOR the data we just read by it.
+	// This simple kind of "encryption" was used by some of the older SCUMM
+	// games.
+	if (_encbyte) {
+		byte *p = (byte *)ptr;
+		byte *end = p + realLen;
+		while (p < end)
+			*p++ ^= _encbyte;
+	}
+
+	return realLen;
+}
+
+uint32 ScummFile::write(const void *, uint32) {
+	error("ScummFile does not support writing!");
+}
+
+
+
 /* Open a room */
 void ScummEngine::openRoom(int room) {
 	int room_offs, roomlimit;
@@ -217,15 +378,24 @@
 
 bool ScummEngine::openResourceFile(const char *filename, byte encByte) {
 	debugC(DEBUG_GENERAL, "openResourceFile(%s)", filename);
+	bool result = false;
 
-	if (_fileHandle.isOpen()) {
+	if (!_containerFile.isEmpty()) {
+		if (!_fileHandle.isOpen())
+			_fileHandle.open(_containerFile.c_str());
+		assert(_fileHandle.isOpen());
+		
+		result = _fileHandle.openSubFile(filename);
+	}
+	
+	if (!result) {
 		_fileHandle.close();
+		result = _fileHandle.open(filename);
 	}
 
-	_fileHandle.open(filename);
 	_fileHandle.setEnc(encByte);
 
-	return _fileHandle.isOpen();
+	return result;
 }
 
 void ScummEngine::askForDisk(const char *filename, int disknum) {

Index: scumm.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/scumm.cpp,v
retrieving revision 1.108
retrieving revision 1.109
diff -u -d -r1.108 -r1.109
--- scumm.cpp	26 Jul 2004 15:14:10 -0000	1.108
+++ scumm.cpp	26 Jul 2004 17:14:56 -0000	1.109
@@ -1009,6 +1009,27 @@
 
 void ScummEngine::launch() {
 
+	// The mac versions of Sam&Max and DOTT use a special container file to
+	// store the actual SCUMM data files. The rescumm utility used to be used
+	// to extract those files. While that is still possible, we now support
+	// reading those files directly. The first step is to check whether one
+	// of them is present (what we do here); the rest is handled by the 
+	// ScummFile class and code in openResourceFile() (and in the Sound class,
+	// for MONSTER.SOU handling).
+	if (_gameId == GID_SAMNMAX) {
+		const char *samDataFile = "Sam & Max Data";
+		if (_fileHandle.open(samDataFile)) {
+			_containerFile = samDataFile;
+		}
+	}
+	if (_gameId == GID_TENTACLE) {
+		const char *dottDataFile = "Day of the Tentacle Data";
+		if (_fileHandle.open(dottDataFile)) {
+			_containerFile = dottDataFile;
+		}
+	}
+
+
 #ifdef __PALM_OS__
 	if (_features & GF_NEW_COSTUMES)
 		_maxHeapThreshold = gVars->memory[kMemScummNewCostGames];

Index: scumm.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/scumm.h,v
retrieving revision 1.432
retrieving revision 1.433
diff -u -d -r1.432 -r1.433
--- scumm.h	26 Jul 2004 15:14:10 -0000	1.432
+++ scumm.h	26 Jul 2004 17:14:56 -0000	1.433
@@ -61,23 +61,28 @@
 
 typedef Common::Map<Common::String, int> ObjectIDMap;
 
-class XORFile : public File {
+class ScummFile : public File {
 private:
 	byte _encbyte;
+	uint32	_subFileStart;
+	uint32	_subFileLen;
+	Common::String _subFileName;
 public:
-	XORFile() : _encbyte(0) {}
-	void setEnc(byte value) { _encbyte = value; }
+	ScummFile();
+	void setEnc(byte value);
+	
+	void setSubfileRange(uint32 start, uint32 len);
+	void resetSubfile();
 
-	uint32 read(void *ptr, uint32 len) {
-		uint32 realLen = File::read(ptr, len);
-		if (_encbyte) {
-			byte *p = (byte *)ptr;
-			byte *end = p + realLen;
-			while (p < end)
-				*p++ ^= _encbyte;
-		}
-		return realLen;
-	}
+	bool open(const char *filename, AccessMode mode = kFileReadMode, const char *directory = NULL);
+	bool openSubFile(const char *filename);
+
+	bool eof();
+	uint32 pos();
+	uint32 size();
+	void seek(int32 offs, int whence = SEEK_SET);
+	uint32 read(void *ptr, uint32 size);
+	uint32 write(const void *ptr, uint32 size);
 };
 
 // Use g_scumm from error() ONLY
@@ -619,8 +624,13 @@
 	void doSentence(int c, int b, int a);
 
 	/* Should be in Resource class */
-	XORFile _fileHandle;
+	ScummFile _fileHandle;
 	uint32 _fileOffset;
+public:
+	/** The name of the (macintosh/rescumm style) container file, if any. */
+	Common::String _containerFile;
+
+protected:
 	int _resourceHeaderSize;
 	Common::String _gameName;	// This is the name we use for opening resource files
 	Common::String _targetName;	// This is the game the user calls it, so use for saving

Index: sound.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/sound.cpp,v
retrieving revision 1.357
retrieving revision 1.358
diff -u -d -r1.357 -r1.358
--- sound.cpp	24 Jul 2004 14:24:34 -0000	1.357
+++ sound.cpp	26 Jul 2004 17:14:57 -0000	1.358
@@ -969,40 +969,50 @@
 }
 
 File *Sound::openSfxFile() {
-	char buf[256];
-	XORFile *file = new XORFile();
-	_offsetTable = NULL;
-	
 	struct SoundFileExtensions {
 		const char *ext;
 		SoundMode mode;
 	};
 	
-	const SoundFileExtensions extensions[] = {
-#ifdef USE_FLAC
+	static const SoundFileExtensions extensions[] = {
+	#ifdef USE_FLAC
 		{ "sof", kFlacMode },
-#endif
-#ifdef USE_MAD
+	#endif
+	#ifdef USE_MAD
 		{ "so3", kMP3Mode },
-#endif
-#ifdef USE_VORBIS
+	#endif
+	#ifdef USE_VORBIS
 		{ "sog", kVorbisMode },
-#endif
+	#endif
 		{ "sou", kVOCMode },
 		{ 0, kVOCMode }
 	};
+	
+	
 
-	/* Try opening the file <_gameName>.sou first, eg tentacle.sou.
+	char buf[256];
+	ScummFile *file = new ScummFile();
+	_offsetTable = NULL;
+	
+	
+	if (!_vm->_containerFile.isEmpty() && file->open(_vm->_containerFile.c_str())) {
+		if (file->openSubFile("monster.sou")) {
+			_soundMode = kVOCMode;
+		} else {
+			file->close();
+		}
+	}
+	
+	/* Try opening the file <_gameName>.sou first, e.g. tentacle.sou.
 	 * That way, you can keep .sou files for multiple games in the
 	 * same directory */
 	
-	int i, j;
 	const char *basename[3] = { 0, 0, 0 };
 	basename[0] = _vm->getGameName();
 	basename[1] = "monster";
 	
-	for (j = 0; basename[j] && !file->isOpen(); ++j) {
-		for (i = 0; extensions[i].ext; ++i) {
+	for (int j = 0; basename[j] && !file->isOpen(); ++j) {
+		for (int i = 0; extensions[i].ext; ++i) {
 			sprintf(buf, "%s.%s", basename[j], extensions[i].ext);
 			if (file->open(buf)) {
 				_soundMode = extensions[i].mode;
@@ -1019,7 +1029,9 @@
 		if (file->open(buf))
 			file->setEnc(0x69);
 		_soundMode = kVOCMode;
-	} else if (_soundMode != kVOCMode) {
+	}
+	
+	if (_soundMode != kVOCMode) {
 		/* Now load the 'offset' index in memory to be able to find the MP3 data
 
 		   The format of the .SO3 file is easy :





More information about the Scummvm-git-logs mailing list