diff options
Diffstat (limited to 'backends/dc/vmsave.cpp')
-rw-r--r-- | backends/dc/vmsave.cpp | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/backends/dc/vmsave.cpp b/backends/dc/vmsave.cpp new file mode 100644 index 0000000000..34bf2e40fa --- /dev/null +++ b/backends/dc/vmsave.cpp @@ -0,0 +1,266 @@ +/* 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 "stdafx.h" +#include "scumm.h" +#include "mididrv.h" +#include "gameDetector.h" +#include "dc.h" +#include "icon.h" +#include "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(GameDetector *d, 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); + char *game_name = d->getGameName(); + strncpy(header.longdesc, game_name, 32); + free(game_name); + 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(GameDetector *d, const char *data, int size, + const char *filename, class Icon &icon) +{ + vmsaveResult r, res = VMSAVE_NOVM; + + if(lastvm >= 0 && + (res = trySave(d, data, size, filename, icon, lastvm)) == VMSAVE_OK) + return res; + + for(int i=0; i<24; i++) + if((r = trySave(d, 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 GameDetector detector; + 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(&detector, 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; +} + |