diff options
Diffstat (limited to 'backends/ps2/savefile.cpp')
-rw-r--r-- | backends/ps2/savefile.cpp | 540 |
1 files changed, 320 insertions, 220 deletions
diff --git a/backends/ps2/savefile.cpp b/backends/ps2/savefile.cpp index 78def68d7b..1449c94510 100644 --- a/backends/ps2/savefile.cpp +++ b/backends/ps2/savefile.cpp @@ -19,9 +19,6 @@ * */ -#include "backends/ps2/savefile.h" -#include "backends/ps2/Gs2dScreen.h" - #include <tamtypes.h> #include <kernel.h> #include <sifrpc.h> @@ -29,69 +26,76 @@ #include <fileio.h> #include <malloc.h> #include <ucl/ucl.h> +#include "backends/ps2/savefile.h" +#include "backends/ps2/Gs2dScreen.h" +#include "backends/ps2/asyncfio.h" +#include "backends/ps2/systemps2.h" #include "scummsys.h" -class StdioSaveFile : public SaveFile { +extern AsyncFio fio; + +class UclOutSaveFile : public Common::WriteStream { 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); + UclOutSaveFile(const char *filename, Gs2dScreen *screen); + virtual ~UclOutSaveFile(void); + virtual uint32 write(const void *ptr, uint32 size); + virtual int flush(void); + virtual bool ioFailed(void); + virtual void clearIOFailed(void); private: - FILE *_fh; - bool _saving; + Gs2dScreen *_screen; + int _fd; + uint8 *_buf; + uint32 _bufSize, _bufPos; + bool _ioFailed; }; -class UclSaveFile : public SaveFile { +class UclInSaveFile : public Common::ReadStream { 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); + UclInSaveFile(const char *filename, Gs2dScreen *screen); + virtual ~UclInSaveFile(void); + virtual bool eos(void) const; + virtual uint32 read(void *ptr, uint32 size); + virtual bool ioFailed(void); + virtual void clearIOFailed(void); private: Gs2dScreen *_screen; - FILE *_fh; - bool _saving; uint8 *_buf; uint32 _bufSize, _bufPos; + bool _ioFailed; }; -#define ARRAY_ENTRIES 16 -static mcTable mcDir[ARRAY_ENTRIES] __attribute__((aligned(64))); -static int mcEntries; -static bool mcNeedUpdate = true; +#define MAX_MC_ENTRIES 16 -Ps2SaveFileManager::Ps2SaveFileManager(const char *path, SaveMode mode, Gs2dScreen *screen) { +Ps2SaveFileManager::Ps2SaveFileManager(OSystem_PS2 *system, Gs2dScreen *screen) { + _system = system; _screen = screen; - if (mcInit(MC_TYPE_MC) < 0) { - printf("Can't init libmc!\n"); - SleepThread(); - } - - if (path) - strcpy(_savePath, path); - else - _savePath[0] = '\0'; + assert(mcInit(MC_TYPE_MC) >= 0); + + _mcDirList = (mcTable*)memalign(64, MAX_MC_ENTRIES * sizeof(mcTable)); + _mcDirName[0] = '\0'; + _mcCheckTime = 0; + _mcNeedsUpdate = true; + + int mcCheckCount; + int res = -10; + for (int mcCheckCount = 0; mcCheckCount < 3; mcCheckCount++) { + /* retry mcGetInfo 3 times. It slows down startup without mc considerably, + but cheap 3rd party memory cards apparently fail to get detected once in a while */ - _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 + if ((res == 0) || (res == -1)) { // mc okay + _mcPresent = true; printf("MC okay, result = %d. Type %d, Free %d, Format %d\n", res, mcType, mcFree, mcFormat); - else + checkMainDirectory(); + break; + } else { + _mcPresent = false; printf("MC failed, not present or not formatted, code %d\n", res); - } else { - printf("HDD not implemented yet\n"); - SleepThread(); + } } - - checkMainDirectory(); } Ps2SaveFileManager::~Ps2SaveFileManager(void) { @@ -100,130 +104,177 @@ 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); + mcGetDir(0, 0, "/ScummVM/*", 0, MAX_MC_ENTRIES, _mcDirList); 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) { + fio.mkdir("mc0:ScummVM"); + int fd = fio.open("mc0:ScummVM/scummvm.icn", O_WRONLY | O_CREAT | O_TRUNC); + if (fd >= 0) { uint16 icoSize; uint16 *icoBuf = decompressIconData(&icoSize); - fwrite(icoBuf, 2, icoSize, outf); - fclose(outf); - printf(".icn written\n"); + fio.write(fd, icoBuf, icoSize * 2); + fio.sync(fd); free(icoBuf); - + fio.close(fd); + printf(".icn written\n"); 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) { +void Ps2SaveFileManager::splitPath(const char *fileName, char *dir, char *name) { + strcpy(dir, fileName); + char *ext = strchr(dir, '.'); + 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); + } + if (ext && *ext) + sprintf(name, "%s.ucl", ext); + else + strcpy(name, "save.ucl"); +} + +bool Ps2SaveFileManager::mcReadyForDir(const char *dir) { + if (_mcNeedsUpdate || ((_system->getMillis() - _mcCheckTime) > 1000) || !_mcPresent) { + // check if memory card was exchanged/removed in the meantime 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; + if (mcResult != 0) { // memory card was exchanged + _mcNeedsUpdate = true; + if (mcResult != -1) { + _mcPresent = false; + printf("MC not found, error code %d\n", mcResult); + return false; + } } - + _mcPresent = true; + } + if (_mcNeedsUpdate || strcmp(_mcDirName, dir)) { + strcpy(_mcDirName, dir); 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, "/ScummVM-%s/*", dir); + mcGetDir(0, 0, dirStr, 0, MAX_MC_ENTRIES, _mcDirList); + mcSync(0, NULL, &_mcEntries); + return (_mcEntries >= 0); + } else + return true; +} + +InSaveFile *Ps2SaveFileManager::openForLoading(const char *filename) { + _screen->wantAnim(true); + + char dir[256], name[256]; + splitPath(filename, dir, name); + if (mcReadyForDir(dir)) { + bool fileExists = false; + for (int i = 0; i < _mcEntries; i++) + if (strcmp(name, (char*)_mcDirList[i].name) == 0) + fileExists = true; + if (fileExists) { + char fullName[256]; + sprintf(fullName, "mc0:ScummVM-%s/%s", dir, name); + UclInSaveFile *file = new UclInSaveFile(fullName, _screen); + if (file) { + if (!file->ioFailed()) { + return (InSaveFile*)file; + } else + delete file; } - } - 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; + } else + printf("file %s (%s) doesn't exist\n", filename, name); } + _screen->wantAnim(false); + return NULL; } -void Ps2SaveFileManager::listSavefiles(const char * /* prefix */, bool *marks, int num) { - memset(marks, true, num * sizeof(bool)); +OutSaveFile *Ps2SaveFileManager::openForSaving(const char *filename) { + _screen->wantAnim(true); + char dir[256], name[256]; + splitPath(filename, dir, name); + + if (!mcReadyForDir(dir)) { + if (_mcPresent) { // directory doesn't seem to exist yet + char fullPath[256]; + sprintf(fullPath, "mc0:ScummVM-%s", dir); + fio.mkdir(fullPath); + + char icoSysDest[256], saveDesc[256]; + sprintf(icoSysDest, "%s/icon.sys", fullPath); + strcpy(saveDesc, dir); + if ((saveDesc[0] >= 'a') && (saveDesc[0] <= 'z')) + saveDesc[0] += 'A' - 'a'; + setupIcon(icoSysDest, "../ScummVM/scummvm.icn", saveDesc, "Savegames"); + } + } + + if (_mcPresent) { + char fullPath[256]; + sprintf(fullPath, "mc0:ScummVM-%s/%s", dir, name); + UclOutSaveFile *file = new UclOutSaveFile(fullPath, _screen); + if (!file->ioFailed()) { + // we're creating a file, mc will have to be updated next time + _mcNeedsUpdate = true; + return (OutSaveFile*)file; + } else + delete file; + } + + _screen->wantAnim(false); + return NULL; } -const char *Ps2SaveFileManager::getSavePath(void) const { - return _savePath; +void Ps2SaveFileManager::listSavefiles(const char *prefix, bool *marks, int num) { + _screen->wantAnim(true); + + int mcType, mcFree, mcFormat, mcResult; + mcGetInfo(0, 0, &mcType, &mcFree, &mcFormat); + mcSync(0, NULL, &mcResult); + + memset(marks, false, num * sizeof(bool)); + + if ((mcResult == 0) || (mcResult == -1)) { + // there's a memory card in the slot. + if (mcResult == -1) + _mcNeedsUpdate = true; + + mcTable *mcEntries = (mcTable*)memalign(64, sizeof(mcTable) * MAX_MC_ENTRIES); + + char dirStr[256], ext[256], mcSearchStr[256]; + strcpy(dirStr, prefix); + char *pos = strchr(dirStr, '.'); + if (pos) { + strcpy(ext, pos + 1); + *pos = '\0'; + } else + ext[0] = '\0'; + sprintf(mcSearchStr, "/ScummVM-%s/%s*", dirStr, ext); + + int numEntries; + mcGetDir(0, 0, mcSearchStr, 0, MAX_MC_ENTRIES, mcEntries); + mcSync(0, NULL, &numEntries); + + int searchLen = strlen(ext); + for (int i = 0; i < numEntries; i++) + if ((((char*)mcEntries[i].name)[0] != '.') && stricmp((char*)mcEntries[i].name, "icon.sys")) { + char *stopCh; + int destNum = (int)strtoul((char*)mcEntries[i].name + searchLen, &stopCh, 10); + if ((!stopCh) || strcmp(stopCh, ".ucl")) + printf("unexpected end %s in name %s, search %s\n", stopCh, (char*)mcEntries[i].name, prefix); + if (destNum < num) + marks[destNum] = true; + } + free(mcEntries); + } + _screen->wantAnim(false); } -void Ps2SaveFileManager::setSavePath(const char *path) { - strcpy(_savePath, path); +const char *Ps2SaveFileManager::getSavePath(void) const { + return "mc0:"; } bool Ps2SaveFileManager::setupIcon(const char *dest, const char *ico, const char *descr1, const char *descr2) { @@ -231,9 +282,14 @@ bool Ps2SaveFileManager::setupIcon(const char *dest, const char *ico, const char memset(&icon_sys, 0, sizeof(mcIcon)); memcpy(icon_sys.head, "PS2D", 4); char title[256]; - sprintf(title, "%s\n%s", descr1, descr2); + if (!stricmp("SAVEGAME", descr1)) { // these are broken sword 1 savegames + sprintf(title, "BSword1\n%s", descr2); + icon_sys.nlOffset = 8; + } else { + sprintf(title, "%s\n%s", descr1, descr2); + icon_sys.nlOffset = strlen(descr1) + 1; + } 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)); @@ -243,11 +299,12 @@ bool Ps2SaveFileManager::setupIcon(const char *dest, const char *ico, const char 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; + int fd = fio.open(dest, O_WRONLY | O_CREAT | O_TRUNC); + if (fd >= 0) { + fio.write(fd, &icon_sys, sizeof(icon_sys)); + int res = fio.sync(fd); + fio.close(fd); + return (res == sizeof(icon_sys)); } else return false; } @@ -256,7 +313,7 @@ uint16 *Ps2SaveFileManager::decompressIconData(uint16 *size) { uint16 inPos = 1; uint16 *rleData = (uint16*)_rleIcoData; uint16 resSize = rleData[0]; - uint16 *resData = (uint16*)malloc(resSize * sizeof(uint16*)); + uint16 *resData = (uint16*)malloc(resSize * sizeof(uint16)); uint16 outPos = 0; while (outPos < resSize) { uint16 len = rleData[inPos++]; @@ -271,105 +328,148 @@ uint16 *Ps2SaveFileManager::decompressIconData(uint16 *size) { return resData; } +UclInSaveFile::UclInSaveFile(const char *filename, Gs2dScreen *screen) { + _screen = screen; + int fd = fio.open(filename, O_RDONLY); + _buf = NULL; + _bufSize = _bufPos = 0; + _ioFailed = false; + + if (fd >= 0) { + int srcSize = fio.seek(fd, 0, SEEK_END); + fio.seek(fd, 0, SEEK_SET); + if (srcSize > 4) { + int res; + uint8 *tmpBuf = (uint8*)malloc(srcSize); + fio.read(fd, tmpBuf, srcSize); + res = fio.sync(fd); + if (res == srcSize) { + uint32 resLen = _bufSize = *(uint32*)tmpBuf; + _buf = (uint8*)malloc(_bufSize + 2048); + res = ucl_nrv2e_decompress_8(tmpBuf + 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; + } + } + free(tmpBuf); + } + if (!_buf) { + printf("Invalid savegame %s\n", filename); + _ioFailed = true; + } + fio.close(fd); + } +} -StdioSaveFile::StdioSaveFile(const char *filename, bool saveOrLoad) { - _fh = ::fopen(filename, (saveOrLoad? "wb" : "rb")); - _saving = saveOrLoad; +UclInSaveFile::~UclInSaveFile(void) { + if (_buf) + free(_buf); + _screen->wantAnim(false); } -StdioSaveFile::~StdioSaveFile(void) { - if (_fh) - ::fclose(_fh); +bool UclInSaveFile::ioFailed(void) { + return _ioFailed; } -bool StdioSaveFile::isOpen(void) const { - return _fh != NULL; +void UclInSaveFile::clearIOFailed(void) { + _ioFailed = false; } -uint32 StdioSaveFile::read(void *buf, uint32 cnt) { - assert(!_saving); - return ::fread(buf, 1, cnt, _fh); +bool UclInSaveFile::eos(void) const { + return _bufPos == _bufSize; } -uint32 StdioSaveFile::write(const void *buf, uint32 cnt) { - assert(_saving); - return ::fwrite(buf, 1, cnt, _fh); +uint32 UclInSaveFile::read(void *ptr, uint32 size) { + uint32 bytesRemain = _bufSize - _bufPos; + if (size > bytesRemain) { + size = bytesRemain; + _ioFailed = true; + } + memcpy(ptr, _buf + _bufPos, size); + _bufPos += size; + return size; } -UclSaveFile::UclSaveFile(const char *filename, bool saveOrLoad, Gs2dScreen *screen) { - _fh = ::fopen(filename, (saveOrLoad? "wb" : "rb")); - _saving = saveOrLoad; - _bufPos = 0; +UclOutSaveFile::UclOutSaveFile(const char *filename, Gs2dScreen *screen) { _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); - } + _bufPos = 0; + _fd = fio.open(filename, O_WRONLY | O_CREAT | O_TRUNC); + if (_fd >= 0) { + _bufSize = 65536; + _buf = (uint8*)malloc(_bufSize); + _ioFailed = false; } else { - printf("Savefile %s doesn't exist\n", filename); + _ioFailed = true; + _bufSize = 0; _buf = NULL; } } -UclSaveFile::~UclSaveFile(void) { - if (_saving) { +UclOutSaveFile::~UclOutSaveFile(void) { + if (_buf) { + if (flush() < 0) + printf("~UclOutSaveFile: Flush failed!\n"); + free(_buf); + } + if (_fd >= 0) + fio.close(_fd); + _screen->wantAnim(false); +} + +bool UclOutSaveFile::ioFailed(void) { + return _ioFailed; +} + +void UclOutSaveFile::clearIOFailed(void) { + _ioFailed = false; +} + +int UclOutSaveFile::flush(void) { + if (_bufPos == 0) + return 0; // no data to flush + if (_buf) { 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); + fio.write(_fd, &_bufPos, 4); + if (fio.sync(_fd) == 4) { + fio.write(_fd, compBuf, compSize); + if (fio.sync(_fd) != compSize) + res = -1; + } else + res = -1; + } else + printf("Unable to compress %d bytes of savedata, errorcode %d\n", _bufPos, res); + free(compBuf); + + if (res >= 0) { + _bufPos = 0; + return 0; } - free(compBuf); } - if (_buf) - free(_buf); - if (_fh) - ::fclose(_fh); - _screen->wantAnim(false); -} - -bool UclSaveFile::isOpen(void) const { - return (_buf != NULL); + _ioFailed = true; + printf("UclOutSaveFile::flush failed!\n"); + return -1; } -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; +uint32 UclOutSaveFile::write(const void *ptr, uint32 size) { + assert(_bufPos <= _bufSize); + uint32 bytesFree = _bufSize - _bufPos; + if (bytesFree < size) { + uint32 allocBytes = (size > 32 * 1024) ? size : 32 * 1024; + _bufSize += allocBytes; _buf = (uint8*)realloc(_buf, _bufSize); + bytesFree = _bufSize - _bufPos; } - memcpy(_buf + _bufPos, buf, cnt); - _bufPos += cnt; - return cnt; + assert(bytesFree >= size); + memcpy(_buf + _bufPos, ptr, size); + _bufPos += size; + return size; } + |