From 83da387eef75aa1140c81bd9e3e002ae3ea83864 Mon Sep 17 00:00:00 2001 From: Marcus Comstedt Date: Tue, 17 Dec 2002 01:15:13 +0000 Subject: New savefile backend system (bye bye NONSTANDARD_SAVE...) svn-id: r6007 --- backends/dc/Makefile | 2 +- backends/dc/dc.h | 3 + backends/dc/vmsave.cpp | 179 ++++++++++++++++++++++++++++++++----------------- backends/gp32/gp32.cpp | 41 ++++++++--- backends/gp32/gp32.h | 4 ++ common/savefile.h | 90 +++++++++++++++++++++++++ common/scummsys.h | 1 - common/system.h | 7 ++ scumm/dialogs.cpp | 10 ++- scumm/saveload.cpp | 52 ++++++++------ scumm/saveload.h | 30 +-------- scumm/scumm.h | 21 +++++- 12 files changed, 311 insertions(+), 129 deletions(-) create mode 100644 common/savefile.h diff --git a/backends/dc/Makefile b/backends/dc/Makefile index 9a8595a95e..79688a729d 100644 --- a/backends/dc/Makefile +++ b/backends/dc/Makefile @@ -6,7 +6,7 @@ VPATH = ../.. CXX = sh-elf-g++ -ml -m4-single-only CXXFLAGS= -O1 -Wno-multichar -DEFINES = -D__DC__ -DNONSTANDARD_PORT -DNONSTANDARD_SAVE +DEFINES = -D__DC__ -DNONSTANDARD_PORT LDFLAGS := -Wl,-Ttext,0x8c010000 -nostartfiles ronin/crt0.o INCLUDES:= -I./ -I../.. -I../../common CPPFLAGS= $(DEFINES) $(INCLUDES) diff --git a/backends/dc/dc.h b/backends/dc/dc.h index cf65f90567..686c590b6b 100644 --- a/backends/dc/dc.h +++ b/backends/dc/dc.h @@ -84,6 +84,9 @@ class OSystem_Dreamcast : public OSystem { virtual void unlock_mutex(void *mutex); virtual void delete_mutex(void *mutex); + // Savefile handling + virtual SaveFileManager *get_savefile_manager(); + static OSystem *create(); diff --git a/backends/dc/vmsave.cpp b/backends/dc/vmsave.cpp index 2bfd2278dd..c8d6d43add 100644 --- a/backends/dc/vmsave.cpp +++ b/backends/dc/vmsave.cpp @@ -155,6 +155,33 @@ static bool tryLoad(char *&buffer, int &size, const char *filename, int vm) return false; } +static void tryList(const char *prefix, bool *marks, int num, int vm) +{ + struct vmsinfo info; + struct superblock super; + struct dir_iterator iter; + struct dir_entry de; + int pl = strlen(prefix); + + if(!vmsfs_check_unit(vm, 0, &info)) + return; + if(!vmsfs_get_superblock(&info, &super)) + return; + vmsfs_open_dir(&super, &iter); + while(vmsfs_next_dir_entry(&iter, &de)) + if(de.entry[0]) { + char buf[16], *endp = NULL; + strncpy(buf, (char *)de.entry+4, 12); + buf[12] = 0; + int l = strlen(buf); + long i = 42; + if(l > pl && !strncmp(buf, prefix, pl) && + (i = strtol(buf+pl, &endp, 10))>=0 && iissave = 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') { +public: + VMSave(const char *_filename, bool _saveOrLoad) + : issave(_saveOrLoad), pos(0), buffer(NULL) + { + strncpy(filename, _filename, 16); + if(issave) + buffer = new char[size = MAX_SAVE_SIZE]; + } + + ~VMSave(); + + virtual int fread(void *buf, int size, int cnt); + virtual int fwrite(void *buf, int size, int cnt); + + bool readSaveGame() + { return ::readSaveGame(buffer, size, filename); } + + void tryUncompress() + { + if(size > 0 && 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; + if(!uncompress((Bytef*)expbuf, &destlen, (Bytef*)buffer, size)) { + delete(buffer); + buffer = expbuf; + size = destlen; } else delete expbuf; } - c->issave = false; - c->pos = 0; - return true; + } +}; + +class VMSaveManager : public SaveFileManager { + virtual SaveFile *open_savefile(const char *filename, bool saveOrLoad); + virtual void list_savefiles(const char *prefix, bool *marks, int num); +}; + +SaveFile *VMSaveManager::open_savefile(const char *filename, + bool saveOrLoad) +{ + VMSave *s = new VMSave(filename, saveOrLoad); + if(saveOrLoad) + return s; + else if(s->readSaveGame()) { + s->tryUncompress(); + return s; } else { - delete c; - context = NULL; - return false; + delete s; + return NULL; } } -void SerializerStream::fclose() +VMSave::~VMSave() { 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; - } - displaySaveResult(writeSaveGame(gGameName, c->buffer, - c->pos, c->filename, icon)); + if(issave) { + if(pos) { + // Try compression + char *compbuf = new char[pos]; + unsigned long destlen = pos; + if(!compress((Bytef*)compbuf, &destlen, (Bytef*)buffer, pos)) { + delete buffer; + buffer = compbuf; + pos = destlen; + } else delete compbuf; } - delete c->buffer; - delete c; - context = NULL; + displaySaveResult(writeSaveGame(gGameName, buffer, + pos, filename, icon)); } + delete buffer; } -int SerializerStream::fread(void *buf, int size, int cnt) +int VMSave::fread(void *buf, int sz, int cnt) { - vmStreamContext *c = (vmStreamContext *)context; - - if (!c || c->issave) + if (issave) return -1; - int nbyt = size*cnt; - if (c->pos + nbyt > c->size) { - cnt = (c->size - c->pos)/size; - nbyt = size*cnt; + int nbyt = sz*cnt; + if (pos + nbyt > size) { + cnt = (size - pos)/sz; + nbyt = sz*cnt; } if (nbyt) - memcpy(buf, c->buffer + c->pos, nbyt); - c->pos += nbyt; + memcpy(buf, buffer + pos, nbyt); + pos += nbyt; return cnt; } -int SerializerStream::fwrite(void *buf, int size, int cnt) +int VMSave::fwrite(void *buf, int sz, int cnt) { - vmStreamContext *c = (vmStreamContext *)context; - - if (!c || !c->issave) + if (!issave) return -1; - int nbyt = size*cnt; - if (c->pos + nbyt > c->size) { - cnt = (c->size - c->pos)/size; - nbyt = size*cnt; + int nbyt = sz*cnt; + if (pos + nbyt > size) { + cnt = (size - pos)/sz; + nbyt = sz*cnt; } if (nbyt) - memcpy(c->buffer + c->pos, buf, nbyt); - c->pos += nbyt; + memcpy(buffer + pos, buf, nbyt); + pos += nbyt; return cnt; } + +void VMSaveManager::list_savefiles(const char *prefix, + bool *marks, int num) +{ + memset(marks, false, num*sizeof(bool)); + + for(int i=0; i<24; i++) + tryList(prefix, marks, num, i); +} + +SaveFileManager *OSystem_Dreamcast::get_savefile_manager() +{ + return new VMSaveManager(); +} diff --git a/backends/gp32/gp32.cpp b/backends/gp32/gp32.cpp index 773b4e95ec..19a1aaec57 100644 --- a/backends/gp32/gp32.cpp +++ b/backends/gp32/gp32.cpp @@ -1221,26 +1221,47 @@ extern "C" int write(int fd, void *p, size_t n); int write(int fd, void *p, size_t n) { return 0; } //ph0x hack! // fixme - unnecessary? -int SerializerStream::fwrite(void *buf, int size, int cnt) { +class GP32SaveFile : public SaveFile { +private: + FILE *fh; +public: + GP32SaveFile(FILE *f) : fh(f) { } + + ~GP32SaveFile(); + + int fread(void *buf, int size, int cnt); + int fwrite(void *buf, int size, int cnt); +} + +class GP32SaveFileManager : public SaveFileManager { + SaveFile *open_savefile(const char *filename, bool saveOrLoad); +} + +int GP32SaveFile::fwrite(void *buf, int size, int cnt) { // implement me - return ::fwrite(buf, size, cnt, (FILE*)context); + return ::fwrite(buf, size, cnt, fh); } -bool SerializerStream::fopen(const char *filename, const char *mode) { +SaveFile GP32SaveFileManager::open_savefile(const char *filename, + bool saveOrLoad) { // implement me - (FILE*)context = ::fopen(filename, mode); - //if (tolower(mode[0])=='w') error("Autosaving.."); - return context != NULL; + FILE *fh = ::fopen(filename, (saveOrLoad? "wb":"rb")); + //if (saveOrLoad) error("Autosaving.."); + return fh? new GP32SaveFile(fh) : NULL; } -void SerializerStream::fclose() { +void GP32SaveFile::~GP32SaveFile() { // implement me - ::fclose((FILE*)context); + ::fclose(fh); } -int SerializerStream::fread(void *buf, int size, int cnt) { +int GP32SaveFile::fread(void *buf, int size, int cnt) { // implement me - return ::fread(buf, size, cnt, (FILE*)context); + return ::fread(buf, size, cnt, fh); + +} +SaveFileManager *OSystem_GP32::get_savefile_manager() { + return new GP32SaveFileManager(); } // Converts 8bit rgb values to a GP32 palette value diff --git a/backends/gp32/gp32.h b/backends/gp32/gp32.h index 7546a25b7b..f56de538f7 100644 --- a/backends/gp32/gp32.h +++ b/backends/gp32/gp32.h @@ -115,6 +115,10 @@ public: void grab_overlay(int16 *buf, int pitch); void copy_rect_overlay(const int16 *buf, int pitch, int x, int y, int w, int h); + // Savefiles + SaveFileManager *get_savefile_manager(); + + static OSystem *create(int gfx_mode, bool full_screen); private: typedef void ScalerProc(uint8 *srcPtr, uint32 srcPitch, uint8 *deltaPtr, diff --git a/common/savefile.h b/common/savefile.h new file mode 100644 index 0000000000..952b07e44f --- /dev/null +++ b/common/savefile.h @@ -0,0 +1,90 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001/2002 The ScummVM project + * + * 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$ + * + */ + +#ifndef COMMON_SAVEFILE_H +#define COMMON_SAVEFILE_H + +#include + +class SaveFile { +public: + virtual ~SaveFile() {} + virtual int fread(void *buf, int size, int cnt) = 0; + virtual int fwrite(void *buf, int size, int cnt) = 0; +#ifdef _WIN32_WCE + //Should go away. See scumm/saveload.cpp and scumm/imuse.cpp + virtual int fseek(long offs, int whence) = 0; + virtual int feof() = 0; +#endif +}; + +class StdioSaveFile : public SaveFile { +private: + FILE *fh; +public: + StdioSaveFile(const char *filename, const char *mode) + { fh = ::fopen(filename, mode); } + ~StdioSaveFile() + { if(fh) ::fclose(fh); } + + + bool is_open() { return fh != NULL; } + + + int fread(void *buf, int size, int cnt) + { return ::fread(buf, size, cnt, fh); } + int fwrite(void *buf, int size, int cnt) + { return ::fwrite(buf, size, cnt, fh); } +#ifdef _WIN32_WCE + int fseek(long offs, int whence) + { return ::fseek(fh, offs, whence); } + int feof() + { return ::feof(fh); } +#endif +}; + +class SaveFileManager { + +public: + virtual ~SaveFileManager() {} + + virtual SaveFile *open_savefile(const char *filename, + bool saveOrLoad) + { + StdioSaveFile *sf = new StdioSaveFile(filename, + (saveOrLoad? "wb":"rb")); + if(!sf->is_open()) { + delete sf; + sf = NULL; + } + return sf; + } + + virtual void list_savefiles(const char *prefix, + bool *marks, int num) + { + memset(marks, true, num*sizeof(bool)); + } + +}; + +#endif diff --git a/common/scummsys.h b/common/scummsys.h index 8b0e7fea29..1c63b4f838 100644 --- a/common/scummsys.h +++ b/common/scummsys.h @@ -240,7 +240,6 @@ #define CDECL #define SCUMM_NEED_ALIGNMENT #define SCUMM_LITTLE_ENDIAN - #define NONSTANDARD_SAVE #define scumm_stricmp stricmp #define CHECK_HEAP diff --git a/common/system.h b/common/system.h index 13a1fab3fd..296fb072c8 100644 --- a/common/system.h +++ b/common/system.h @@ -24,6 +24,7 @@ #define COMMON_SYSTEM_H #include "scummsys.h" +#include "savefile.h" class Timer; @@ -180,6 +181,12 @@ public: g = (((color>>5)&0x3F) << 2); b = ((color&0x1F) << 3); } + + // Savefile management + virtual SaveFileManager *get_savefile_manager() + { + return new SaveFileManager(); + } }; diff --git a/scumm/dialogs.cpp b/scumm/dialogs.cpp index c115295ca1..e676c48775 100644 --- a/scumm/dialogs.cpp +++ b/scumm/dialogs.cpp @@ -406,12 +406,20 @@ void SaveLoadDialog::fillList() ScummVM::StringList l; char name[32]; int i = _saveMode ? 1 : 0; + bool avail_saves[81]; + SaveFileManager *mgr = _scumm->_system->get_savefile_manager(); + _scumm->listSavegames(avail_saves, 81, mgr); for (; i <= 80; i++) { // 80 - got this value from the old GUI - _scumm->getSavegameName(i, name); + if(avail_saves[i]) + _scumm->getSavegameName(i, name, mgr); + else + name[0] = 0; l.push_back(name); } + delete mgr; + _savegameList->setList(l); _savegameList->setNumberingMode(_saveMode ? kListNumberingOne : kListNumberingZero); } diff --git a/scumm/saveload.cpp b/scumm/saveload.cpp index eee440a11e..78be8b140b 100644 --- a/scumm/saveload.cpp +++ b/scumm/saveload.cpp @@ -39,15 +39,15 @@ struct SaveGameHeader { }; -bool Scumm::saveState(int slot, bool compat) +bool Scumm::saveState(int slot, bool compat, SaveFileManager *mgr) { char filename[256]; - SerializerStream out; + SaveFile *out; SaveGameHeader hdr; makeSavegameName(filename, slot, compat); - if (!out.fopen(filename, "wb")) + if (!(out = mgr->open_savefile(filename, true))) return false; memcpy(hdr.name, _saveLoadName, sizeof(hdr.name)); @@ -56,32 +56,32 @@ bool Scumm::saveState(int slot, bool compat) hdr.size = 0; hdr.ver = TO_LE_32(CURRENT_VER); - out.fwrite(&hdr, sizeof(hdr), 1); + out->fwrite(&hdr, sizeof(hdr), 1); Serializer ser(out, true, CURRENT_VER); saveOrLoad(&ser, CURRENT_VER); - out.fclose(); + delete out; debug(1, "State saved as '%s'", filename); return true; } -bool Scumm::loadState(int slot, bool compat) +bool Scumm::loadState(int slot, bool compat, SaveFileManager *mgr) { char filename[256]; - SerializerStream out; + SaveFile *out; int i, j; SaveGameHeader hdr; int sb, sh; makeSavegameName(filename, slot, compat); - if (!out.fopen(filename, "rb")) + if (!(out = mgr->open_savefile(filename, false))) return false; - out.fread(&hdr, sizeof(hdr), 1); + out->fread(&hdr, sizeof(hdr), 1); if (hdr.type != MKID('SCVM')) { warning("Invalid savegame '%s'", filename); - out.fclose(); + delete out; return false; } @@ -92,7 +92,7 @@ bool Scumm::loadState(int slot, bool compat) if (hdr.ver < VER_V7 || hdr.ver > CURRENT_VER) { warning("Invalid version of '%s'", filename); - out.fclose(); + delete out; return false; } @@ -126,7 +126,7 @@ bool Scumm::loadState(int slot, bool compat) Serializer ser(out, false, hdr.ver); saveOrLoad(&ser, hdr.ver); - out.fclose(); + delete out; sb = _screenB; sh = _screenH; @@ -174,20 +174,28 @@ void Scumm::makeSavegameName(char *out, int slot, bool compatible) sprintf(out, "%s%s.%c%.2d", dir, _game_name, compatible ? 'c' : 's', slot); } -bool Scumm::getSavegameName(int slot, char *desc) +void Scumm::listSavegames(bool *marks, int num, SaveFileManager *mgr) +{ + char prefix[256]; + makeSavegameName(prefix, 99, false); + prefix[strlen(prefix)-2] = 0; + mgr->list_savefiles(prefix, marks, num); +} + +bool Scumm::getSavegameName(int slot, char *desc, SaveFileManager *mgr) { char filename[256]; - SerializerStream out; + SaveFile *out; SaveGameHeader hdr; int len; makeSavegameName(filename, slot, false); - if (!out.fopen(filename, "rb")) { + if (!(out = mgr->open_savefile(filename, false))) { strcpy(desc, ""); return false; } - len = out.fread(&hdr, sizeof(hdr), 1); - out.fclose(); + len = out->fread(&hdr, sizeof(hdr), 1); + delete out; if (len != 1 || hdr.type != MKID('SCVM')) { strcpy(desc, "Invalid savegame"); @@ -652,12 +660,12 @@ void Scumm::saveLoadResource(Serializer *ser, int type, int idx) void Serializer::saveBytes(void *b, int len) { - _saveLoadStream.fwrite(b, 1, len); + _saveLoadStream->fwrite(b, 1, len); } void Serializer::loadBytes(void *b, int len) { - _saveLoadStream.fread(b, 1, len); + _saveLoadStream->fread(b, 1, len); } #ifdef _WIN32_WCE @@ -666,11 +674,11 @@ void Serializer::loadBytes(void *b, int len) bool Serializer::checkEOFLoadStream() { - if (!fseek(_saveLoadStream.out, 1, SEEK_CUR)) + if (!_saveLoadStream->fseek(1, SEEK_CUR)) return true; - if (feof(_saveLoadStream.out)) + if (_saveLoadStream->feof()) return true; - fseek(_saveLoadStream.out, -1, SEEK_CUR); + _saveLoadStream->fseek(-1, SEEK_CUR); return false; } diff --git a/scumm/saveload.h b/scumm/saveload.h index 1667aeb045..7be5d061a1 100644 --- a/scumm/saveload.h +++ b/scumm/saveload.h @@ -85,38 +85,12 @@ struct SaveLoadEntry { uint8 maxVersion; }; -struct SerializerStream { -#ifdef NONSTANDARD_SAVE - void *context; - - bool fopen(const char *filename, const char *mode); - void fclose(); - int fread(void *buf, int size, int cnt); - int fwrite(void *buf, int size, int cnt); -#else - FILE *out; - - FILE *fopen(const char *filename, const char *mode) { - return out = ::fopen(filename, mode); - } - void fclose() { - ::fclose(out); - } - int fread(void *buf, int size, int cnt) { - return ::fread(buf, size, cnt, out); - } - int fwrite(void *buf, int size, int cnt) { - return ::fwrite(buf, size, cnt, out); - } -#endif -}; - typedef int SerializerSaveReference(void *me, byte type, void *ref); typedef void *SerializerLoadReference(void *me, byte type, int ref); class Serializer { public: - Serializer(SerializerStream stream, bool saveOrLoad, uint32 savegameVersion) + Serializer(SaveFile *stream, bool saveOrLoad, uint32 savegameVersion) : _save_ref(0), _load_ref(0), _ref_me(0), _saveLoadStream(stream), _saveOrLoad(saveOrLoad), _savegameVersion(savegameVersion) @@ -146,7 +120,7 @@ public: void loadBytes(void *b, int len); protected: - SerializerStream _saveLoadStream; + SaveFile *_saveLoadStream; bool _saveOrLoad; uint32 _savegameVersion; diff --git a/scumm/scumm.h b/scumm/scumm.h index 5e0c54a005..ead8ef4c36 100644 --- a/scumm/scumm.h +++ b/scumm/scumm.h @@ -439,13 +439,28 @@ public: bool _saveLoadCompatible; char _saveLoadName[32]; - bool saveState(int slot, bool compat); - bool loadState(int slot, bool compat); + bool saveState(int slot, bool compat, SaveFileManager *mgr); + bool loadState(int slot, bool compat, SaveFileManager *mgr); + bool saveState(int slot, bool compat) + { + SaveFileManager *mgr = _system->get_savefile_manager(); + bool result = saveState(slot, compat, mgr); + delete mgr; + return result; + } + bool loadState(int slot, bool compat) + { + SaveFileManager *mgr = _system->get_savefile_manager(); + bool result = loadState(slot, compat, mgr); + delete mgr; + return result; + } void saveOrLoad(Serializer *s, uint32 savegameVersion); - bool getSavegameName(int slot, char *desc); + bool getSavegameName(int slot, char *desc, SaveFileManager *mgr); void makeSavegameName(char *out, int slot, bool compatible); void saveLoadResource(Serializer *ser, int type, int index); + void listSavegames(bool *marks, int num, SaveFileManager *mgr); /* Heap and memory management */ uint32 _maxHeapThreshold, _minHeapThreshold; -- cgit v1.2.3