Skip to content

Commit

Permalink
SCI: Implement the file operations needed for the save dialog in Phan…
Browse files Browse the repository at this point in the history
…tasmagoria

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
  • Loading branch information
bluegr committed Jun 13, 2012
1 parent f76c71d commit aeac51d
Show file tree
Hide file tree
Showing 6 changed files with 351 additions and 37 deletions.
139 changes: 139 additions & 0 deletions 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
75 changes: 75 additions & 0 deletions 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

0 comments on commit aeac51d

Please sign in to comment.