scummvm/backends/dc/vmsave.cpp
Marcus Comstedt 12f491211d Removed dependency on GameDetector.
svn-id: r5180
2002-10-18 01:45:47 +00:00

264 lines
6.2 KiB
C++

/* ScummVM - Scumm Interpreter
* Dreamcast port
* Copyright (C) 2002 Marcus Comstedt
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#include <common/scummsys.h>
#include <common/stdafx.h>
#include <common/engine.h>
#include "dc.h"
#include "icon.h"
#include <scumm/saveload.h>
#include <ronin/zlib.h>
// Savegame can not be bigger than this, even before compression
#define MAX_SAVE_SIZE (128*1024)
enum vmsaveResult {
VMSAVE_OK,
VMSAVE_NOVM,
VMSAVE_NOSPACE,
VMSAVE_WRITEERROR,
};
static int lastvm=-1;
static vmsaveResult trySave(const char *gamename, const char *data, int size,
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];
if(!vmsfs_check_unit(vm, 0, &info))
return VMSAVE_NOVM;
if(!vmsfs_get_superblock(&info, &super))
return VMSAVE_NOVM;
int free_cnt = vmsfs_count_free(&super);
if(vmsfs_open_file(&super, filename, &file))
free_cnt += file.blks;
if(((128+512+size+511)>>9) > free_cnt)
return VMSAVE_NOSPACE;
memset(&header, 0, sizeof(header));
strncpy(header.shortdesc, "ScummVM savegame", 16);
strncpy(header.longdesc, gamename, 32);
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;
if(!vmsfs_create_file(&super, filename, &header,
iconbuffer+sizeof(header.palette), NULL,
data, size, &tstamp)) {
fprintf(stderr, "%s\n", vmsfs_describe_error());
vmsfs_beep(&info, 0);
return VMSAVE_WRITEERROR;
}
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;
struct vms_file_header header;
struct timestamp tstamp;
struct tm tm;
time_t t;
unsigned char iconbuffer[512+32];
if(!vmsfs_check_unit(vm, 0, &info))
return false;
if(!vmsfs_get_superblock(&info, &super))
return false;
if(!vmsfs_open_file(&super, filename, &file))
return false;
buffer = new char[size = file.size];
if(vmsfs_read_file(&file, (unsigned char *)buffer, size))
return true;
delete buffer;
return false;
}
vmsaveResult writeSaveGame(const char *gamename, const char *data, int size,
const char *filename, class Icon &icon)
{
vmsaveResult r, res = VMSAVE_NOVM;
if(lastvm >= 0 &&
(res = trySave(gamename, data, size, filename, icon, lastvm)) == VMSAVE_OK)
return res;
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;
return res;
}
bool readSaveGame(char *&buffer, int &size, const char *filename)
{
if(lastvm >= 0 &&
tryLoad(buffer, size, filename, lastvm))
return true;
for(int i=0; i<24; i++)
if(tryLoad(buffer, size, filename, i)) {
lastvm = i;
return true;
}
return false;
}
struct vmStreamContext {
bool issave;
char *buffer;
int pos, size;
char filename[16];
};
bool SerializerStream::fopen(const char *filename, const char *mode)
{
vmStreamContext *c = new vmStreamContext;
context = c;
if(strchr(mode, 'w')) {
c->issave = true;
strncpy(c->filename, filename, 16);
c->pos = 0;
c->buffer = new char[c->size = MAX_SAVE_SIZE];
return true;
} else if(readSaveGame(c->buffer, c->size, filename)) {
if(c->size > 0 && c->buffer[0] != 'S') {
// Data does not start with "SCVM". Maybe compressed?
char *expbuf = new char[MAX_SAVE_SIZE];
unsigned long destlen = MAX_SAVE_SIZE;
if(!uncompress((Bytef*)expbuf, &destlen, (Bytef*)c->buffer, c->size)) {
delete(c->buffer);
c->buffer = expbuf;
c->size = destlen;
} else delete expbuf;
}
c->issave = false;
c->pos = 0;
return true;
} else {
delete c;
context = NULL;
return false;
}
}
void SerializerStream::fclose()
{
extern const char *gGameName;
extern Icon icon;
if(context) {
vmStreamContext *c = (vmStreamContext *)context;
if(c->issave) {
if(c->pos) {
// Try compression
char *compbuf = new char[c->pos];
unsigned long destlen = c->pos;
if(!compress((Bytef*)compbuf, &destlen, (Bytef*)c->buffer, c->pos)) {
delete c->buffer;
c->buffer = compbuf;
c->pos = destlen;
} else delete compbuf;
}
writeSaveGame(gGameName, c->buffer, c->pos,
c->filename, icon);
}
delete c->buffer;
delete c;
context = NULL;
}
}
int SerializerStream::fread(void *buf, int size, int cnt)
{
vmStreamContext *c = (vmStreamContext *)context;
if (!c || c->issave)
return -1;
int nbyt = size*cnt;
if (c->pos + nbyt > c->size) {
cnt = (c->size - c->pos)/size;
nbyt = size*cnt;
}
if (nbyt)
memcpy(buf, c->buffer + c->pos, nbyt);
c->pos += nbyt;
return cnt;
}
int SerializerStream::fwrite(void *buf, int size, int cnt)
{
vmStreamContext *c = (vmStreamContext *)context;
if (!c || !c->issave)
return -1;
int nbyt = size*cnt;
if (c->pos + nbyt > c->size) {
cnt = (c->size - c->pos)/size;
nbyt = size*cnt;
}
if (nbyt)
memcpy(c->buffer + c->pos, buf, nbyt);
c->pos += nbyt;
return cnt;
}