diff options
Diffstat (limited to 'backends/ps2/savefile.cpp')
-rw-r--r-- | backends/ps2/savefile.cpp | 375 |
1 files changed, 375 insertions, 0 deletions
diff --git a/backends/ps2/savefile.cpp b/backends/ps2/savefile.cpp new file mode 100644 index 0000000000..74a8bca036 --- /dev/null +++ b/backends/ps2/savefile.cpp @@ -0,0 +1,375 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002-2005 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$ + * + */ + +#include "backends/ps2/savefile.h" +#include "backends/ps2/Gs2dScreen.h" + +#include <tamtypes.h> +#include <kernel.h> +#include <sifrpc.h> +#include <loadfile.h> +#include <fileio.h> +#include <malloc.h> +#include <ucl/ucl.h> +#include "scummsys.h" + +class StdioSaveFile : public SaveFile { +public: + StdioSaveFile(const char *filename, bool saveOrLoad); + virtual ~StdioSaveFile(); + virtual bool isOpen() const; + virtual uint32 read(void *buf, uint32 cnt); + virtual uint32 write(const void *buf, uint32 cnt); +private: + FILE *_fh; + bool _saving; +}; + +class UclSaveFile : public SaveFile { +public: + UclSaveFile(const char *filename, bool saveOrLoad, Gs2dScreen *screen); + virtual ~UclSaveFile(); + virtual bool isOpen() const; + virtual uint32 read(void *buf, uint32 cnt); + virtual uint32 write(const void *buf, uint32 cnt); +private: + Gs2dScreen *_screen; + FILE *_fh; + bool _saving; + uint8 *_buf; + uint32 _bufSize, _bufPos; +}; + +#define ARRAY_ENTRIES 16 +static mcTable mcDir[ARRAY_ENTRIES] __attribute__((aligned(64))); +static int mcEntries; +static bool mcNeedUpdate = true; + +Ps2SaveFileManager::Ps2SaveFileManager(const char *path, SaveMode mode, Gs2dScreen *screen) { + _screen = screen; + if (mcInit(MC_TYPE_MC) < 0) { + printf("Can't init libmc!\n"); + SleepThread(); + } + + if (path) + strcpy(_savePath, path); + else + _savePath[0] = '\0'; + + _mode = mode; + if (mode == TO_HOST) { + printf("saving to host:/\n"); + } else if (mode == TO_MC) { + int mcType, mcFree, mcFormat, res; + mcGetInfo(0, 0, &mcType, &mcFree, &mcFormat); + mcSync(0, NULL, &res); + if ((res == 0) || (res == -1)) // mc okay + printf("MC okay, result = %d. Type %d, Free %d, Format %d\n", res, mcType, mcFree, mcFormat); + else + printf("MC failed, not present or not formatted, code %d\n", res); + } else { + printf("HDD not implemented yet\n"); + SleepThread(); + } + + checkMainDirectory(); +} + +Ps2SaveFileManager::~Ps2SaveFileManager(void) { +} + +void Ps2SaveFileManager::checkMainDirectory(void) { + // verify that the main directory (scummvm config + icon) exists + int ret; + mcGetDir(0, 0, "/ScummVM/*", 0, ARRAY_ENTRIES, mcDir); + mcSync(0, NULL, &ret); + printf("/ScummVM/* res = %d\n", ret); + if (ret <= 0) { // assume directory doesn't exist + printf("Dir doesn't exist\n"); + fioMkdir("mc0:ScummVM"); + FILE *outf = fopen("mc0:ScummVM/scummvm.icn", "wb"); + if (outf) { + uint16 icoSize; + uint16 *icoBuf = decompressIconData(&icoSize); + fwrite(icoBuf, 2, icoSize, outf); + fclose(outf); + printf(".icn written\n"); + free(icoBuf); + + setupIcon("mc0:ScummVM/icon.sys", "scummvm.icn", "ScummVM", "Configuration"); + } else + printf("unable to write icon data\n"); + } +} + +SaveFile *Ps2SaveFileManager::openSavefile(const char *filename, bool saveOrLoad) { + char *defaultExt = "SAVE"; + char nameBase[256]; + strcpy(nameBase, filename); + char *ext = strchr(nameBase, '.'); + if (ext) { + *ext = '\0'; + ext++; + if (!*ext) + ext = defaultExt; + } else + ext = defaultExt; + + if (_mode == TO_HOST) { + char hostName[256]; + sprintf(hostName, "%s%s", _savePath, filename); + SaveFile *res = new StdioSaveFile(hostName, saveOrLoad); + if (!res->isOpen()) { + printf("unable to open savefile %s for %s\n", hostName, saveOrLoad ? "saving" : "loading"); + delete res; + return NULL; + } + printf("Savefile %s opened for %s\n", hostName, saveOrLoad ? "saving" : "loading"); + return res; + } else if (_mode == TO_MC) { + _screen->wantAnim(true); + int mcType, mcFree, mcFormat, mcResult; + mcGetInfo(0, 0, &mcType, &mcFree, &mcFormat); + mcSync(0, NULL, &mcResult); + if (mcResult == -1) // memory card was exchanged + mcNeedUpdate = true; + else if (mcResult != 0) { + printf("Memory card is not ready\n"); + return NULL; + } + + char dirStr[256]; + sprintf(dirStr, "/ScummVM-%s/*", nameBase); + if (saveOrLoad) { // saving + mcGetDir(0, 0, dirStr, 0, ARRAY_ENTRIES, mcDir); + mcSync(0, NULL, &mcEntries); + mcNeedUpdate = true; + if (mcEntries <= 0) { // directory is empty or doesn't exist. + sprintf(dirStr, "mc0:ScummVM-%s", nameBase); + printf("Creating directory %s\n", dirStr); + if (mcEntries < 0) { // directory doesn't exist + if (fioMkdir(dirStr) < 0) { + printf("unable to create directory %s\n", dirStr); + _screen->wantAnim(false); + return NULL; // unable to create directory + } + } + char icoSysDest[256], saveDesc[256]; + sprintf(icoSysDest, "%s/icon.sys", dirStr); + strcpy(saveDesc, nameBase); + if ((saveDesc[0] >= 'a') && (saveDesc[0] <= 'z')) + saveDesc[0] += 'A' - 'a'; + setupIcon(icoSysDest, "../ScummVM/scummvm.icn", saveDesc, "Savegames"); + } + } else { + // scumm engine tries to open hundreds of files to search for savegames. + if (mcNeedUpdate) { + mcGetDir(0, 0, dirStr, 0, ARRAY_ENTRIES, mcDir); + mcSync(0, NULL, &mcEntries); + mcNeedUpdate = false; + } + bool fileExists = false; + char searchName[32]; + sprintf(searchName, "%s.bin", ext); + for (int cnt = 0; (cnt < mcEntries) && !fileExists; cnt++) + if (strcmp(searchName, (char*)mcDir[cnt].name) == 0) + fileExists = true; + + if (!fileExists) { + _screen->wantAnim(false); + return NULL; + } + } + sprintf(dirStr, "mc0:ScummVM-%s/%s.bin", nameBase, ext); + SaveFile *file = new UclSaveFile(dirStr, saveOrLoad, _screen); + if (!file->isOpen()) { + printf("unable to open savefile %s for %s\n", dirStr, saveOrLoad ? "saving" : "loading"); + delete file; + _screen->wantAnim(false); + return NULL; + } + return file; + } else { + printf("HDD not implemented yet\n"); + return NULL; + } +} + +void Ps2SaveFileManager::listSavefiles(const char * /* prefix */, bool *marks, int num) { + memset(marks, true, num * sizeof(bool)); +} + +const char *Ps2SaveFileManager::getSavePath(void) const { + return _savePath; +} + +void Ps2SaveFileManager::setSavePath(const char *path) { + strcpy(_savePath, path); +} + +bool Ps2SaveFileManager::setupIcon(const char *dest, const char *ico, const char *descr1, const char *descr2) { + mcIcon icon_sys; + memset(&icon_sys, 0, sizeof(mcIcon)); + memcpy(icon_sys.head, "PS2D", 4); + char title[256]; + sprintf(title, "%s\n%s", descr1, descr2); + strcpy_sjis((short*)&(icon_sys.title), title); + icon_sys.nlOffset = strlen(descr1) + 1; + icon_sys.trans = 0x10; + memcpy(icon_sys.bgCol, _bgcolor, sizeof(_bgcolor)); + memcpy(icon_sys.lightDir, _lightdir, sizeof(_lightdir)); + memcpy(icon_sys.lightCol, _lightcol, sizeof(_lightcol)); + memcpy(icon_sys.lightAmbient, _ambient, sizeof(_ambient)); + strcpy((char*)icon_sys.view, ico); + strcpy((char*)icon_sys.copy, ico); + strcpy((char*)icon_sys.del, ico); + + FILE *outf = fopen(dest, "wb"); + if (outf) { + fwrite(&icon_sys, 1, sizeof(icon_sys), outf); + fclose(outf); + return true; + } else + return false; +} + +uint16 *Ps2SaveFileManager::decompressIconData(uint16 *size) { + uint16 inPos = 1; + uint16 *rleData = (uint16*)_rleIcoData; + uint16 resSize = rleData[0]; + uint16 *resData = (uint16*)malloc(resSize * sizeof(uint16*)); + uint16 outPos = 0; + while (outPos < resSize) { + uint16 len = rleData[inPos++]; + while (len--) + resData[outPos++] = 0x7FFF; + len = rleData[inPos++]; + while (len--) + resData[outPos++] = rleData[inPos++]; + } + *size = resSize; + assert(outPos == resSize); + return resData; +} + + +StdioSaveFile::StdioSaveFile(const char *filename, bool saveOrLoad) { + _fh = ::fopen(filename, (saveOrLoad? "wb" : "rb")); + _saving = saveOrLoad; +} + +StdioSaveFile::~StdioSaveFile(void) { + if (_fh) + ::fclose(_fh); +} + +bool StdioSaveFile::isOpen(void) const { + return _fh != NULL; +} + +uint32 StdioSaveFile::read(void *buf, uint32 cnt) { + assert(!_saving); + return ::fread(buf, 1, cnt, _fh); +} + +uint32 StdioSaveFile::write(const void *buf, uint32 cnt) { + assert(_saving); + return ::fwrite(buf, 1, cnt, _fh); +} + +UclSaveFile::UclSaveFile(const char *filename, bool saveOrLoad, Gs2dScreen *screen) { + _fh = ::fopen(filename, (saveOrLoad? "wb" : "rb")); + _saving = saveOrLoad; + _bufPos = 0; + _screen = screen; + if (_fh) { + if (_saving) { + _buf = (uint8*)malloc(65536); + _bufSize = 65536; + } else { + uint32 srcSize = ::fsize(_fh); + uint8 *srcBuf = (uint8*)malloc(srcSize); + int res = ::fread(srcBuf, 1, srcSize, _fh); + assert(res == srcSize); + + uint32 resLen = _bufSize = *(uint32*)srcBuf; + _buf = (uint8*)malloc(_bufSize + 2048); + res = ucl_nrv2e_decompress_8(srcBuf + 4, srcSize - 4, _buf, &resLen, NULL); + if ((res < 0) || (resLen != _bufSize)) { + printf("Unable to decompress file %s (%d -> %d) error code %d\n", filename, srcSize, _bufSize, res); + free(_buf); + _buf = NULL; + _bufSize = 0; + } + ::fclose(_fh); + _fh = NULL; + free(srcBuf); + } + } else { + printf("Savefile %s doesn't exist\n", filename); + _buf = NULL; + } +} + +UclSaveFile::~UclSaveFile(void) { + if (_saving) { + uint8 *compBuf = (uint8*)malloc(_bufPos * 2); + uint32 compSize = _bufPos * 2; + int res = ucl_nrv2e_99_compress(_buf, _bufPos, compBuf, &compSize, NULL, 10, NULL, NULL); + if (res >= 0) { + fwrite(&_bufPos, 1, 4, _fh); + fwrite(compBuf, 1, compSize, _fh); + } else { + printf("unable to compress %d bytes of savedata, errorcode %d\n", _bufPos, res); + } + free(compBuf); + } + if (_buf) + free(_buf); + if (_fh) + ::fclose(_fh); + _screen->wantAnim(false); +} + +bool UclSaveFile::isOpen(void) const { + return (_buf != NULL); +} + +uint32 UclSaveFile::read(void *buf, uint32 cnt) { + assert(!_saving); + uint32 numBytes = (cnt > _bufSize - _bufPos) ? (_bufSize - _bufPos) : cnt; + memcpy(buf, _buf + _bufPos, numBytes); + _bufPos += numBytes; + return numBytes; +} + +uint32 UclSaveFile::write(const void *buf, uint32 cnt) { + assert(_saving); + if (_bufSize - _bufPos < cnt) { + _bufSize += (cnt > 65536) ? cnt : 65536; + _buf = (uint8*)realloc(_buf, _bufSize); + } + memcpy(_buf + _bufPos, buf, cnt); + _bufPos += cnt; + return cnt; +} + |