scummvm/backends/platform/dc/vmsave.cpp

437 lines
9.5 KiB
C++
Raw Normal View History

/* 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.
2002-02-02 23:36:35 +00:00
*
* 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.
*
2002-02-02 23:36:35 +00:00
* 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.
*
2002-02-02 23:36:35 +00:00
* 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.
2002-02-02 23:36:35 +00:00
*
*/
2011-06-06 23:04:15 +02:00
#define FORBIDDEN_SYMBOL_ALLOW_ALL
#include <common/scummsys.h>
#include "engines/engine.h"
2002-02-02 23:36:35 +00:00
#include "dc.h"
#include "icon.h"
#include <common/savefile.h>
#include <gui/gui-manager.h>
#include <gui/message.h>
#include <common/zlib.h>
2002-02-02 23:36:35 +00:00
2002-02-27 01:02:16 +00:00
// Savegame can not be bigger than this
2002-02-27 01:02:16 +00:00
#define MAX_SAVE_SIZE (128*1024)
2002-02-02 23:36:35 +00:00
enum vmsaveResult {
VMSAVE_OK,
VMSAVE_NOVM,
VMSAVE_NOSPACE,
VMSAVE_WRITEERROR
2002-02-02 23:36:35 +00:00
};
static int lastvm=-1;
static void displaySaveResult(vmsaveResult res)
{
char buf[1024];
switch(res) {
case VMSAVE_OK:
sprintf(buf, "Game saved on unit %c%d", 'A'+(lastvm/6), lastvm%6);
break;
case VMSAVE_NOVM:
strcpy(buf, "No memory card present!");
break;
case VMSAVE_NOSPACE:
strcpy(buf, "Not enough space available!");
break;
case VMSAVE_WRITEERROR:
strcpy(buf, "Write error!!!");
break;
default:
strcpy(buf, "Unknown error!!!");
break;
}
GUI::MessageDialog dialog(buf);
dialog.runModal();
}
static vmsaveResult trySave(const char *gamename, const char *data, int size,
2002-02-02 23:36:35 +00:00
const char *filename, class Icon &icon, int vm)
{
struct vmsinfo info;
struct superblock super;
struct vms_file file;
struct vms_file_header header;
struct timestamp tstamp;
struct tm tm;
time_t t;
unsigned char iconbuffer[512+32];
2007-09-18 20:16:33 +00:00
if (!vmsfs_check_unit(vm, 0, &info))
return VMSAVE_NOVM;
2007-09-18 20:16:33 +00:00
if (!vmsfs_get_superblock(&info, &super))
return VMSAVE_NOVM;
2002-02-02 23:36:35 +00:00
int free_cnt = vmsfs_count_free(&super);
2007-09-18 20:16:33 +00:00
if (vmsfs_open_file(&super, filename, &file))
free_cnt += file.blks;
2007-09-18 20:16:33 +00:00
if (((128+512+size+511)>>9) > free_cnt)
return VMSAVE_NOSPACE;
2002-02-02 23:36:35 +00:00
memset(&header, 0, sizeof(header));
strncpy(header.shortdesc, "ScummVM savegame", 16);
strncpy(header.longdesc, gamename, 32);
2002-02-02 23:36:35 +00:00
strncpy(header.id, "ScummVM", 16);
icon.create_vmicon(iconbuffer);
header.numicons = 1;
memcpy(header.palette, iconbuffer, sizeof(header.palette));
time(&t);
tm = *localtime(&t);
tstamp.year = tm.tm_year+1900;
tstamp.month = tm.tm_mon+1;
tstamp.day = tm.tm_mday;
tstamp.hour = tm.tm_hour;
tstamp.minute = tm.tm_min;
tstamp.second = tm.tm_sec;
tstamp.wkday = (tm.tm_wday+6)%7;
vmsfs_beep(&info, 1);
vmsfs_errno = 0;
2007-09-18 20:16:33 +00:00
if (!vmsfs_create_file(&super, filename, &header,
2002-02-02 23:36:35 +00:00
iconbuffer+sizeof(header.palette), NULL,
data, size, &tstamp)) {
fprintf(stderr, "%s\n", vmsfs_describe_error());
vmsfs_beep(&info, 0);
return VMSAVE_WRITEERROR;
2002-02-02 23:36:35 +00:00
}
vmsfs_beep(&info, 0);
return VMSAVE_OK;
}
static bool tryLoad(char *&buffer, int &size, const char *filename, int vm)
{
struct vmsinfo info;
struct superblock super;
struct vms_file file;
2007-09-18 20:16:33 +00:00
if (!vmsfs_check_unit(vm, 0, &info))
return false;
2007-09-18 20:16:33 +00:00
if (!vmsfs_get_superblock(&info, &super))
return false;
2007-09-18 20:16:33 +00:00
if (!vmsfs_open_file(&super, filename, &file))
return false;
2002-02-02 23:36:35 +00:00
buffer = new char[size = file.size];
2007-09-18 20:16:33 +00:00
if (vmsfs_read_file(&file, (unsigned char *)buffer, size))
return true;
2002-02-02 23:36:35 +00:00
delete[] buffer;
buffer = NULL;
2002-02-02 23:36:35 +00:00
return false;
}
static bool tryDelete(const char *filename, int vm)
{
struct vmsinfo info;
struct superblock super;
if (!vmsfs_check_unit(vm, 0, &info))
return false;
if (!vmsfs_get_superblock(&info, &super))
return false;
if (!vmsfs_delete_file(&super, filename))
return false;
return true;
}
static void tryList(const Common::String &glob, int vm, Common::StringArray &list)
{
struct vmsinfo info;
struct superblock super;
struct dir_iterator iter;
struct dir_entry de;
2007-09-18 20:16:33 +00:00
if (!vmsfs_check_unit(vm, 0, &info))
return;
2007-09-18 20:16:33 +00:00
if (!vmsfs_get_superblock(&info, &super))
return;
vmsfs_open_dir(&super, &iter);
2007-09-18 20:16:33 +00:00
while (vmsfs_next_dir_entry(&iter, &de))
if (de.entry[0]) {
char buf[16];
strncpy(buf, (char *)de.entry+4, 12);
buf[12] = 0;
if (Common::matchString(buf, glob.c_str()))
list.push_back(buf);
}
}
vmsaveResult writeSaveGame(const char *gamename, const char *data, int size,
2002-02-02 23:36:35 +00:00
const char *filename, class Icon &icon)
{
vmsaveResult r, res = VMSAVE_NOVM;
2007-09-18 20:16:33 +00:00
if (lastvm >= 0 &&
(res = trySave(gamename, data, size, filename, icon, lastvm)) == VMSAVE_OK)
return res;
2002-02-02 23:36:35 +00:00
2007-09-18 20:16:33 +00:00
for (int i=0; i<24; i++)
if ((r = trySave(gamename, data, size, filename, icon, i)) == VMSAVE_OK) {
lastvm = i;
return r;
} else if (r > res)
res = r;
2002-02-02 23:36:35 +00:00
return res;
}
bool readSaveGame(char *&buffer, int &size, const char *filename)
{
2007-09-18 20:16:33 +00:00
if (lastvm >= 0 &&
tryLoad(buffer, size, filename, lastvm))
return true;
2002-02-02 23:36:35 +00:00
2007-09-18 20:16:33 +00:00
for (int i=0; i<24; i++)
if (tryLoad(buffer, size, filename, i)) {
lastvm = i;
return true;
}
2002-02-02 23:36:35 +00:00
return false;
}
bool deleteSaveGame(const char *filename)
{
if (lastvm >= 0 &&
tryDelete(filename, lastvm))
return true;
for (int i=0; i<24; i++)
if (tryDelete(filename, i)) {
lastvm = i;
return true;
}
return false;
}
2002-02-02 23:36:35 +00:00
class InVMSave : public Common::InSaveFile {
private:
2002-02-02 23:36:35 +00:00
char *buffer;
int _pos, _size;
bool _eos;
2002-02-02 23:36:35 +00:00
2021-03-30 12:39:43 +03:00
uint32 read(void *buf, uint32 cnt) override;
bool skip(uint32 offset) override;
bool seek(int32 offs, int whence) override;
public:
InVMSave()
: _pos(0), buffer(NULL), _eos(false)
{ }
~InVMSave()
{
delete[] buffer;
}
2021-03-30 12:39:43 +03:00
bool eos() const override { return _eos; }
void clearErr() override { _eos = false; }
int32 pos() const override { return _pos; }
int32 size() const override { return _size; }
2005-04-27 21:57:13 +00:00
bool readSaveGame(const char *filename)
{ return ::readSaveGame(buffer, _size, filename); }
};
class OutVMSave : public Common::WriteStream {
private:
char *buffer;
2016-08-04 13:08:25 +02:00
int _pos, size, committed;
char filename[16];
bool iofailed;
public:
uint32 write(const void *buf, uint32 cnt);
2016-08-04 13:08:25 +02:00
virtual int32 pos() const { return _pos; }
OutVMSave(const char *_filename)
: _pos(0), committed(-1), iofailed(false)
{
strncpy(filename, _filename, 16);
buffer = new char[size = MAX_SAVE_SIZE];
}
~OutVMSave();
bool err() const { return iofailed; }
void clearErr() { iofailed = false; }
2007-02-18 11:48:10 +00:00
void finalize();
};
class VMSaveManager : public Common::SaveFileManager {
2016-09-26 15:22:26 +02:00
private:
2016-09-28 16:10:16 +02:00
static int nameCompare(const unsigned char *entry, const char *match) {
return !scumm_strnicmp(reinterpret_cast<const char *>(entry), match, 12);
}
2016-09-26 15:22:26 +02:00
public:
virtual void updateSavefilesList(Common::StringArray &lockedFiles) {
// TODO: implement this (locks files, preventing them from being listed, saved or loaded)
}
2016-09-28 16:10:16 +02:00
VMSaveManager() {
vmsfs_name_compare_function = nameCompare;
}
2016-09-26 15:22:26 +02:00
virtual Common::InSaveFile *openRawFile(const Common::String &filename) {
InVMSave *s = new InVMSave();
if (s->readSaveGame(filename.c_str())) {
return s;
} else {
delete s;
return NULL;
}
}
virtual Common::OutSaveFile *openForSaving(const Common::String &filename, bool compress = true) {
OutVMSave *s = new OutVMSave(filename.c_str());
return new Common::OutSaveFile(compress ? Common::wrapCompressedWriteStream(s) : s);
}
virtual Common::InSaveFile *openForLoading(const Common::String &filename) {
InVMSave *s = new InVMSave();
if (s->readSaveGame(filename.c_str())) {
return Common::wrapCompressedReadStream(s);
} else {
delete s;
return NULL;
}
}
virtual bool removeSavefile(const Common::String &filename) {
return ::deleteSaveGame(filename.c_str());
}
virtual Common::StringArray listSavefiles(const Common::String &pattern);
};
2007-02-18 11:48:10 +00:00
void OutVMSave::finalize()
2002-02-02 23:36:35 +00:00
{
2020-11-23 12:24:54 +00:00
extern char gGameName[32];
2002-02-02 23:36:35 +00:00
extern Icon icon;
2016-08-04 13:08:25 +02:00
if (committed >= _pos)
return;
char *data = buffer;
2016-08-04 13:08:25 +02:00
int len = _pos;
vmsaveResult r = writeSaveGame(gGameName, data, len, filename, icon);
2016-08-04 13:08:25 +02:00
committed = _pos;
2007-09-18 20:16:33 +00:00
if (r != VMSAVE_OK)
iofailed = true;
displaySaveResult(r);
}
OutVMSave::~OutVMSave()
{
2007-02-18 11:48:10 +00:00
finalize();
delete[] buffer;
2002-02-02 23:36:35 +00:00
}
uint32 InVMSave::read(void *buf, uint32 cnt)
2002-02-02 23:36:35 +00:00
{
int nbyt = cnt;
if (_pos + nbyt > _size) {
cnt = (_size - _pos);
_eos = true;
nbyt = cnt;
2002-02-02 23:36:35 +00:00
}
if (nbyt)
memcpy(buf, buffer + _pos, nbyt);
_pos += nbyt;
2002-02-02 23:36:35 +00:00
return cnt;
}
bool InVMSave::skip(uint32 offset)
{
int nbyt = offset;
if (_pos + nbyt > _size)
nbyt = (_size - _pos);
_pos += nbyt;
return true;
}
bool InVMSave::seek(int32 offs, int whence)
{
switch(whence) {
case SEEK_SET:
_pos = offs;
break;
case SEEK_CUR:
_pos += offs;
break;
case SEEK_END:
_pos = _size + offs;
break;
}
2007-09-18 20:16:33 +00:00
if (_pos < 0)
_pos = 0;
2007-09-18 20:16:33 +00:00
else if (_pos > _size)
_pos = _size;
_eos = false;
return true;
}
uint32 OutVMSave::write(const void *buf, uint32 cnt)
2002-02-02 23:36:35 +00:00
{
int nbyt = cnt;
2016-08-04 13:08:25 +02:00
if (_pos + nbyt > size) {
cnt = (size - _pos);
nbyt = cnt;
2002-02-02 23:36:35 +00:00
}
if (nbyt)
memcpy(buffer + _pos, buf, nbyt);
2016-08-04 13:08:25 +02:00
_pos += nbyt;
2002-02-02 23:36:35 +00:00
return cnt;
}
Common::StringArray VMSaveManager::listSavefiles(const Common::String &pattern)
{
Common::StringArray list;
2007-09-18 20:16:33 +00:00
for (int i=0; i<24; i++)
tryList(pattern, i, list);
return list;
}
2006-10-22 17:58:38 +00:00
Common::SaveFileManager *OSystem_Dreamcast::createSavefileManager()
{
return new VMSaveManager();
}