From 35c306b277e41dd71bc5cb6c822be07a9b15b008 Mon Sep 17 00:00:00 2001 From: Steven Casper Date: Thu, 5 Sep 2024 09:01:52 -0400 Subject: [PATCH] More iSG memcard stuff (#364) --- .../MSL/MSL_C/MSL_Common/Include/string.h | 1 + include/dolphin/dolphin.h | 70 ++- src/SB/Core/gc/isavegame.cpp | 457 +++++++++++++++++- src/SB/Core/gc/isavegame.h | 33 +- 4 files changed, 517 insertions(+), 44 deletions(-) diff --git a/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/string.h b/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/string.h index fba49b6a..1245435e 100644 --- a/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/string.h +++ b/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/string.h @@ -9,6 +9,7 @@ extern "C" { void* memset(void*, int, size_t); void* memcpy(void*, const void*, size_t); +int memcmp(const void* ptr1, const void* ptr2, size_t num); size_t strlen(const char*); char* strcpy(char* dest, const char* source); char* strncpy(char* dest, const char* source, size_t n); diff --git a/include/dolphin/dolphin.h b/include/dolphin/dolphin.h index 01a4d64c..1dc1637f 100644 --- a/include/dolphin/dolphin.h +++ b/include/dolphin/dolphin.h @@ -167,26 +167,25 @@ typedef struct OSContext f64 psf[32]; } OSContext; - #define PAD_MAX_CONTROLLERS 4 -#define PAD_BUTTON_LEFT 0x0001 +#define PAD_BUTTON_LEFT 0x0001 #define PAD_BUTTON_RIGHT 0x0002 -#define PAD_BUTTON_DOWN 0x0004 -#define PAD_BUTTON_UP 0x0008 -#define PAD_TRIGGER_Z 0x0010 -#define PAD_TRIGGER_R 0x0020 -#define PAD_TRIGGER_L 0x0040 -#define PAD_BUTTON_A 0x0100 -#define PAD_BUTTON_B 0x0200 -#define PAD_BUTTON_X 0x0400 -#define PAD_BUTTON_Y 0x0800 +#define PAD_BUTTON_DOWN 0x0004 +#define PAD_BUTTON_UP 0x0008 +#define PAD_TRIGGER_Z 0x0010 +#define PAD_TRIGGER_R 0x0020 +#define PAD_TRIGGER_L 0x0040 +#define PAD_BUTTON_A 0x0100 +#define PAD_BUTTON_B 0x0200 +#define PAD_BUTTON_X 0x0400 +#define PAD_BUTTON_Y 0x0800 #define PAD_BUTTON_START 0x1000 -#define PAD_ERR_NONE 0 +#define PAD_ERR_NONE 0 #define PAD_ERR_NO_CONTROLLER -1 -#define PAD_ERR_NOT_READY -2 -#define PAD_ERR_TRANSFER -3 +#define PAD_ERR_NOT_READY -2 +#define PAD_ERR_TRANSFER -3 typedef struct PADStatus { @@ -238,6 +237,19 @@ void AXFreeVoice(_AXVPB*); void OSSetSoundMode(u32 mode); void VIWaitForRetrace(); +#define CARD_FILENAME_MAX 32 +#define CARD_MAX_FILE 127 +#define CARD_ICON_MAX 8 + +typedef struct CARDFileInfo +{ + /*0x00*/ s32 chan; + /*0x04*/ s32 fileNo; + /*0x08*/ s32 offset; + /*0x0C*/ s32 length; + /*0x10*/ u16 iBlock; +} CARDFileInfo; + #define CARD_RESULT_UNLOCKED 1 #define CARD_RESULT_READY 0 #define CARD_RESULT_BUSY -1 @@ -256,9 +268,37 @@ void VIWaitForRetrace(); #define CARD_RESULT_CANCELED -14 #define CARD_RESULT_FATAL_ERROR -128 +// CARDBios.h void CARDInit(void); -s32 CARDUnmount(s32 chan); +s32 CARDFreeBlocks(s32 chan, s32* byteNotUsed, s32* filesNotUsed); +s32 CARDGetEncoding(s32 chan, u16* encode); +s32 CARDGetSectorSize(s32 chan, u32* size); +// CARDMount.h s32 CARDProbeEx(s32 chan, s32* memSize, s32* sectorSize); +s32 CARDUnmount(s32 chan); +// CARDCheck.h +s32 CARDCheckEx(s32 chan, s32* xferBytes); +// CARDStat.h +typedef struct CARDStat +{ + /*0x00*/ char fileName[CARD_FILENAME_MAX]; + /*0x20*/ u32 length; + /*0x24*/ u32 time; + /*0x28*/ u8 gameName[4]; + /*0x2C*/ u8 company[2]; + /*0x2E*/ u8 bannerFormat; + /*0x30*/ u32 iconAddr; + /*0x34*/ u16 iconFormat; + /*0x36*/ u16 iconSpeed; + /*0x38*/ u32 commentAddr; + /*0x3C*/ u32 offsetBanner; + /*0x40*/ u32 offsetBannerTlut; + /*0x44*/ u32 offsetIcon[CARD_ICON_MAX]; + /*0x64*/ u32 offsetIconTlut; + /*0x68*/ u32 offsetData; +} CARDStat; +// CARDRead.h +s32 CARDRead(struct CARDFileInfo* fileInfo, void* buf, s32 length, s32 offset); #ifdef __cplusplus } diff --git a/src/SB/Core/gc/isavegame.cpp b/src/SB/Core/gc/isavegame.cpp index 7147775f..ddc21d32 100644 --- a/src/SB/Core/gc/isavegame.cpp +++ b/src/SB/Core/gc/isavegame.cpp @@ -1,6 +1,9 @@ #include "isavegame.h" +#include "xMemMgr.h" + #include "iFile.h" +#include "iSystem.h" #include "iTRC.h" #include @@ -197,6 +200,449 @@ static S32 iSG_mc_exists(S32 slot) return ret; } +static S32 iSG_mc_tryRepair(st_ISG_MEMCARD_DATA* mcdata) +{ + S32 result = 0; + S32 rc = 0; + s32 xferBytes = 0; + + if (mcdata->unk_0 == 0) + { + rc = 0; + } + + else if (mcdata->unk_12c) + { + rc = 0; + } + else + { + do + { + result = CARDCheckEx(mcdata->unk_4, &xferBytes); + } while (result == CARD_RESULT_BUSY); + + if (result == CARD_RESULT_READY) + { + rc = 1; + } + else if (result == CARD_RESULT_ENCODING) + { + rc = 1; + } + else + { + if (result != CARD_RESULT_BROKEN) + { + mcdata->unk_12c = 1; + } + rc = 0; + } + } + return rc; +} + +static S32 iSG_mc_isformatted(st_ISG_MEMCARD_DATA* mcdata) +{ + S32 result = 0; + S32 rc = 0; + s32 xferBytes = 0; + + if (mcdata->unk_0 == 0) + { + rc = 0; + } + else if (mcdata->unk_12c) + { + rc = 0; + } + else + { + do + { + result = CARDCheckEx(mcdata->unk_4, &xferBytes); + } while (result == CARD_RESULT_BUSY); + + if (result == CARD_RESULT_READY) + { + rc = 1; + } + else if (result == CARD_RESULT_BROKEN) + { + rc = 0; + } + else + { + rc = 0; + } + } + + return rc; +} + +static S32 iSG_mc_isGCcard(st_ISG_MEMCARD_DATA* mcdata, int* param2, int* param3) +{ + S32 result = 0; + S32 rc = 0; + + s32 xferBytes = 0; + u16 encoding = 0; + s32 memSize = 0; + s32 sectorSize = 0; + + if (param2) + { + *param2 = 0; + } + + if (param3) + { + *param3 = 0; + } + + if (mcdata->unk_0 == 0) + { + return 0; + } + if (mcdata->unk_12c) + { + return 0; + } + + do + { + result = CARDProbeEx(mcdata->unk_4, &memSize, §orSize); + } while (result == CARD_RESULT_BUSY); + + if (result == CARD_RESULT_READY) + { + rc = 1; + } + + if (rc != 0) + { + do + { + result = CARDCheckEx(mcdata->unk_4, &xferBytes); + } while (result == CARD_RESULT_BUSY); + + if (result == CARD_RESULT_READY) + { + rc = 1; + } + else if (result == CARD_RESULT_BROKEN) + { + rc = 2; + } + else + { + if (result == CARD_RESULT_ENCODING) + { + rc = 3; + if (param2) + { + *param2 = 1; + } + } + else + { + rc = 0; + if (result == CARD_RESULT_ENCODING && param2) + { + *param2 = 1; + } + if (result == CARD_RESULT_IOERROR && param3) + { + *param3 = 1; + } + } + } + } + + if (rc == 1) + { + do + { + result = CARDGetEncoding(mcdata->unk_4, &encoding); + } while (result == CARD_RESULT_BUSY); + + if (result == CARD_RESULT_READY && encoding && param2) + { + *param2 = 1; + } + } + + return rc; +} + +static S32 iSG_cubeicon_size(S32 param1, S32 param2); +static S32 iSG_get_finfo(st_ISG_MEMCARD_DATA*, const char*); +// PS2 signature: +// static signed int iSG_isSpaceForFile(class st_ISG_MEMCARD_DATA* mcdata, S32 mcidx, S32 fsize, +// char* dpath, char* fname, S32* bytesNeeded, S32* availOnDisk) +static S32 iSG_isSpaceForFile(st_ISG_MEMCARD_DATA* mcdata, S32 param2, const char* param3, + S32* param4, S32* param5, S32* param6) +{ + S32 rc = 0; + S32 result = 0; + s32 byteNotUsed = 0; + s32 filesNotUsed = 0; + S32 len; + + if (mcdata->unk_0 == 0) + { + return 0; + } + len = iSG_cubeicon_size(mcdata->unk_4, mcdata->sectorSize); + len = len + param2; + // FIXME: fakematch: x + (n-1) & -x is the same as Round x up to next n + len = -mcdata->sectorSize & len + mcdata->sectorSize - 1; + + do + { + result = CARDFreeBlocks(mcdata->unk_4, &byteNotUsed, &filesNotUsed); + } while (result == CARD_RESULT_BUSY); + + if (result == CARD_RESULT_READY) + { + if (param5) + { + *param5 = byteNotUsed / mcdata->sectorSize; + } + if (param4) + { + *param4 = len / mcdata->sectorSize; + } + } + else + { + return 0; + } + + if (param6) + { + *param6 = 1; + } + + if (iSG_get_finfo(mcdata, param3)) + { + if (param6) + { + *param6 = *param6 - 1 & ~(*param6 - 1 >> 0x1f); // FIXME: Fakematch + } + if (len <= mcdata->unk_b0.length + byteNotUsed) + { + rc = 1; + } + } + else + { + if (len <= byteNotUsed && filesNotUsed > 0) + { + rc = 1; + } + } + + return rc; +} + +static S32 iSG_mc_mount(S32 slot); +static bool iSG_mc_settgt(st_ISG_MEMCARD_DATA* mcdata, S32 slot) +{ + if (iSG_mc_mount(slot)) + { + mcdata->unk_0 = 1; + mcdata->unk_4 = slot; + + iSG_mc_tryRepair(mcdata); + CARDGetSectorSize(slot, (u32*)&mcdata->sectorSize); + } + else + { + mcdata->unk_0 = 0; + } + + return mcdata->unk_0 != 0; +} + +static S32 iSG_mc_fopen(st_ISG_MEMCARD_DATA*, const char*, int, en_ISG_IOMODE, en_ASYNC_OPERR*); +static void iSG_mc_fclose(st_ISG_MEMCARD_DATA*); +static S32 iSG_get_finfo(st_ISG_MEMCARD_DATA* mcdata, const char* param2) +{ + S32 rc = 0; + en_ASYNC_OPERR operr = ISG_OPERR_NONE; + + if (iSG_mc_fopen(mcdata, param2, -1, ISG_IOMODE_READ, &operr)) + { + rc = 1; + memcpy(&mcdata->unk_b0, &mcdata->unk_20, sizeof(CARDStat)); + memcpy(&mcdata->unk_9c, &mcdata->unk_c, sizeof(CARDFileInfo)); + iSG_mc_fclose(mcdata); + } + + return rc; +} + +static S32 iSG_curKosher(CARDStat* stat, CARDFileInfo* info) +{ + S32 rc = 1; + + if ((stat->iconAddr < 1 || stat->iconAddr > 0x7fffffff) && + (stat->commentAddr < 1 || stat->commentAddr > 0x7fffffff)) + { + rc = 0; + } + else + { + char stuff[0x200] = { 0 }; + sprintf(stuff, "SPONGEBOB:WHENROBOTSATTACK::RyanNeilDan"); + void* alloc = xMemPushTemp(0x5e00 + 0x1f); + // align buf address to 32 bytes + char* buf = (char*)((U32)alloc + 0x1f & ~0x1f); + + S32 result; + do + { + result = CARDRead(info, buf, 0x5e00, 0); + } while (result == CARD_RESULT_BUSY); + + if (result == CARD_RESULT_READY) + { + if (memcmp(buf + 0x5a40, stuff, strlen(stuff) - 1)) + { + rc = 0; + } + + if (memcmp(buf, "Battle for Bikini Bottom", strlen("Battle for Bikini Bottom") - 1)) + { + rc = 0; + } + } + + xMemPopTemp(alloc); + } + + return rc; +} +static S32 iSG_mc_fdel(st_ISG_MEMCARD_DATA*, const char*); +static S32 iSG_fileKosher(st_ISG_MEMCARD_DATA* mcdata, const char* param2, int param3, int* param4) +{ + S32 rc = 0; + en_ASYNC_OPERR operr = ISG_OPERR_NONE; + + if (param4) + { + *param4 = 0; + } + + if (iSG_mc_fopen(mcdata, param2, -1, ISG_IOMODE_READ, &operr) == 0) + { + return -1; + } + + S32 ret = iSG_curKosher(&mcdata->unk_20, &mcdata->unk_c); + iSG_mc_fclose(mcdata); + + if (ret == 0) + { + rc = 0; + if (param3 && iSG_mc_fdel(mcdata, param2) && param4) + { + *param4 = 1; + } + } + else + { + rc = 1; + } + return rc; +} + +static S32 iSG_get_fsize(st_ISG_MEMCARD_DATA* mcdata, const char* param2) +{ + S32 rc = -1; + + if (iSG_get_finfo(mcdata, param2)) + { + rc = mcdata->unk_b0.length; + } + + if (rc < 0) + { + rc = -1; + } + + return rc; +} + +static S32 iSG_get_fmoddate(st_ISG_MEMCARD_DATA* mcdata, const char* fname, int* sec, int* min, + int* hr, int* mon, int* day, int* yr) +{ + S32 rc = 1; + OSCalendarTime time = { 0 }; + + if (iSG_get_finfo(mcdata, fname) == 0) + { + rc = 0; + } + else + { + // FIXME: This first param isn't right, can't decipher the 64 bit math + OSTicksToCalendarTime((u64)mcdata->unk_b0.time * (u64)(GET_BUS_FREQUENCY() / 4), &time); + + if (sec) + { + *sec = time.sec; + } + if (min) + { + *min = time.min; + } + if (hr) + { + *hr = time.hour; + } + if (mon) + { + *mon = time.mon + 1; + } + if (day) + { + *day = time.mday; + } + if (mon) + { + *mon = time.mon + 1; + } + if (day) + { + *day = time.mday; + } + if (yr) + { + *yr = time.year; + } + } + + return rc; +} + +static void iSG_timestamp(CARDStat*) +{ +} + +static S32 iSG_cubeicon_size(S32 slot, S32 param2) +{ + if ((U32)slot > 1) + { + return -1; + } + + // FIXME: fakematch: x + (n-1) & -x is the same as Round x up to next n + S32 t = (param2 + 0x1ffU) & -param2; + return -t & (t + 0x5c3f); +} + static S32 iSG_chk_icondata() { return 1; @@ -225,25 +671,24 @@ static void iSG_discard_icondata() static S32 iSG_mc_unmount(S32 slot) { - S32 ret = 0; - s32 chan = slot; + S32 rc = 0; S32 result; do { - result = CARDUnmount(chan); + result = CARDUnmount(slot); } while (result == CARD_RESULT_BUSY); if (result == CARD_RESULT_READY) { - ret = 1; + rc = 1; } else if (result == CARD_RESULT_NOCARD) { - ret = 1; + rc = 1; } - return ret; + return rc; } static void iSG_cb_asyndone(long, long) diff --git a/src/SB/Core/gc/isavegame.h b/src/SB/Core/gc/isavegame.h index b3c59078..ad96a47f 100644 --- a/src/SB/Core/gc/isavegame.h +++ b/src/SB/Core/gc/isavegame.h @@ -3,28 +3,7 @@ #include -struct sceMcStDateTime -{ - U8 Resv2; - U8 Sec; - U8 Min; - U8 Hour; - U8 Day; - U8 Month; - U16 Year; -}; - -struct sceMcTblGetDir -{ - sceMcStDateTime _Create; - sceMcStDateTime _Modify; - U32 FileSizeByte; - U16 AttrFile; - U16 Reserve1; - U32 Reserve2; - U32 PdaAplNo; - U8 EntryName[32]; -}; +#include enum en_ISG_IOMODE { @@ -131,7 +110,15 @@ public: struct st_ISG_MEMCARD_DATA { S32 unk_0; - S32 unk_pad[75]; + S32 unk_4; + S32 sectorSize; + CARDFileInfo unk_c; + CARDStat unk_20; + S32 unk_pad5[4]; + CARDFileInfo unk_9c; + CARDStat unk_b0; + S32 unk_pad6[4]; + S32 unk_12c; }; #define ISG_NUM_SLOTS 2