[Scummvm-cvs-logs] scummvm master -> 93024c073be6d93c9369a83e4b4468bb0aaeeadd

bluegr md5 at scummvm.org
Wed Jun 13 11:29:04 CEST 2012


This automated email contains information about 9 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
f76c71d968 SCI: Add debug code to automatically skip robot videos
aeac51d726 SCI: Implement the file operations needed for the save dialog in Phantasmagoria
a209359a67 SCI: Reorder the file kernel functions a bit
5a17ea0585 SCI: Move all file-related functions in file.*
944a774e6a SCI: Change kSave() to be a kernel function with subops
098f162ecc SCI: Use the later SCI file functions for the SCI0 ones
694f0f534a SCI: Only include kSave_subops if ENABLE_SCI32 is defined
e2613d2242 SCI: Add a workaround for the French version of Torin's Passage
93024c073b SCI: Handle the torindebug config setting for Torin's Passage French


Commit: f76c71d9682e193af3c852e27c3923950137445d
    https://github.com/scummvm/scummvm/commit/f76c71d9682e193af3c852e27c3923950137445d
Author: Filippos Karapetis (md5 at scummvm.org)
Date: 2012-06-13T02:26:48-07:00

Commit Message:
SCI: Add debug code to automatically skip robot videos

Changed paths:
    engines/sci/engine/kvideo.cpp



diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp
index c9cf652..f176a13 100644
--- a/engines/sci/engine/kvideo.cpp
+++ b/engines/sci/engine/kvideo.cpp
@@ -259,6 +259,7 @@ reg_t kRobot(EngineState *s, int argc, reg_t *argv) {
 		warning("kRobot(%d)", subop);
 		break;
 	case 8: // sync
+		//if (false) {	// debug: automatically skip all robot videos
 		if ((uint32)g_sci->_robotDecoder->getCurFrame() !=  g_sci->_robotDecoder->getFrameCount() - 1) {
 			writeSelector(s->_segMan, argv[1], SELECTOR(signal), NULL_REG);
 		} else {


Commit: aeac51d7263bf5233f3fb1f24d8a0789a9f8ca18
    https://github.com/scummvm/scummvm/commit/aeac51d7263bf5233f3fb1f24d8a0789a9f8ca18
Author: Filippos Karapetis (md5 at scummvm.org)
Date: 2012-06-13T02:26:49-07:00

Commit Message:
SCI: Implement the file operations needed for the save dialog in Phantasmagoria

Phantasmagoria's scripts keep polling for the existence of the savegame
index file and request to read and write it using the same parameters
when opening it. The index file is closed and reopened for every save
slot, which is slow and can be much slower on non-desktop devices.
Also, the game scripts request seeking in writable streams and request
to expand the existing index file.

To provide this functionality and to reduce constant slow file opening
and closing, this virtual class has been introduced

Changed paths:
  A engines/sci/engine/file.cpp
  A engines/sci/engine/file.h
    engines/sci/engine/kfile.cpp
    engines/sci/engine/state.cpp
    engines/sci/engine/state.h
    engines/sci/module.mk



diff --git a/engines/sci/engine/file.cpp b/engines/sci/engine/file.cpp
new file mode 100644
index 0000000..8876f3c
--- /dev/null
+++ b/engines/sci/engine/file.cpp
@@ -0,0 +1,139 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/savefile.h"
+#include "common/stream.h"
+
+#include "sci/sci.h"
+#include "sci/engine/file.h"
+
+namespace Sci {
+
+#ifdef ENABLE_SCI32
+
+VirtualIndexFile::VirtualIndexFile(Common::String fileName) : _fileName(fileName), _changed(false) {
+	Common::SeekableReadStream *inFile = g_sci->getSaveFileManager()->openForLoading(fileName);
+
+	_bufferSize = inFile->size();
+	_buffer = new char[_bufferSize];
+	inFile->read(_buffer, _bufferSize);
+	_ptr = _buffer;
+	delete inFile;
+}
+
+VirtualIndexFile::~VirtualIndexFile() {
+	close();
+
+	_bufferSize = 0;
+	delete[] _buffer;
+	_buffer = 0;
+}
+
+uint32 VirtualIndexFile::read(char *buffer, uint32 size) {
+	uint32 curPos = _ptr - _buffer;
+	uint32 finalSize = MIN<uint32>(size, _bufferSize - curPos);
+	char *localPtr = buffer;
+
+	for (uint32 i = 0; i < finalSize; i++)
+		*localPtr++ = *_ptr++;
+
+	return finalSize;
+}
+
+uint32 VirtualIndexFile::write(const char *buffer, uint32 size) {
+	_changed = true;
+	uint32 curPos = _ptr - _buffer;
+	
+	// Check if the buffer needs to be resized
+	if (curPos + size >= _bufferSize) {
+		_bufferSize = curPos + size + 1;
+		char *tmp = _buffer;
+		_buffer = new char[_bufferSize];
+		_ptr = _buffer + curPos;
+		memcpy(_buffer, tmp, _bufferSize);
+		delete[] tmp;
+	}
+
+	for (uint32 i = 0; i < size; i++)
+		*_ptr++ = *buffer++;
+
+	return size;
+}
+
+uint32 VirtualIndexFile::readLine(char *buffer, uint32 size) {
+	uint32 startPos = _ptr - _buffer;
+	uint32 bytesRead = 0;
+	char *localPtr = buffer;
+
+	// This is not a full-blown implementation of readLine, but it
+	// suffices for Phantasmagoria
+	while (startPos + bytesRead < size) {
+		bytesRead++;
+
+		if (*_ptr == 0 || *_ptr == 0x0A) {
+			_ptr++;
+			*localPtr = 0;
+			return bytesRead;
+		} else {
+			*localPtr++ = *_ptr++;
+		}
+	}
+
+	return bytesRead;
+}
+
+bool VirtualIndexFile::seek(int32 offset, int whence) {
+	uint32 startPos = _ptr - _buffer;
+	assert(offset >= 0);
+
+	switch (whence) {
+	case SEEK_CUR:
+		assert(startPos + offset < _bufferSize);
+		_ptr += offset;
+		break;
+	case SEEK_SET:
+		assert(offset < _bufferSize);
+		_ptr = _buffer + offset;
+		break;
+	case SEEK_END:
+		assert(_bufferSize - offset >= 0);
+		_ptr = _buffer + (_bufferSize - offset);
+		break;
+	}
+
+	return true;
+}
+
+void VirtualIndexFile::close() {
+	if (_changed) {
+		Common::WriteStream *outFile = g_sci->getSaveFileManager()->openForSaving(_fileName);
+		outFile->write(_buffer, _bufferSize);
+		delete outFile;
+	}
+
+	// Maintain the buffer, and seek to the beginning of it
+	_ptr = _buffer;
+}
+
+#endif
+
+} // End of namespace Sci
diff --git a/engines/sci/engine/file.h b/engines/sci/engine/file.h
new file mode 100644
index 0000000..e7b1090
--- /dev/null
+++ b/engines/sci/engine/file.h
@@ -0,0 +1,75 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SCI_ENGINE_FILE_H
+#define SCI_ENGINE_FILE_H
+
+#include "common/scummsys.h"
+
+namespace Sci {
+
+#ifdef ENABLE_SCI32
+
+/**
+ * An implementation of a virtual file that supports basic read and write
+ * operations simultaneously.
+ *
+ * This class has been initially implemented for Phantasmagoria, which has its
+ * own custom save/load code. The load code keeps checking for the existence
+ * of the save index file and keeps closing and reopening it for each save
+ * slot. This is notoriously slow and clumsy, and introduces noticeable delays,
+ * especially for non-desktop systems. Also, its game scripts request to open
+ * the index file for reading and writing with the same parameters
+ * (SaveManager::setCurrentSave and SaveManager::getCurrentSave). Moreover,
+ * the game scripts reopen the index file for writing in order to update it
+ * and seek within it. We do not support seeking in writeable streams, and the
+ * fact that our saved games are ZIP files makes this operation even more
+ * expensive. Finally, the savegame index file is supposed to be expanded when
+ * a new save slot is added.
+ * For the aforementioned reasons, this class has been implemented, which offers
+ * the basic functionality needed by the game scripts in Phantasmagoria.
+ */
+class VirtualIndexFile {
+public:
+	VirtualIndexFile(Common::String fileName);
+	~VirtualIndexFile();
+
+	uint32 read(char *buffer, uint32 size);
+	uint32 readLine(char *buffer, uint32 size);
+	uint32 write(const char *buffer, uint32 size);
+	bool seek(int32 offset, int whence);
+	void close();
+
+private:
+	char *_buffer;
+	uint32 _bufferSize;
+	char *_ptr;
+
+	Common::String _fileName;
+	bool _changed;
+};
+
+#endif
+
+} // End of namespace Sci
+
+#endif // SCI_ENGINE_FILE_H
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index 42f8b88..0dd2296 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -33,6 +33,7 @@
 #include "gui/saveload.h"
 
 #include "sci/sci.h"
+#include "sci/engine/file.h"
 #include "sci/engine/state.h"
 #include "sci/engine/kernel.h"
 #include "sci/engine/savegame.h"
@@ -72,8 +73,6 @@ struct SavegameDesc {
  * for reading only.
  */
 
-
-
 FileHandle::FileHandle() : _in(0), _out(0) {
 }
 
@@ -93,15 +92,14 @@ bool FileHandle::isOpen() const {
 	return _in || _out;
 }
 
-
-
 enum {
 	_K_FILE_MODE_OPEN_OR_CREATE = 0,
 	_K_FILE_MODE_OPEN_OR_FAIL = 1,
 	_K_FILE_MODE_CREATE = 2
 };
 
-
+#define VIRTUALFILE_HANDLE 200
+#define PHANTASMAGORIA_SAVEGAME_INDEX "phantsg.dir"
 
 reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool unwrapFilename) {
 	Common::String englishName = g_sci->getSciLanguageString(filename, K_LANG_ENGLISH);
@@ -130,6 +128,7 @@ reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool u
 		outFile = saveFileMan->openForSaving(wrappedName);
 		if (!outFile)
 			debugC(kDebugLevelFile, "  -> file_open(_K_FILE_MODE_CREATE): failed to create file '%s'", englishName.c_str());
+		
 		// QfG1 opens the character export file with _K_FILE_MODE_CREATE first,
 		// closes it immediately and opens it again with this here. Perhaps
 		// other games use this for read access as well. I guess changing this
@@ -171,8 +170,8 @@ reg_t kFOpen(EngineState *s, int argc, reg_t *argv) {
 }
 
 static FileHandle *getFileFromHandle(EngineState *s, uint handle) {
-	if (handle == 0) {
-		error("Attempt to use file handle 0");
+	if (handle == 0 || handle == VIRTUALFILE_HANDLE) {
+		error("Attempt to use invalid file handle (%d)", handle);
 		return 0;
 	}
 
@@ -738,6 +737,21 @@ reg_t kFileIO(EngineState *s, int argc, reg_t *argv) {
 reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) {
 	Common::String name = s->_segMan->getString(argv[0]);
 
+#ifdef ENABLE_SCI32
+	if (name == PHANTASMAGORIA_SAVEGAME_INDEX) {
+		if (s->_virtualIndexFile) {
+			return make_reg(0, VIRTUALFILE_HANDLE);
+		} else {
+			Common::String englishName = g_sci->getSciLanguageString(name, K_LANG_ENGLISH);
+			Common::String wrappedName = g_sci->wrapFilename(englishName);
+			if (!g_sci->getSaveFileManager()->listSavefiles(wrappedName).empty()) {
+				s->_virtualIndexFile = new VirtualIndexFile(wrappedName);
+				return make_reg(0, VIRTUALFILE_HANDLE);
+			}
+		}
+	}
+#endif
+
 	// SCI32 can call K_FILEIO_OPEN with only one argument. It seems to
 	// just be checking if it exists.
 	int mode = (argc < 2) ? (int)_K_FILE_MODE_OPEN_OR_FAIL : argv[1].toUint16();
@@ -780,7 +794,16 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) {
 reg_t kFileIOClose(EngineState *s, int argc, reg_t *argv) {
 	debugC(kDebugLevelFile, "kFileIO(close): %d", argv[0].toUint16());
 
-	FileHandle *f = getFileFromHandle(s, argv[0].toUint16());
+	uint16 handle = argv[0].toUint16();
+
+#ifdef ENABLE_SCI32
+	if (handle == VIRTUALFILE_HANDLE) {
+		s->_virtualIndexFile->close();
+		return SIGNAL_REG;
+	}
+#endif
+
+	FileHandle *f = getFileFromHandle(s, handle);
 	if (f) {
 		f->close();
 		return SIGNAL_REG;
@@ -789,39 +812,56 @@ reg_t kFileIOClose(EngineState *s, int argc, reg_t *argv) {
 }
 
 reg_t kFileIOReadRaw(EngineState *s, int argc, reg_t *argv) {
-	int handle = argv[0].toUint16();
-	int size = argv[2].toUint16();
+	uint16 handle = argv[0].toUint16();
+	uint16 size = argv[2].toUint16();
 	int bytesRead = 0;
 	char *buf = new char[size];
 	debugC(kDebugLevelFile, "kFileIO(readRaw): %d, %d", handle, size);
 
-	FileHandle *f = getFileFromHandle(s, handle);
-	if (f) {
-		bytesRead = f->_in->read(buf, size);
-		// TODO: What happens if less bytes are read than what has
-		// been requested? (i.e. if bytesRead is non-zero, but still
-		// less than size)
-		if (bytesRead > 0)
-			s->_segMan->memcpy(argv[1], (const byte*)buf, size);
+#ifdef ENABLE_SCI32
+	if (handle == VIRTUALFILE_HANDLE) {
+		bytesRead = s->_virtualIndexFile->read(buf, size);
+	} else {
+#endif
+		FileHandle *f = getFileFromHandle(s, handle);
+		if (f)
+			bytesRead = f->_in->read(buf, size);
+#ifdef ENABLE_SCI32
 	}
+#endif
+
+	// TODO: What happens if less bytes are read than what has
+	// been requested? (i.e. if bytesRead is non-zero, but still
+	// less than size)
+	if (bytesRead > 0)
+		s->_segMan->memcpy(argv[1], (const byte*)buf, size);
 
 	delete[] buf;
 	return make_reg(0, bytesRead);
 }
 
 reg_t kFileIOWriteRaw(EngineState *s, int argc, reg_t *argv) {
-	int handle = argv[0].toUint16();
-	int size = argv[2].toUint16();
+	uint16 handle = argv[0].toUint16();
+	uint16 size = argv[2].toUint16();
 	char *buf = new char[size];
 	bool success = false;
 	s->_segMan->memcpy((byte *)buf, argv[1], size);
 	debugC(kDebugLevelFile, "kFileIO(writeRaw): %d, %d", handle, size);
 
-	FileHandle *f = getFileFromHandle(s, handle);
-	if (f) {
-		f->_out->write(buf, size);
+#ifdef ENABLE_SCI32
+	if (handle == VIRTUALFILE_HANDLE) {
+		s->_virtualIndexFile->write(buf, size);
 		success = true;
+	} else {
+#endif
+		FileHandle *f = getFileFromHandle(s, handle);
+		if (f) {
+			f->_out->write(buf, size);
+			success = true;
+		}
+#ifdef ENABLE_SCI32
 	}
+#endif
 
 	delete[] buf;
 	if (success)
@@ -854,9 +894,19 @@ reg_t kFileIOUnlink(EngineState *s, int argc, reg_t *argv) {
 		name = g_sci->getSavegameName(savedir_nr);
 		result = saveFileMan->removeSavefile(name);
 	} else if (getSciVersion() >= SCI_VERSION_2) {
-		// We don't need to wrap the filename in SCI32 games, as it's already
-		// constructed here
+		// The file name may be already wrapped, so check both cases
 		result = saveFileMan->removeSavefile(name);
+		if (!result) {
+			const Common::String wrappedName = g_sci->wrapFilename(name);
+			result = saveFileMan->removeSavefile(wrappedName);
+		}
+
+#ifdef ENABLE_SCI32
+		if (name == PHANTASMAGORIA_SAVEGAME_INDEX) {
+			delete s->_virtualIndexFile;
+			s->_virtualIndexFile = 0;
+		}
+#endif
 	} else {
 		const Common::String wrappedName = g_sci->wrapFilename(name);
 		result = saveFileMan->removeSavefile(wrappedName);
@@ -869,15 +919,22 @@ reg_t kFileIOUnlink(EngineState *s, int argc, reg_t *argv) {
 }
 
 reg_t kFileIOReadString(EngineState *s, int argc, reg_t *argv) {
-	int size = argv[1].toUint16();
+	uint16 size = argv[1].toUint16();
 	char *buf = new char[size];
-	int handle = argv[2].toUint16();
+	uint16 handle = argv[2].toUint16();
 	debugC(kDebugLevelFile, "kFileIO(readString): %d, %d", handle, size);
+	uint32 bytesRead;
+
+#ifdef ENABLE_SCI32
+	if (handle == VIRTUALFILE_HANDLE)
+		bytesRead = s->_virtualIndexFile->readLine(buf, size);
+	else
+#endif
+		bytesRead = fgets_wrapper(s, buf, size, handle);
 
-	int readBytes = fgets_wrapper(s, buf, size, handle);
 	s->_segMan->memcpy(argv[0], (const byte*)buf, size);
 	delete[] buf;
-	return readBytes ? argv[0] : NULL_REG;
+	return bytesRead ? argv[0] : NULL_REG;
 }
 
 reg_t kFileIOWriteString(EngineState *s, int argc, reg_t *argv) {
@@ -885,6 +942,13 @@ reg_t kFileIOWriteString(EngineState *s, int argc, reg_t *argv) {
 	Common::String str = s->_segMan->getString(argv[1]);
 	debugC(kDebugLevelFile, "kFileIO(writeString): %d", handle);
 
+#ifdef ENABLE_SCI32
+	if (handle == VIRTUALFILE_HANDLE) {
+		s->_virtualIndexFile->write(str.c_str(), str.size());
+		return NULL_REG;
+	}
+#endif
+
 	FileHandle *f = getFileFromHandle(s, handle);
 
 	if (f) {
@@ -896,15 +960,31 @@ reg_t kFileIOWriteString(EngineState *s, int argc, reg_t *argv) {
 }
 
 reg_t kFileIOSeek(EngineState *s, int argc, reg_t *argv) {
-	int handle = argv[0].toUint16();
-	int offset = argv[1].toUint16();
-	int whence = argv[2].toUint16();
+	uint16 handle = argv[0].toUint16();
+	uint16 offset = ABS<int16>(argv[1].toSint16());	// can be negative
+	uint16 whence = argv[2].toUint16();
 	debugC(kDebugLevelFile, "kFileIO(seek): %d, %d, %d", handle, offset, whence);
 
+#ifdef ENABLE_SCI32
+	if (handle == VIRTUALFILE_HANDLE)
+		return make_reg(0, s->_virtualIndexFile->seek(offset, whence));
+#endif
+
 	FileHandle *f = getFileFromHandle(s, handle);
 
-	if (f)
-		s->r_acc = make_reg(0, f->_in->seek(offset, whence));
+	if (f && f->_in) {
+		// Backward seeking isn't supported in zip file streams, thus adapt the
+		// parameters accordingly if games ask for such a seek mode. A known
+		// case where this is requested is the save file manager in Phantasmagoria
+		if (whence == SEEK_END) {
+			whence = SEEK_SET;
+			offset = f->_in->size() - offset;
+		}
+
+		return make_reg(0, f->_in->seek(offset, whence));
+	} else if (f && f->_out) {
+		error("kFileIOSeek: Unsupported seek operation on a writeable stream (offset: %d, whence: %d)", offset, whence);
+	}
 
 	return SIGNAL_REG;
 }
@@ -1027,6 +1107,14 @@ reg_t kFileIOFindNext(EngineState *s, int argc, reg_t *argv) {
 reg_t kFileIOExists(EngineState *s, int argc, reg_t *argv) {
 	Common::String name = s->_segMan->getString(argv[0]);
 
+#ifdef ENABLE_SCI32
+	// Cache the file existence result for the Phantasmagoria
+	// save index file, as the game scripts keep checking for
+	// its existence.
+	if (name == PHANTASMAGORIA_SAVEGAME_INDEX && s->_virtualIndexFile)
+		return TRUE_REG;
+#endif
+
 	bool exists = false;
 
 	// Check for regular file
diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp
index 28818cd..237c6b5 100644
--- a/engines/sci/engine/state.cpp
+++ b/engines/sci/engine/state.cpp
@@ -26,6 +26,7 @@
 #include "sci/debug.h"	// for g_debug_sleeptime_factor
 #include "sci/event.h"
 
+#include "sci/engine/file.h"
 #include "sci/engine/kernel.h"
 #include "sci/engine/state.h"
 #include "sci/engine/selector.h"
@@ -68,21 +69,26 @@ static const uint16 s_halfWidthSJISMap[256] = {
 };
 
 EngineState::EngineState(SegManager *segMan)
-: _segMan(segMan), _dirseeker() {
+: _segMan(segMan),
+#ifdef ENABLE_SCI32
+	_virtualIndexFile(0),
+#endif
+	_dirseeker() {
 
 	reset(false);
 }
 
 EngineState::~EngineState() {
 	delete _msgState;
+#ifdef ENABLE_SCI32
+	delete _virtualIndexFile;
+#endif
 }
 
 void EngineState::reset(bool isRestoring) {
 	if (!isRestoring) {
 		_memorySegmentSize = 0;
-
 		_fileHandles.resize(5);
-
 		abortScriptProcessing = kAbortNone;
 	}
 
diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h
index dcffe6d..6f1f6a6 100644
--- a/engines/sci/engine/state.h
+++ b/engines/sci/engine/state.h
@@ -45,6 +45,7 @@ namespace Sci {
 class EventManager;
 class MessageState;
 class SoundCommandParser;
+class VirtualIndexFile;
 
 enum AbortGameState {
 	kAbortNone = 0,
@@ -163,6 +164,10 @@ public:
 	int16 _lastSaveVirtualId; // last virtual id fed to kSaveGame, if no kGetSaveFiles was called inbetween
 	int16 _lastSaveNewId;    // last newly created filename-id by kSaveGame
 
+#ifdef ENABLE_SCI32
+	VirtualIndexFile *_virtualIndexFile;
+#endif
+
 	uint _chosenQfGImportItem; // Remembers the item selected in QfG import rooms
 
 	bool _cursorWorkaroundActive; // ffs. GfxCursor::setPosition()
diff --git a/engines/sci/module.mk b/engines/sci/module.mk
index b6d5837..6b6058c 100644
--- a/engines/sci/module.mk
+++ b/engines/sci/module.mk
@@ -10,6 +10,7 @@ MODULE_OBJS := \
 	sci.o \
 	util.o \
 	engine/features.o \
+	engine/file.o \
 	engine/gc.o \
 	engine/kernel.o \
 	engine/kevent.o \


Commit: a209359a678ea19935c875da96fbdb1015bcee74
    https://github.com/scummvm/scummvm/commit/a209359a678ea19935c875da96fbdb1015bcee74
Author: Filippos Karapetis (md5 at scummvm.org)
Date: 2012-06-13T02:26:51-07:00

Commit Message:
SCI: Reorder the file kernel functions a bit

Changed paths:
    engines/sci/engine/kfile.cpp



diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index 0dd2296..dddbc27 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -869,6 +869,47 @@ reg_t kFileIOWriteRaw(EngineState *s, int argc, reg_t *argv) {
 	return make_reg(0, 6); // DOS - invalid handle
 }
 
+reg_t kFileIOReadString(EngineState *s, int argc, reg_t *argv) {
+	uint16 size = argv[1].toUint16();
+	char *buf = new char[size];
+	uint16 handle = argv[2].toUint16();
+	debugC(kDebugLevelFile, "kFileIO(readString): %d, %d", handle, size);
+	uint32 bytesRead;
+
+#ifdef ENABLE_SCI32
+	if (handle == VIRTUALFILE_HANDLE)
+		bytesRead = s->_virtualIndexFile->readLine(buf, size);
+	else
+#endif
+		bytesRead = fgets_wrapper(s, buf, size, handle);
+
+	s->_segMan->memcpy(argv[0], (const byte*)buf, size);
+	delete[] buf;
+	return bytesRead ? argv[0] : NULL_REG;
+}
+
+reg_t kFileIOWriteString(EngineState *s, int argc, reg_t *argv) {
+	int handle = argv[0].toUint16();
+	Common::String str = s->_segMan->getString(argv[1]);
+	debugC(kDebugLevelFile, "kFileIO(writeString): %d", handle);
+
+#ifdef ENABLE_SCI32
+	if (handle == VIRTUALFILE_HANDLE) {
+		s->_virtualIndexFile->write(str.c_str(), str.size());
+		return NULL_REG;
+	}
+#endif
+
+	FileHandle *f = getFileFromHandle(s, handle);
+
+	if (f) {
+		f->_out->write(str.c_str(), str.size());
+		return NULL_REG;
+	}
+
+	return make_reg(0, 6); // DOS - invalid handle
+}
+
 reg_t kFileIOUnlink(EngineState *s, int argc, reg_t *argv) {
 	Common::String name = s->_segMan->getString(argv[0]);
 	Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
@@ -918,47 +959,6 @@ reg_t kFileIOUnlink(EngineState *s, int argc, reg_t *argv) {
 	return make_reg(0, 2); // DOS - file not found error code
 }
 
-reg_t kFileIOReadString(EngineState *s, int argc, reg_t *argv) {
-	uint16 size = argv[1].toUint16();
-	char *buf = new char[size];
-	uint16 handle = argv[2].toUint16();
-	debugC(kDebugLevelFile, "kFileIO(readString): %d, %d", handle, size);
-	uint32 bytesRead;
-
-#ifdef ENABLE_SCI32
-	if (handle == VIRTUALFILE_HANDLE)
-		bytesRead = s->_virtualIndexFile->readLine(buf, size);
-	else
-#endif
-		bytesRead = fgets_wrapper(s, buf, size, handle);
-
-	s->_segMan->memcpy(argv[0], (const byte*)buf, size);
-	delete[] buf;
-	return bytesRead ? argv[0] : NULL_REG;
-}
-
-reg_t kFileIOWriteString(EngineState *s, int argc, reg_t *argv) {
-	int handle = argv[0].toUint16();
-	Common::String str = s->_segMan->getString(argv[1]);
-	debugC(kDebugLevelFile, "kFileIO(writeString): %d", handle);
-
-#ifdef ENABLE_SCI32
-	if (handle == VIRTUALFILE_HANDLE) {
-		s->_virtualIndexFile->write(str.c_str(), str.size());
-		return NULL_REG;
-	}
-#endif
-
-	FileHandle *f = getFileFromHandle(s, handle);
-
-	if (f) {
-		f->_out->write(str.c_str(), str.size());
-		return NULL_REG;
-	}
-
-	return make_reg(0, 6); // DOS - invalid handle
-}
-
 reg_t kFileIOSeek(EngineState *s, int argc, reg_t *argv) {
 	uint16 handle = argv[0].toUint16();
 	uint16 offset = ABS<int16>(argv[1].toSint16());	// can be negative


Commit: 5a17ea058583fb0a3d00392b8e07b2a1f414fded
    https://github.com/scummvm/scummvm/commit/5a17ea058583fb0a3d00392b8e07b2a1f414fded
Author: Filippos Karapetis (md5 at scummvm.org)
Date: 2012-06-13T02:26:53-07:00

Commit Message:
SCI: Move all file-related functions in file.*

This way, there is a clear separation of the actual SCI kernel file
functions and the file classes and wrappers of ScummVM

Changed paths:
    engines/sci/console.cpp
    engines/sci/engine/file.cpp
    engines/sci/engine/file.h
    engines/sci/engine/kernel.h
    engines/sci/engine/kfile.cpp
    engines/sci/engine/state.h



diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 5b5301b..6a44972 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -1216,6 +1216,27 @@ bool Console::cmdRestartGame(int argc, const char **argv) {
 	return Cmd_Exit(0, 0);
 }
 
+// The scripts get IDs ranging from 100->199, because the scripts require us to assign unique ids THAT EVEN STAY BETWEEN
+//  SAVES and the scripts also use "saves-count + 1" to create a new savedgame slot.
+//  SCI1.1 actually recycles ids, in that case we will currently get "0".
+// This behavior is required especially for LSL6. In this game, it's possible to quick save. The scripts will use
+//  the last-used id for that feature. If we don't assign sticky ids, the feature will overwrite different saves all the
+//  time. And sadly we can't just use the actual filename ids directly, because of the creation method for new slots.
+
+extern void listSavegames(Common::Array<SavegameDesc> &saves);
+
+bool Console::cmdListSaves(int argc, const char **argv) {
+	Common::Array<SavegameDesc> saves;
+	listSavegames(saves);
+
+	for (uint i = 0; i < saves.size(); i++) {
+		Common::String filename = g_sci->getSavegameName(saves[i].id);
+		DebugPrintf("%s: '%s'\n", filename.c_str(), saves[i].name);
+	}
+
+	return true;
+}
+
 bool Console::cmdClassTable(int argc, const char **argv) {
 	DebugPrintf("Available classes (parse a parameter to filter the table by a specific class):\n");
 
diff --git a/engines/sci/engine/file.cpp b/engines/sci/engine/file.cpp
index 8876f3c..66f54d6 100644
--- a/engines/sci/engine/file.cpp
+++ b/engines/sci/engine/file.cpp
@@ -25,9 +25,315 @@
 
 #include "sci/sci.h"
 #include "sci/engine/file.h"
+#include "sci/engine/kernel.h"
+#include "sci/engine/savegame.h"
+#include "sci/engine/selector.h"
+#include "sci/engine/state.h"
 
 namespace Sci {
 
+/*
+ * Note on how file I/O is implemented: In ScummVM, one can not create/write
+ * arbitrary data files, simply because many of our target platforms do not
+ * support this. The only files one can create are savestates. But SCI has an
+ * opcode to create and write to seemingly 'arbitrary' files. This is mainly
+ * used in LSL3 for LARRY3.DRV (which is a game data file, not a driver, used
+ * for persisting the results of the "age quiz" across restarts) and in LSL5
+ * for MEMORY.DRV (which is again a game data file and contains the game's
+ * password, XOR encrypted).
+ * To implement that opcode, we combine the SaveFileManager with regular file
+ * code, similarly to how the SCUMM HE engine does it.
+ *
+ * To handle opening a file called "foobar", what we do is this: First, we
+ * create an 'augmented file name', by prepending the game target and a dash,
+ * so if we running game target sq1sci, the name becomes "sq1sci-foobar".
+ * Next, we check if such a file is known to the SaveFileManager. If so, we
+ * we use that for reading/writing, delete it, whatever.
+ *
+ * If no such file is present but we were only asked to *read* the file,
+ * we fallback to looking for a regular file called "foobar", and open that
+ * for reading only.
+ */
+
+reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool unwrapFilename) {
+	Common::String englishName = g_sci->getSciLanguageString(filename, K_LANG_ENGLISH);
+	Common::String wrappedName = unwrapFilename ? g_sci->wrapFilename(englishName) : englishName;
+	Common::SeekableReadStream *inFile = 0;
+	Common::WriteStream *outFile = 0;
+	Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
+
+	if (mode == _K_FILE_MODE_OPEN_OR_FAIL) {
+		// Try to open file, abort if not possible
+		inFile = saveFileMan->openForLoading(wrappedName);
+		// If no matching savestate exists: fall back to reading from a regular
+		// file
+		if (!inFile)
+			inFile = SearchMan.createReadStreamForMember(englishName);
+
+		if (!inFile)
+			debugC(kDebugLevelFile, "  -> file_open(_K_FILE_MODE_OPEN_OR_FAIL): failed to open file '%s'", englishName.c_str());
+	} else if (mode == _K_FILE_MODE_CREATE) {
+		// Create the file, destroying any content it might have had
+		outFile = saveFileMan->openForSaving(wrappedName);
+		if (!outFile)
+			debugC(kDebugLevelFile, "  -> file_open(_K_FILE_MODE_CREATE): failed to create file '%s'", englishName.c_str());
+	} else if (mode == _K_FILE_MODE_OPEN_OR_CREATE) {
+		// Try to open file, create it if it doesn't exist
+		outFile = saveFileMan->openForSaving(wrappedName);
+		if (!outFile)
+			debugC(kDebugLevelFile, "  -> file_open(_K_FILE_MODE_CREATE): failed to create file '%s'", englishName.c_str());
+		
+		// QfG1 opens the character export file with _K_FILE_MODE_CREATE first,
+		// closes it immediately and opens it again with this here. Perhaps
+		// other games use this for read access as well. I guess changing this
+		// whole code into using virtual files and writing them after close
+		// would be more appropriate.
+	} else {
+		error("file_open: unsupported mode %d (filename '%s')", mode, englishName.c_str());
+	}
+
+	if (!inFile && !outFile) { // Failed
+		debugC(kDebugLevelFile, "  -> file_open() failed");
+		return SIGNAL_REG;
+	}
+
+	// Find a free file handle
+	uint handle = 1; // Ignore _fileHandles[0]
+	while ((handle < s->_fileHandles.size()) && s->_fileHandles[handle].isOpen())
+		handle++;
+
+	if (handle == s->_fileHandles.size()) {
+		// Hit size limit => Allocate more space
+		s->_fileHandles.resize(s->_fileHandles.size() + 1);
+	}
+
+	s->_fileHandles[handle]._in = inFile;
+	s->_fileHandles[handle]._out = outFile;
+	s->_fileHandles[handle]._name = englishName;
+
+	debugC(kDebugLevelFile, "  -> opened file '%s' with handle %d", englishName.c_str(), handle);
+	return make_reg(0, handle);
+}
+
+FileHandle *getFileFromHandle(EngineState *s, uint handle) {
+	if (handle == 0 || handle == VIRTUALFILE_HANDLE) {
+		error("Attempt to use invalid file handle (%d)", handle);
+		return 0;
+	}
+
+	if ((handle >= s->_fileHandles.size()) || !s->_fileHandles[handle].isOpen()) {
+		warning("Attempt to use invalid/unused file handle %d", handle);
+		return 0;
+	}
+
+	return &s->_fileHandles[handle];
+}
+
+int fgets_wrapper(EngineState *s, char *dest, int maxsize, int handle) {
+	FileHandle *f = getFileFromHandle(s, handle);
+	if (!f)
+		return 0;
+
+	if (!f->_in) {
+		error("fgets_wrapper: Trying to read from file '%s' opened for writing", f->_name.c_str());
+		return 0;
+	}
+	int readBytes = 0;
+	if (maxsize > 1) {
+		memset(dest, 0, maxsize);
+		f->_in->readLine(dest, maxsize);
+		readBytes = strlen(dest); // FIXME: sierra sci returned byte count and didn't react on NUL characters
+		// The returned string must not have an ending LF
+		if (readBytes > 0) {
+			if (dest[readBytes - 1] == 0x0A)
+				dest[readBytes - 1] = 0;
+		}
+	} else {
+		*dest = 0;
+	}
+
+	debugC(kDebugLevelFile, "  -> FGets'ed \"%s\"", dest);
+	return readBytes;
+}
+
+static bool _savegame_sort_byDate(const SavegameDesc &l, const SavegameDesc &r) {
+	if (l.date != r.date)
+		return (l.date > r.date);
+	return (l.time > r.time);
+}
+
+// Create a sorted array containing all found savedgames
+void listSavegames(Common::Array<SavegameDesc> &saves) {
+	Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
+
+	// Load all saves
+	Common::StringArray saveNames = saveFileMan->listSavefiles(g_sci->getSavegamePattern());
+
+	for (Common::StringArray::const_iterator iter = saveNames.begin(); iter != saveNames.end(); ++iter) {
+		Common::String filename = *iter;
+		Common::SeekableReadStream *in;
+		if ((in = saveFileMan->openForLoading(filename))) {
+			SavegameMetadata meta;
+			if (!get_savegame_metadata(in, &meta) || meta.name.empty()) {
+				// invalid
+				delete in;
+				continue;
+			}
+			delete in;
+
+			SavegameDesc desc;
+			desc.id = strtol(filename.end() - 3, NULL, 10);
+			desc.date = meta.saveDate;
+			// We need to fix date in here, because we save DDMMYYYY instead of
+			// YYYYMMDD, so sorting wouldn't work
+			desc.date = ((desc.date & 0xFFFF) << 16) | ((desc.date & 0xFF0000) >> 8) | ((desc.date & 0xFF000000) >> 24);
+			desc.time = meta.saveTime;
+			desc.version = meta.version;
+
+			if (meta.name.lastChar() == '\n')
+				meta.name.deleteLastChar();
+
+			Common::strlcpy(desc.name, meta.name.c_str(), SCI_MAX_SAVENAME_LENGTH);
+
+			debug(3, "Savegame in file %s ok, id %d", filename.c_str(), desc.id);
+
+			saves.push_back(desc);
+		}
+	}
+
+	// Sort the list by creation date of the saves
+	Common::sort(saves.begin(), saves.end(), _savegame_sort_byDate);
+}
+
+// Find a savedgame according to virtualId and return the position within our array
+int findSavegame(Common::Array<SavegameDesc> &saves, int16 savegameId) {
+	for (uint saveNr = 0; saveNr < saves.size(); saveNr++) {
+		if (saves[saveNr].id == savegameId)
+			return saveNr;
+	}
+	return -1;
+}
+
+
+FileHandle::FileHandle() : _in(0), _out(0) {
+}
+
+FileHandle::~FileHandle() {
+	close();
+}
+
+void FileHandle::close() {
+	delete _in;
+	delete _out;
+	_in = 0;
+	_out = 0;
+	_name.clear();
+}
+
+bool FileHandle::isOpen() const {
+	return _in || _out;
+}
+
+
+void DirSeeker::addAsVirtualFiles(Common::String title, Common::String fileMask) {
+	Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
+	Common::StringArray foundFiles = saveFileMan->listSavefiles(fileMask);
+	if (!foundFiles.empty()) {
+		_files.push_back(title);
+		_virtualFiles.push_back("");
+		Common::StringArray::iterator it;
+		Common::StringArray::iterator it_end = foundFiles.end();
+
+		for (it = foundFiles.begin(); it != it_end; it++) {
+			Common::String regularFilename = *it;
+			Common::String wrappedFilename = Common::String(regularFilename.c_str() + fileMask.size() - 1);
+
+			Common::SeekableReadStream *testfile = saveFileMan->openForLoading(regularFilename);
+			int32 testfileSize = testfile->size();
+			delete testfile;
+			if (testfileSize > 1024) // check, if larger than 1k. in that case its a saved game.
+				continue; // and we dont want to have those in the list
+			// We need to remove the prefix for display purposes
+			_files.push_back(wrappedFilename);
+			// but remember the actual name as well
+			_virtualFiles.push_back(regularFilename);
+		}
+	}
+}
+
+Common::String DirSeeker::getVirtualFilename(uint fileNumber) {
+	if (fileNumber >= _virtualFiles.size())
+		error("invalid virtual filename access");
+	return _virtualFiles[fileNumber];
+}
+
+reg_t DirSeeker::firstFile(const Common::String &mask, reg_t buffer, SegManager *segMan) {
+	// Verify that we are given a valid buffer
+	if (!buffer.segment) {
+		error("DirSeeker::firstFile('%s') invoked with invalid buffer", mask.c_str());
+		return NULL_REG;
+	}
+	_outbuffer = buffer;
+	_files.clear();
+	_virtualFiles.clear();
+
+	int QfGImport = g_sci->inQfGImportRoom();
+	if (QfGImport) {
+		_files.clear();
+		addAsVirtualFiles("-QfG1-", "qfg1-*");
+		addAsVirtualFiles("-QfG1VGA-", "qfg1vga-*");
+		if (QfGImport > 2)
+			addAsVirtualFiles("-QfG2-", "qfg2-*");
+		if (QfGImport > 3)
+			addAsVirtualFiles("-QfG3-", "qfg3-*");
+
+		if (QfGImport == 3) {
+			// QfG3 sorts the filelisting itself, we can't let that happen otherwise our
+			//  virtual list would go out-of-sync
+			reg_t savedHeros = segMan->findObjectByName("savedHeros");
+			if (!savedHeros.isNull())
+				writeSelectorValue(segMan, savedHeros, SELECTOR(sort), 0);
+		}
+
+	} else {
+		// Prefix the mask
+		const Common::String wrappedMask = g_sci->wrapFilename(mask);
+
+		// Obtain a list of all files matching the given mask
+		Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
+		_files = saveFileMan->listSavefiles(wrappedMask);
+	}
+
+	// Reset the list iterator and write the first match to the output buffer,
+	// if any.
+	_iter = _files.begin();
+	return nextFile(segMan);
+}
+
+reg_t DirSeeker::nextFile(SegManager *segMan) {
+	if (_iter == _files.end()) {
+		return NULL_REG;
+	}
+
+	Common::String string;
+
+	if (_virtualFiles.empty()) {
+		// Strip the prefix, if we don't got a virtual filelisting
+		const Common::String wrappedString = *_iter;
+		string = g_sci->unwrapFilename(wrappedString);
+	} else {
+		string = *_iter;
+	}
+	if (string.size() > 12)
+		string = Common::String(string.c_str(), 12);
+	segMan->strcpy(_outbuffer, string.c_str());
+
+	// Return the result and advance the list iterator :)
+	++_iter;
+	return _outbuffer;
+}
+
+
 #ifdef ENABLE_SCI32
 
 VirtualIndexFile::VirtualIndexFile(Common::String fileName) : _fileName(fileName), _changed(false) {
@@ -111,7 +417,7 @@ bool VirtualIndexFile::seek(int32 offset, int whence) {
 		_ptr += offset;
 		break;
 	case SEEK_SET:
-		assert(offset < _bufferSize);
+		assert(offset < (int32)_bufferSize);
 		_ptr = _buffer + offset;
 		break;
 	case SEEK_END:
diff --git a/engines/sci/engine/file.h b/engines/sci/engine/file.h
index e7b1090..896dcd2 100644
--- a/engines/sci/engine/file.h
+++ b/engines/sci/engine/file.h
@@ -23,10 +23,74 @@
 #ifndef SCI_ENGINE_FILE_H
 #define SCI_ENGINE_FILE_H
 
-#include "common/scummsys.h"
+#include "common/str-array.h"
+#include "common/stream.h"
 
 namespace Sci {
 
+enum {
+	_K_FILE_MODE_OPEN_OR_CREATE = 0,
+	_K_FILE_MODE_OPEN_OR_FAIL = 1,
+	_K_FILE_MODE_CREATE = 2
+};
+
+/* Maximum length of a savegame name (including terminator character). */
+#define SCI_MAX_SAVENAME_LENGTH 0x24
+
+enum {
+	MAX_SAVEGAME_NR = 20 /**< Maximum number of savegames */
+};
+
+#define VIRTUALFILE_HANDLE 200
+#define PHANTASMAGORIA_SAVEGAME_INDEX "phantsg.dir"
+
+struct SavegameDesc {
+	int16 id;
+	int virtualId; // straight numbered, according to id but w/o gaps
+	int date;
+	int time;
+	int version;
+	char name[SCI_MAX_SAVENAME_LENGTH];
+};
+
+class FileHandle {
+public:
+	Common::String _name;
+	Common::SeekableReadStream *_in;
+	Common::WriteStream *_out;
+
+public:
+	FileHandle();
+	~FileHandle();
+
+	void close();
+	bool isOpen() const;
+};
+
+
+class DirSeeker {
+protected:
+	reg_t _outbuffer;
+	Common::StringArray _files;
+	Common::StringArray _virtualFiles;
+	Common::StringArray::const_iterator _iter;
+
+public:
+	DirSeeker() {
+		_outbuffer = NULL_REG;
+		_iter = _files.begin();
+	}
+
+	reg_t firstFile(const Common::String &mask, reg_t buffer, SegManager *segMan);
+	reg_t nextFile(SegManager *segMan);
+
+	Common::String getVirtualFilename(uint fileNumber);
+
+private:
+	void addAsVirtualFiles(Common::String title, Common::String fileMask);
+};
+
+
 #ifdef ENABLE_SCI32
 
 /**
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index d9fdbef..25ca082 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -276,9 +276,6 @@ private:
 	const Common::String _invalid;
 };
 
-/* Maximum length of a savegame name (including terminator character). */
-#define SCI_MAX_SAVENAME_LENGTH 0x24
-
 /******************** Kernel functions ********************/
 
 reg_t kStrLen(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index dddbc27..36e5273 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -41,125 +41,11 @@
 
 namespace Sci {
 
-struct SavegameDesc {
-	int16 id;
-	int virtualId; // straight numbered, according to id but w/o gaps
-	int date;
-	int time;
-	int version;
-	char name[SCI_MAX_SAVENAME_LENGTH];
-};
-
-/*
- * Note on how file I/O is implemented: In ScummVM, one can not create/write
- * arbitrary data files, simply because many of our target platforms do not
- * support this. The only files one can create are savestates. But SCI has an
- * opcode to create and write to seemingly 'arbitrary' files. This is mainly
- * used in LSL3 for LARRY3.DRV (which is a game data file, not a driver, used
- * for persisting the results of the "age quiz" across restarts) and in LSL5
- * for MEMORY.DRV (which is again a game data file and contains the game's
- * password, XOR encrypted).
- * To implement that opcode, we combine the SaveFileManager with regular file
- * code, similarly to how the SCUMM HE engine does it.
- *
- * To handle opening a file called "foobar", what we do is this: First, we
- * create an 'augmented file name', by prepending the game target and a dash,
- * so if we running game target sq1sci, the name becomes "sq1sci-foobar".
- * Next, we check if such a file is known to the SaveFileManager. If so, we
- * we use that for reading/writing, delete it, whatever.
- *
- * If no such file is present but we were only asked to *read* the file,
- * we fallback to looking for a regular file called "foobar", and open that
- * for reading only.
- */
-
-FileHandle::FileHandle() : _in(0), _out(0) {
-}
-
-FileHandle::~FileHandle() {
-	close();
-}
-
-void FileHandle::close() {
-	delete _in;
-	delete _out;
-	_in = 0;
-	_out = 0;
-	_name.clear();
-}
-
-bool FileHandle::isOpen() const {
-	return _in || _out;
-}
-
-enum {
-	_K_FILE_MODE_OPEN_OR_CREATE = 0,
-	_K_FILE_MODE_OPEN_OR_FAIL = 1,
-	_K_FILE_MODE_CREATE = 2
-};
-
-#define VIRTUALFILE_HANDLE 200
-#define PHANTASMAGORIA_SAVEGAME_INDEX "phantsg.dir"
-
-reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool unwrapFilename) {
-	Common::String englishName = g_sci->getSciLanguageString(filename, K_LANG_ENGLISH);
-	Common::String wrappedName = unwrapFilename ? g_sci->wrapFilename(englishName) : englishName;
-	Common::SeekableReadStream *inFile = 0;
-	Common::WriteStream *outFile = 0;
-	Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
-
-	if (mode == _K_FILE_MODE_OPEN_OR_FAIL) {
-		// Try to open file, abort if not possible
-		inFile = saveFileMan->openForLoading(wrappedName);
-		// If no matching savestate exists: fall back to reading from a regular
-		// file
-		if (!inFile)
-			inFile = SearchMan.createReadStreamForMember(englishName);
-
-		if (!inFile)
-			debugC(kDebugLevelFile, "  -> file_open(_K_FILE_MODE_OPEN_OR_FAIL): failed to open file '%s'", englishName.c_str());
-	} else if (mode == _K_FILE_MODE_CREATE) {
-		// Create the file, destroying any content it might have had
-		outFile = saveFileMan->openForSaving(wrappedName);
-		if (!outFile)
-			debugC(kDebugLevelFile, "  -> file_open(_K_FILE_MODE_CREATE): failed to create file '%s'", englishName.c_str());
-	} else if (mode == _K_FILE_MODE_OPEN_OR_CREATE) {
-		// Try to open file, create it if it doesn't exist
-		outFile = saveFileMan->openForSaving(wrappedName);
-		if (!outFile)
-			debugC(kDebugLevelFile, "  -> file_open(_K_FILE_MODE_CREATE): failed to create file '%s'", englishName.c_str());
-		
-		// QfG1 opens the character export file with _K_FILE_MODE_CREATE first,
-		// closes it immediately and opens it again with this here. Perhaps
-		// other games use this for read access as well. I guess changing this
-		// whole code into using virtual files and writing them after close
-		// would be more appropriate.
-	} else {
-		error("file_open: unsupported mode %d (filename '%s')", mode, englishName.c_str());
-	}
-
-	if (!inFile && !outFile) { // Failed
-		debugC(kDebugLevelFile, "  -> file_open() failed");
-		return SIGNAL_REG;
-	}
-
-	// Find a free file handle
-	uint handle = 1; // Ignore _fileHandles[0]
-	while ((handle < s->_fileHandles.size()) && s->_fileHandles[handle].isOpen())
-		handle++;
-
-	if (handle == s->_fileHandles.size()) {
-		// Hit size limit => Allocate more space
-		s->_fileHandles.resize(s->_fileHandles.size() + 1);
-	}
-
-	s->_fileHandles[handle]._in = inFile;
-	s->_fileHandles[handle]._out = outFile;
-	s->_fileHandles[handle]._name = englishName;
-
-	debugC(kDebugLevelFile, "  -> opened file '%s' with handle %d", englishName.c_str(), handle);
-	return make_reg(0, handle);
-}
+extern reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool unwrapFilename);
+extern FileHandle *getFileFromHandle(EngineState *s, uint handle);
+extern int fgets_wrapper(EngineState *s, char *dest, int maxsize, int handle);
+extern void listSavegames(Common::Array<SavegameDesc> &saves);
+extern int findSavegame(Common::Array<SavegameDesc> &saves, int16 savegameId);
 
 reg_t kFOpen(EngineState *s, int argc, reg_t *argv) {
 	Common::String name = s->_segMan->getString(argv[0]);
@@ -169,20 +55,6 @@ reg_t kFOpen(EngineState *s, int argc, reg_t *argv) {
 	return file_open(s, name, mode, true);
 }
 
-static FileHandle *getFileFromHandle(EngineState *s, uint handle) {
-	if (handle == 0 || handle == VIRTUALFILE_HANDLE) {
-		error("Attempt to use invalid file handle (%d)", handle);
-		return 0;
-	}
-
-	if ((handle >= s->_fileHandles.size()) || !s->_fileHandles[handle].isOpen()) {
-		warning("Attempt to use invalid/unused file handle %d", handle);
-		return 0;
-	}
-
-	return &s->_fileHandles[handle];
-}
-
 reg_t kFClose(EngineState *s, int argc, reg_t *argv) {
 	debugC(kDebugLevelFile, "kFClose(%d)", argv[0].toUint16());
 	if (argv[0] != SIGNAL_REG) {
@@ -204,33 +76,6 @@ reg_t kFPuts(EngineState *s, int argc, reg_t *argv) {
 	return s->r_acc;
 }
 
-static int fgets_wrapper(EngineState *s, char *dest, int maxsize, int handle) {
-	FileHandle *f = getFileFromHandle(s, handle);
-	if (!f)
-		return 0;
-
-	if (!f->_in) {
-		error("fgets_wrapper: Trying to read from file '%s' opened for writing", f->_name.c_str());
-		return 0;
-	}
-	int readBytes = 0;
-	if (maxsize > 1) {
-		memset(dest, 0, maxsize);
-		f->_in->readLine(dest, maxsize);
-		readBytes = strlen(dest); // FIXME: sierra sci returned byte count and didn't react on NUL characters
-		// The returned string must not have an ending LF
-		if (readBytes > 0) {
-			if (dest[readBytes - 1] == 0x0A)
-				dest[readBytes - 1] = 0;
-		}
-	} else {
-		*dest = 0;
-	}
-
-	debugC(kDebugLevelFile, "  -> FGets'ed \"%s\"", dest);
-	return readBytes;
-}
-
 reg_t kFGets(EngineState *s, int argc, reg_t *argv) {
 	int maxsize = argv[1].toUint16();
 	char *buf = new char[maxsize];
@@ -257,9 +102,6 @@ reg_t kGetCWD(EngineState *s, int argc, reg_t *argv) {
 	return argv[0];
 }
 
-static void listSavegames(Common::Array<SavegameDesc> &saves);
-static int findSavegame(Common::Array<SavegameDesc> &saves, int16 saveId);
-
 enum {
 	K_DEVICE_INFO_GET_DEVICE = 0,
 	K_DEVICE_INFO_GET_CURRENT_DEVICE = 1,
@@ -393,83 +235,6 @@ reg_t kCheckFreeSpace(EngineState *s, int argc, reg_t *argv) {
 	return make_reg(0, 1);
 }
 
-static bool _savegame_sort_byDate(const SavegameDesc &l, const SavegameDesc &r) {
-	if (l.date != r.date)
-		return (l.date > r.date);
-	return (l.time > r.time);
-}
-
-// Create a sorted array containing all found savedgames
-static void listSavegames(Common::Array<SavegameDesc> &saves) {
-	Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
-
-	// Load all saves
-	Common::StringArray saveNames = saveFileMan->listSavefiles(g_sci->getSavegamePattern());
-
-	for (Common::StringArray::const_iterator iter = saveNames.begin(); iter != saveNames.end(); ++iter) {
-		Common::String filename = *iter;
-		Common::SeekableReadStream *in;
-		if ((in = saveFileMan->openForLoading(filename))) {
-			SavegameMetadata meta;
-			if (!get_savegame_metadata(in, &meta) || meta.name.empty()) {
-				// invalid
-				delete in;
-				continue;
-			}
-			delete in;
-
-			SavegameDesc desc;
-			desc.id = strtol(filename.end() - 3, NULL, 10);
-			desc.date = meta.saveDate;
-			// We need to fix date in here, because we save DDMMYYYY instead of
-			// YYYYMMDD, so sorting wouldn't work
-			desc.date = ((desc.date & 0xFFFF) << 16) | ((desc.date & 0xFF0000) >> 8) | ((desc.date & 0xFF000000) >> 24);
-			desc.time = meta.saveTime;
-			desc.version = meta.version;
-
-			if (meta.name.lastChar() == '\n')
-				meta.name.deleteLastChar();
-
-			Common::strlcpy(desc.name, meta.name.c_str(), SCI_MAX_SAVENAME_LENGTH);
-
-			debug(3, "Savegame in file %s ok, id %d", filename.c_str(), desc.id);
-
-			saves.push_back(desc);
-		}
-	}
-
-	// Sort the list by creation date of the saves
-	Common::sort(saves.begin(), saves.end(), _savegame_sort_byDate);
-}
-
-// Find a savedgame according to virtualId and return the position within our array
-static int findSavegame(Common::Array<SavegameDesc> &saves, int16 savegameId) {
-	for (uint saveNr = 0; saveNr < saves.size(); saveNr++) {
-		if (saves[saveNr].id == savegameId)
-			return saveNr;
-	}
-	return -1;
-}
-
-// The scripts get IDs ranging from 100->199, because the scripts require us to assign unique ids THAT EVEN STAY BETWEEN
-//  SAVES and the scripts also use "saves-count + 1" to create a new savedgame slot.
-//  SCI1.1 actually recycles ids, in that case we will currently get "0".
-// This behavior is required especially for LSL6. In this game, it's possible to quick save. The scripts will use
-//  the last-used id for that feature. If we don't assign sticky ids, the feature will overwrite different saves all the
-//  time. And sadly we can't just use the actual filename ids directly, because of the creation method for new slots.
-
-bool Console::cmdListSaves(int argc, const char **argv) {
-	Common::Array<SavegameDesc> saves;
-	listSavegames(saves);
-
-	for (uint i = 0; i < saves.size(); i++) {
-		Common::String filename = g_sci->getSavegameName(saves[i].id);
-		DebugPrintf("%s: '%s'\n", filename.c_str(), saves[i].name);
-	}
-
-	return true;
-}
-
 reg_t kCheckSaveGame(EngineState *s, int argc, reg_t *argv) {
 	Common::String game_id = s->_segMan->getString(argv[0]);
 	uint16 virtualId = argv[1].toUint16();
@@ -989,104 +754,6 @@ reg_t kFileIOSeek(EngineState *s, int argc, reg_t *argv) {
 	return SIGNAL_REG;
 }
 
-void DirSeeker::addAsVirtualFiles(Common::String title, Common::String fileMask) {
-	Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
-	Common::StringArray foundFiles = saveFileMan->listSavefiles(fileMask);
-	if (!foundFiles.empty()) {
-		_files.push_back(title);
-		_virtualFiles.push_back("");
-		Common::StringArray::iterator it;
-		Common::StringArray::iterator it_end = foundFiles.end();
-
-		for (it = foundFiles.begin(); it != it_end; it++) {
-			Common::String regularFilename = *it;
-			Common::String wrappedFilename = Common::String(regularFilename.c_str() + fileMask.size() - 1);
-
-			Common::SeekableReadStream *testfile = saveFileMan->openForLoading(regularFilename);
-			int32 testfileSize = testfile->size();
-			delete testfile;
-			if (testfileSize > 1024) // check, if larger than 1k. in that case its a saved game.
-				continue; // and we dont want to have those in the list
-			// We need to remove the prefix for display purposes
-			_files.push_back(wrappedFilename);
-			// but remember the actual name as well
-			_virtualFiles.push_back(regularFilename);
-		}
-	}
-}
-
-Common::String DirSeeker::getVirtualFilename(uint fileNumber) {
-	if (fileNumber >= _virtualFiles.size())
-		error("invalid virtual filename access");
-	return _virtualFiles[fileNumber];
-}
-
-reg_t DirSeeker::firstFile(const Common::String &mask, reg_t buffer, SegManager *segMan) {
-	// Verify that we are given a valid buffer
-	if (!buffer.segment) {
-		error("DirSeeker::firstFile('%s') invoked with invalid buffer", mask.c_str());
-		return NULL_REG;
-	}
-	_outbuffer = buffer;
-	_files.clear();
-	_virtualFiles.clear();
-
-	int QfGImport = g_sci->inQfGImportRoom();
-	if (QfGImport) {
-		_files.clear();
-		addAsVirtualFiles("-QfG1-", "qfg1-*");
-		addAsVirtualFiles("-QfG1VGA-", "qfg1vga-*");
-		if (QfGImport > 2)
-			addAsVirtualFiles("-QfG2-", "qfg2-*");
-		if (QfGImport > 3)
-			addAsVirtualFiles("-QfG3-", "qfg3-*");
-
-		if (QfGImport == 3) {
-			// QfG3 sorts the filelisting itself, we can't let that happen otherwise our
-			//  virtual list would go out-of-sync
-			reg_t savedHeros = segMan->findObjectByName("savedHeros");
-			if (!savedHeros.isNull())
-				writeSelectorValue(segMan, savedHeros, SELECTOR(sort), 0);
-		}
-
-	} else {
-		// Prefix the mask
-		const Common::String wrappedMask = g_sci->wrapFilename(mask);
-
-		// Obtain a list of all files matching the given mask
-		Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
-		_files = saveFileMan->listSavefiles(wrappedMask);
-	}
-
-	// Reset the list iterator and write the first match to the output buffer,
-	// if any.
-	_iter = _files.begin();
-	return nextFile(segMan);
-}
-
-reg_t DirSeeker::nextFile(SegManager *segMan) {
-	if (_iter == _files.end()) {
-		return NULL_REG;
-	}
-
-	Common::String string;
-
-	if (_virtualFiles.empty()) {
-		// Strip the prefix, if we don't got a virtual filelisting
-		const Common::String wrappedString = *_iter;
-		string = g_sci->unwrapFilename(wrappedString);
-	} else {
-		string = *_iter;
-	}
-	if (string.size() > 12)
-		string = Common::String(string.c_str(), 12);
-	segMan->strcpy(_outbuffer, string.c_str());
-
-	// Return the result and advance the list iterator :)
-	++_iter;
-	return _outbuffer;
-}
-
 reg_t kFileIOFindFirst(EngineState *s, int argc, reg_t *argv) {
 	Common::String mask = s->_segMan->getString(argv[0]);
 	reg_t buf = argv[1];
diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h
index 6f1f6a6..78a8a5b 100644
--- a/engines/sci/engine/state.h
+++ b/engines/sci/engine/state.h
@@ -34,6 +34,7 @@ class WriteStream;
 }
 
 #include "sci/sci.h"
+#include "sci/engine/file.h"
 #include "sci/engine/seg_manager.h"
 
 #include "sci/parser/vocabulary.h"
@@ -42,6 +43,8 @@ class WriteStream;
 
 namespace Sci {
 
+class FileHandle;
+class DirSeeker;
 class EventManager;
 class MessageState;
 class SoundCommandParser;
@@ -54,32 +57,6 @@ enum AbortGameState {
 	kAbortQuitGame = 3
 };
 
-class DirSeeker {
-protected:
-	reg_t _outbuffer;
-	Common::StringArray _files;
-	Common::StringArray _virtualFiles;
-	Common::StringArray::const_iterator _iter;
-
-public:
-	DirSeeker() {
-		_outbuffer = NULL_REG;
-		_iter = _files.begin();
-	}
-
-	reg_t firstFile(const Common::String &mask, reg_t buffer, SegManager *segMan);
-	reg_t nextFile(SegManager *segMan);
-
-	Common::String getVirtualFilename(uint fileNumber);
-
-private:
-	void addAsVirtualFiles(Common::String title, Common::String fileMask);
-};
-
-enum {
-	MAX_SAVEGAME_NR = 20 /**< Maximum number of savegames */
-};
-
 // We assume that scripts give us savegameId 0->99 for creating a new save slot
 //  and savegameId 100->199 for existing save slots ffs. kfile.cpp
 enum {
@@ -93,20 +70,6 @@ enum {
 	GAMEISRESTARTING_RESTORE = 2
 };
 
-class FileHandle {
-public:
-	Common::String _name;
-	Common::SeekableReadStream *_in;
-	Common::WriteStream *_out;
-
-public:
-	FileHandle();
-	~FileHandle();
-
-	void close();
-	bool isOpen() const;
-};
-
 enum VideoFlags {
 	kNone            = 0,
 	kDoubled         = 1 << 0,


Commit: 944a774e6a7fd604b0754569007e5e34d1be915f
    https://github.com/scummvm/scummvm/commit/944a774e6a7fd604b0754569007e5e34d1be915f
Author: Filippos Karapetis (md5 at scummvm.org)
Date: 2012-06-13T02:26:55-07:00

Commit Message:
SCI: Change kSave() to be a kernel function with subops

Changed paths:
    engines/sci/engine/kernel.h
    engines/sci/engine/kernel_tables.h
    engines/sci/engine/kfile.cpp



diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index 25ca082..d64bc42 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -461,6 +461,7 @@ reg_t kMakeSaveFileName(EngineState *s, int argc, reg_t *argv);
 // SCI2.1 Kernel Functions
 reg_t kText(EngineState *s, int argc, reg_t *argv);
 reg_t kSave(EngineState *s, int argc, reg_t *argv);
+reg_t kAutoSave(EngineState *s, int argc, reg_t *argv);
 reg_t kList(EngineState *s, int argc, reg_t *argv);
 reg_t kRobot(EngineState *s, int argc, reg_t *argv);
 reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 9b76528..cdc810e 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -245,6 +245,18 @@ static const SciKernelMapSubEntry kFileIO_subops[] = {
 	SCI_SUBOPENTRY_TERMINATOR
 };
 
+static const SciKernelMapSubEntry kSave_subops[] = {
+	{ SIG_SCI32,           0, MAP_CALL(SaveGame),                  "[r0]i[r0](r)",         NULL },
+	{ SIG_SCI32,           1, MAP_CALL(RestoreGame),               "[r0]i[r0]",            NULL },
+	{ SIG_SCI32,           2, MAP_CALL(GetSaveDir),                "(r*)",                 NULL },
+	{ SIG_SCI32,           3, MAP_CALL(CheckSaveGame),             ".*",                   NULL },
+	// Subop 4 hasn't been encountered yet
+	{ SIG_SCI32,           5, MAP_CALL(GetSaveFiles),              "rrr",                  NULL },
+	{ SIG_SCI32,           6, MAP_CALL(MakeSaveCatName),           "rr",                   NULL },
+	{ SIG_SCI32,           7, MAP_CALL(MakeSaveFileName),          "rri",                  NULL },
+	{ SIG_SCI32,           8, MAP_CALL(AutoSave),                  "[o0]",                 NULL },
+};
+
 #ifdef ENABLE_SCI32
 //    version,         subId, function-mapping,                    signature,              workarounds
 static const SciKernelMapSubEntry kList_subops[] = {
@@ -555,7 +567,7 @@ static SciKernelMapEntry s_kernelMap[] = {
 	{ MAP_CALL(MulDiv),            SIG_EVERYWHERE,           "iii",                   NULL,            NULL },
 	{ MAP_CALL(PlayVMD),           SIG_EVERYWHERE,           "(.*)",                  NULL,            NULL },
 	{ MAP_CALL(Robot),             SIG_EVERYWHERE,           "(.*)",                  NULL,            NULL },
-	{ MAP_CALL(Save),              SIG_EVERYWHERE,           "(.*)",                  NULL,            NULL },
+	{ MAP_CALL(Save),              SIG_EVERYWHERE,           "i(.*)",                 kSave_subops,    NULL },
 	{ MAP_CALL(Text),              SIG_EVERYWHERE,           "(.*)",                  NULL,            NULL },
 	{ MAP_CALL(AddPicAt),          SIG_EVERYWHERE,           "oiii",                  NULL,            NULL },
 	{ MAP_CALL(GetWindowsOption),  SIG_EVERYWHERE,           "i",                     NULL,            NULL },
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index 36e5273..fe54987 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -946,35 +946,21 @@ reg_t kMakeSaveFileName(EngineState *s, int argc, reg_t *argv) {
 	return argv[0];
 }
 
+reg_t kAutoSave(EngineState *s, int argc, reg_t *argv) {
+	// TODO
+	// This is a timer callback, with 1 parameter: the timer object
+	// (e.g. "timers").
+	// It's used for auto-saving (i.e. save every X minutes, by checking
+	// the elapsed time from the timer object)
+
+	// This function has to return something other than 0 to proceed
+	return s->r_acc;
+}
+
 reg_t kSave(EngineState *s, int argc, reg_t *argv) {
-	switch (argv[0].toUint16()) {
-	case 0:
-		return kSaveGame(s, argc - 1,argv + 1);
-	case 1:
-		return kRestoreGame(s, argc - 1,argv + 1);
-	case 2:
-		return kGetSaveDir(s, argc - 1, argv + 1);
-	case 3:
-		return kCheckSaveGame(s, argc - 1, argv + 1);
-	case 5:
-		return kGetSaveFiles(s, argc - 1, argv + 1);
-	case 6:
-		return kMakeSaveCatName(s, argc - 1, argv + 1);
-	case 7:
-		return kMakeSaveFileName(s, argc - 1, argv + 1);
-	case 8:
-		// TODO
-		// This is a timer callback, with 1 parameter: the timer object
-		// (e.g. "timers").
-		// It's used for auto-saving (i.e. save every X minutes, by checking
-		// the elapsed time from the timer object)
-
-		// This function has to return something other than 0 to proceed
-		return s->r_acc;
-	default:
-		kStub(s, argc, argv);
-		return NULL_REG;
-	}
+	if (!s)
+		return make_reg(0, getSciVersion());
+	error("not supposed to call this");
 }
 
 #endif


Commit: 098f162ecc4951873909e9815506d4053178b6f9
    https://github.com/scummvm/scummvm/commit/098f162ecc4951873909e9815506d4053178b6f9
Author: Filippos Karapetis (md5 at scummvm.org)
Date: 2012-06-13T02:26:57-07:00

Commit Message:
SCI: Use the later SCI file functions for the SCI0 ones

They are essentially the same (with the exception of the return values),
so unifying them reduces code duplication

Changed paths:
    engines/sci/engine/kernel.h
    engines/sci/engine/kernel_tables.h
    engines/sci/engine/kfile.cpp



diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index d64bc42..677b790 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -323,10 +323,6 @@ reg_t kTimesCot(EngineState *s, int argc, reg_t *argv);
 reg_t kCosDiv(EngineState *s, int argc, reg_t *argv);
 reg_t kSinDiv(EngineState *s, int argc, reg_t *argv);
 reg_t kValidPath(EngineState *s, int argc, reg_t *argv);
-reg_t kFOpen(EngineState *s, int argc, reg_t *argv);
-reg_t kFPuts(EngineState *s, int argc, reg_t *argv);
-reg_t kFGets(EngineState *s, int argc, reg_t *argv);
-reg_t kFClose(EngineState *s, int argc, reg_t *argv);
 reg_t kMapKeyToDir(EngineState *s, int argc, reg_t *argv);
 reg_t kGlobalToLocal(EngineState *s, int argc, reg_t *argv);
 reg_t kLocalToGlobal(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index cdc810e..d093310 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -350,10 +350,10 @@ static SciKernelMapEntry s_kernelMap[] = {
 	{ MAP_CALL(EditControl),       SIG_EVERYWHERE,           "[o0][o0]",              NULL,            NULL },
 	{ MAP_CALL(Empty),             SIG_EVERYWHERE,           "(.*)",                  NULL,            NULL },
 	{ MAP_CALL(EmptyList),         SIG_EVERYWHERE,           "l",                     NULL,            NULL },
-	{ MAP_CALL(FClose),            SIG_EVERYWHERE,           "i",                     NULL,            NULL },
-	{ MAP_CALL(FGets),             SIG_EVERYWHERE,           "rii",                   NULL,            NULL },
-	{ MAP_CALL(FOpen),             SIG_EVERYWHERE,           "ri",                    NULL,            NULL },
-	{ MAP_CALL(FPuts),             SIG_EVERYWHERE,           "ir",                    NULL,            NULL },
+	{ "FClose", kFileIOClose,      SIG_EVERYWHERE,           "i",                     NULL,            NULL },
+	{ "FGets", kFileIOReadString,  SIG_EVERYWHERE,           "rii",                   NULL,            NULL },
+	{ "FOpen", kFileIOOpen,        SIG_EVERYWHERE,           "ri",                    NULL,            NULL },
+	{ "FPuts", kFileIOWriteString, SIG_EVERYWHERE,           "ir",                    NULL,            NULL },
 	{ MAP_CALL(FileIO),            SIG_EVERYWHERE,           "i(.*)",                 kFileIO_subops,  NULL },
 	{ MAP_CALL(FindKey),           SIG_EVERYWHERE,           "l.",                    NULL,            kFindKey_workarounds },
 	{ MAP_CALL(FirstNode),         SIG_EVERYWHERE,           "[l0]",                  NULL,            NULL },
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index fe54987..0523329 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -47,47 +47,6 @@ extern int fgets_wrapper(EngineState *s, char *dest, int maxsize, int handle);
 extern void listSavegames(Common::Array<SavegameDesc> &saves);
 extern int findSavegame(Common::Array<SavegameDesc> &saves, int16 savegameId);
 
-reg_t kFOpen(EngineState *s, int argc, reg_t *argv) {
-	Common::String name = s->_segMan->getString(argv[0]);
-	int mode = argv[1].toUint16();
-
-	debugC(kDebugLevelFile, "kFOpen(%s,0x%x)", name.c_str(), mode);
-	return file_open(s, name, mode, true);
-}
-
-reg_t kFClose(EngineState *s, int argc, reg_t *argv) {
-	debugC(kDebugLevelFile, "kFClose(%d)", argv[0].toUint16());
-	if (argv[0] != SIGNAL_REG) {
-		FileHandle *f = getFileFromHandle(s, argv[0].toUint16());
-		if (f)
-			f->close();
-	}
-	return s->r_acc;
-}
-
-reg_t kFPuts(EngineState *s, int argc, reg_t *argv) {
-	int handle = argv[0].toUint16();
-	Common::String data = s->_segMan->getString(argv[1]);
-
-	FileHandle *f = getFileFromHandle(s, handle);
-	if (f)
-		f->_out->write(data.c_str(), data.size());
-
-	return s->r_acc;
-}
-
-reg_t kFGets(EngineState *s, int argc, reg_t *argv) {
-	int maxsize = argv[1].toUint16();
-	char *buf = new char[maxsize];
-	int handle = argv[2].toUint16();
-
-	debugC(kDebugLevelFile, "kFGets(%d, %d)", handle, maxsize);
-	int readBytes = fgets_wrapper(s, buf, maxsize, handle);
-	s->_segMan->memcpy(argv[0], (const byte*)buf, maxsize);
-	delete[] buf;
-	return readBytes ? argv[0] : NULL_REG;
-}
-
 /**
  * Writes the cwd to the supplied address and returns the address in acc.
  */
@@ -559,6 +518,9 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) {
 reg_t kFileIOClose(EngineState *s, int argc, reg_t *argv) {
 	debugC(kDebugLevelFile, "kFileIO(close): %d", argv[0].toUint16());
 
+	if (argv[0] == SIGNAL_REG)
+		return s->r_acc;
+	
 	uint16 handle = argv[0].toUint16();
 
 #ifdef ENABLE_SCI32
@@ -571,8 +533,13 @@ reg_t kFileIOClose(EngineState *s, int argc, reg_t *argv) {
 	FileHandle *f = getFileFromHandle(s, handle);
 	if (f) {
 		f->close();
+		if (getSciVersion() <= SCI_VERSION_0_LATE)
+			return s->r_acc;	// SCI0 semantics: no value returned
 		return SIGNAL_REG;
 	}
+
+	if (getSciVersion() <= SCI_VERSION_0_LATE)
+		return s->r_acc;	// SCI0 semantics: no value returned
 	return NULL_REG;
 }
 
@@ -635,20 +602,20 @@ reg_t kFileIOWriteRaw(EngineState *s, int argc, reg_t *argv) {
 }
 
 reg_t kFileIOReadString(EngineState *s, int argc, reg_t *argv) {
-	uint16 size = argv[1].toUint16();
-	char *buf = new char[size];
+	uint16 maxsize = argv[1].toUint16();
+	char *buf = new char[maxsize];
 	uint16 handle = argv[2].toUint16();
-	debugC(kDebugLevelFile, "kFileIO(readString): %d, %d", handle, size);
+	debugC(kDebugLevelFile, "kFileIO(readString): %d, %d", handle, maxsize);
 	uint32 bytesRead;
 
 #ifdef ENABLE_SCI32
 	if (handle == VIRTUALFILE_HANDLE)
-		bytesRead = s->_virtualIndexFile->readLine(buf, size);
+		bytesRead = s->_virtualIndexFile->readLine(buf, maxsize);
 	else
 #endif
-		bytesRead = fgets_wrapper(s, buf, size, handle);
+		bytesRead = fgets_wrapper(s, buf, maxsize, handle);
 
-	s->_segMan->memcpy(argv[0], (const byte*)buf, size);
+	s->_segMan->memcpy(argv[0], (const byte*)buf, maxsize);
 	delete[] buf;
 	return bytesRead ? argv[0] : NULL_REG;
 }
@@ -669,9 +636,13 @@ reg_t kFileIOWriteString(EngineState *s, int argc, reg_t *argv) {
 
 	if (f) {
 		f->_out->write(str.c_str(), str.size());
+		if (getSciVersion() <= SCI_VERSION_0_LATE)
+			return s->r_acc;	// SCI0 semantics: no value returned
 		return NULL_REG;
 	}
 
+	if (getSciVersion() <= SCI_VERSION_0_LATE)
+		return s->r_acc;	// SCI0 semantics: no value returned
 	return make_reg(0, 6); // DOS - invalid handle
 }
 


Commit: 694f0f534a548061c3fecec3c8b0be0e0e5310dd
    https://github.com/scummvm/scummvm/commit/694f0f534a548061c3fecec3c8b0be0e0e5310dd
Author: Filippos Karapetis (md5 at scummvm.org)
Date: 2012-06-13T02:26:58-07:00

Commit Message:
SCI: Only include kSave_subops if ENABLE_SCI32 is defined

Changed paths:
    engines/sci/engine/kernel_tables.h



diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index d093310..6965a5d 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -245,6 +245,8 @@ static const SciKernelMapSubEntry kFileIO_subops[] = {
 	SCI_SUBOPENTRY_TERMINATOR
 };
 
+#ifdef ENABLE_SCI32
+
 static const SciKernelMapSubEntry kSave_subops[] = {
 	{ SIG_SCI32,           0, MAP_CALL(SaveGame),                  "[r0]i[r0](r)",         NULL },
 	{ SIG_SCI32,           1, MAP_CALL(RestoreGame),               "[r0]i[r0]",            NULL },
@@ -255,9 +257,9 @@ static const SciKernelMapSubEntry kSave_subops[] = {
 	{ SIG_SCI32,           6, MAP_CALL(MakeSaveCatName),           "rr",                   NULL },
 	{ SIG_SCI32,           7, MAP_CALL(MakeSaveFileName),          "rri",                  NULL },
 	{ SIG_SCI32,           8, MAP_CALL(AutoSave),                  "[o0]",                 NULL },
+	SCI_SUBOPENTRY_TERMINATOR
 };
 
-#ifdef ENABLE_SCI32
 //    version,         subId, function-mapping,                    signature,              workarounds
 static const SciKernelMapSubEntry kList_subops[] = {
 	{ SIG_SCI21,           0, MAP_CALL(NewList),                   "",                     NULL },


Commit: e2613d22423fe2108e13909279b2f336a8a3209d
    https://github.com/scummvm/scummvm/commit/e2613d22423fe2108e13909279b2f336a8a3209d
Author: Filippos Karapetis (md5 at scummvm.org)
Date: 2012-06-13T02:27:00-07:00

Commit Message:
SCI: Add a workaround for the French version of Torin's Passage

Thanks to LePhilousophe for playing and providing the workaround

Changed paths:
    engines/sci/engine/workarounds.cpp



diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index c1d4a3d..ecb1e4c 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -167,6 +167,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
 	{ GID_SQ6,            -1,     0,  0,                "SQ6", "init",           -1,    2, { WORKAROUND_FAKE,   0 } }, // Demo and full version: called when the game starts (demo: room 0, full: room 100)
 	{ GID_SQ6,           100, 64950,  0,               "View", "handleEvent",    -1,    0, { WORKAROUND_FAKE,   0 } }, // called when pressing "Start game" in the main menu
 	{ GID_SQ6,            -1, 64964,  0,              "DPath", "init",           -1,    1, { WORKAROUND_FAKE,   0 } }, // during the game
+	{ GID_TORIN,          -1, 64017,  0,             "oFlags", "clear",          -1,    0, { WORKAROUND_FAKE,   0 } }, // entering Torin's home in the French version
 	SCI_WORKAROUNDENTRY_TERMINATOR
 };
 


Commit: 93024c073be6d93c9369a83e4b4468bb0aaeeadd
    https://github.com/scummvm/scummvm/commit/93024c073be6d93c9369a83e4b4468bb0aaeeadd
Author: Filippos Karapetis (md5 at scummvm.org)
Date: 2012-06-13T02:27:02-07:00

Commit Message:
SCI: Handle the torindebug config setting for Torin's Passage French

Thanks to LePhilousophe for testing and providing a patch

Changed paths:
    engines/sci/engine/kmisc.cpp



diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp
index 1cbaf07..47c891e 100644
--- a/engines/sci/engine/kmisc.cpp
+++ b/engines/sci/engine/kmisc.cpp
@@ -384,6 +384,10 @@ reg_t kGetConfig(EngineState *s, int argc, reg_t *argv) {
 	} else if (setting == "language") {
 		Common::String languageId = Common::String::format("%d", g_sci->getSciLanguage());
 		s->_segMan->strcpy(data, languageId.c_str());
+	} else if (setting == "torindebug") {
+		// Used to enable the debug mode in Torin's Passage (French).
+		// If true, the debug mode is enabled.
+		s->_segMan->strcpy(data, "");
 	} else {
 		error("GetConfig: Unknown configuration setting %s", setting.c_str());
 	}






More information about the Scummvm-git-logs mailing list