From da54226f8a52a6d13e797b58bdfe288aab1ed38f Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Fri, 18 Jul 2025 03:21:54 -0300 Subject: [PATCH 01/16] Implement controller pak functions --- librecomp/src/pak.cpp | 269 ++++++++++++++++++++-- ultramodern/include/ultramodern/ultra64.h | 7 + 2 files changed, 255 insertions(+), 21 deletions(-) diff --git a/librecomp/src/pak.cpp b/librecomp/src/pak.cpp index 0be1513..df86301 100644 --- a/librecomp/src/pak.cpp +++ b/librecomp/src/pak.cpp @@ -1,51 +1,278 @@ +#include +#include #include "ultramodern/ultra64.h" #include "ultramodern/ultramodern.hpp" #include "recomp.h" #include "helpers.hpp" -extern "C" void osPfsInitPak_recomp(uint8_t * rdram, recomp_context* ctx) { - ctx->r2 = 1; // PFS_ERR_NOPACK +typedef struct ControllerPak { + OSPfsState state; + FILE* file; +} ControllerPak; + +static ControllerPak sControllerPak[16]; +static int sFileSelect = 0; + +void ByteSwapFile(u8* buffer, size_t size) { + uint8_t c0, c1, c2, c3; + + for (size_t i = 0; i < size; i += 4) { + c0 = buffer[i + 0]; + c1 = buffer[i + 1]; + c2 = buffer[i + 2]; + c3 = buffer[i + 3]; + + buffer[i + 3] = c0; + buffer[i + 2] = c1; + buffer[i + 1] = c2; + buffer[i + 0] = c3; + } } -extern "C" void osPfsFreeBlocks_recomp(uint8_t * rdram, recomp_context * ctx) { - ctx->r2 = 1; // PFS_ERR_NOPACK +// s32 osPfsIsPlug(OSMesgQueue* mq, u8* pattern) +extern "C" void osPfsIsPlug_recomp(uint8_t* rdram, recomp_context* ctx) { + MEM_B(0, ctx->r5) = 1; // *pattern = 1; + ctx->r2 = 0; // PFS_NO_ERROR } -extern "C" void osPfsAllocateFile_recomp(uint8_t * rdram, recomp_context * ctx) { - ctx->r2 = 1; // PFS_ERR_NOPACK +// s32 osPfsInit(OSMesgQueue* queue, OSPfs* pfs, int channel) { +extern "C" void osPfsInit_recomp(uint8_t* rdram, recomp_context* ctx) { + OSMesgQueue* queue = _arg<0, OSMesgQueue*>(rdram, ctx); + OSPfs* pfs = _arg<1, OSPfs*>(rdram, ctx); + s32 channel = _arg<2, s32>(rdram, ctx); + + pfs->queue = (int32_t) queue; + pfs->channel = channel; + pfs->status = 0x1; + + ctx->r2 = 0; // PFS_NO_ERROR } -extern "C" void osPfsDeleteFile_recomp(uint8_t * rdram, recomp_context * ctx) { - ctx->r2 = 1; // PFS_ERR_NOPACK +// s32 osPfsInitPak(OSMesgQueue* queue, OSPfs* pfs, int channel); +extern "C" void osPfsInitPak_recomp(uint8_t* rdram, recomp_context* ctx) { + OSMesgQueue* queue = _arg<0, OSMesgQueue*>(rdram, ctx); + OSPfs* pfs = _arg<1, OSPfs*>(rdram, ctx); + s32 channel = _arg<2, s32>(rdram, ctx); + + pfs->queue = (int32_t) queue; + pfs->channel = channel; + pfs->status = 0x1; + + ctx->r2 = 0; // PFS_NO_ERROR } -extern "C" void osPfsFileState_recomp(uint8_t * rdram, recomp_context * ctx) { - ctx->r2 = 1; // PFS_ERR_NOPACK +// s32 osPfsFreeBlocks(OSPfs* pfs, s32* bytes_not_used); +extern "C" void osPfsFreeBlocks_recomp(uint8_t* rdram, recomp_context* ctx) { + s32* bytes_not_used = _arg<1, s32*>(rdram, ctx); + + *bytes_not_used = 123 << 8; + + ctx->r2 = 0; // PFS_NO_ERROR } -extern "C" void osPfsFindFile_recomp(uint8_t * rdram, recomp_context * ctx) { - ctx->r2 = 1; // PFS_ERR_NOPACK +// TODO: VALIDATE +// Can't really be validated without a valid controller pak file system header, which is only used +// by the controller pak manager present in games by holding START on boot and not necessary for recomp. +// s32 osPfsAllocateFile(OSPfs* pfs, u16 company_code, u32 game_code, u8* game_name, u8* ext_name, +// int file_size_in_bytes, s32* file_no); +extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { + u16 company_code = _arg<1, u16>(rdram, ctx); + u32 game_code = _arg<2, u32>(rdram, ctx); + u8* game_name = _arg<3, u8*>(rdram, ctx); + u8* ext_name = TO_PTR(u8, MEM_W(0x10, ctx->r29)); + s32 file_size_in_bytes = (s32) MEM_W(0x14, ctx->r29); + s32* file_no = TO_PTR(s32, MEM_W(0x18, ctx->r29)); + + ControllerPak* pak = &sControllerPak[*file_no]; + + printf("osPfsAllocateFile_recomp:\n"); + + *file_no = sFileSelect++; + + char filename[100]; + sprintf(filename, "controllerPak_file_%d.sav", *file_no); + pak->file = fopen(filename, "wb+"); + + file_size_in_bytes = (file_size_in_bytes + 31) & ~31; + + u8* zero_block = (u8*) malloc(file_size_in_bytes); + memset(zero_block, 0, file_size_in_bytes); + fwrite(zero_block, file_size_in_bytes, 1, pak->file); + + pak->state.company_code = company_code; + pak->state.game_code = game_code; + strcpy(pak->state.game_name, (const char*) game_name); + strcpy(pak->state.ext_name, (const char*) ext_name); + + ctx->r2 = 0; // PFS_NO_ERROR } -extern "C" void osPfsReadWriteFile_recomp(uint8_t * rdram, recomp_context * ctx) { - ctx->r2 = 1; // PFS_ERR_NOPACK +// TODO: VALIDATE +// Can't really be validated without a valid controller pak file system header, which is only used +// by the controller pak manager present in games by holding START on boot and not necessary for recomp. +// s32 osPfsDeleteFile(OSPfs* pfs, u16 company_code, u32 game_code, u8* game_name, u8* ext_name); +extern "C" void osPfsDeleteFile_recomp(uint8_t* rdram, recomp_context* ctx) { + u16 company_code = _arg<1, u16>(rdram, ctx); + u32 game_code = _arg<2, u32>(rdram, ctx); + u8* game_name = _arg<3, u8*>(rdram, ctx); + u8* ext_name = TO_PTR(u8, MEM_W(0x10, ctx->r29)); + s32 file_no; + + printf("osPfsDeleteFile_recomp:\n"); + + for (size_t i = 0; i < ARRAYSIZE(sControllerPak); i++) { + if ((sControllerPak[i].state.company_code = company_code) && (sControllerPak[i].state.game_code == game_code) && + (strcmp(sControllerPak[i].state.game_name, (const char*) game_name) == 0) && + strcmp(sControllerPak[i].state.ext_name, (const char*) ext_name) == 0) { + file_no = i; + + char filename[100]; + sprintf(filename, "controllerPak_file_%d.sav", file_no); + remove(filename); + + ctx->r2 = 0; // PFS_NO_ERROR + printf("Returned 0: FILE DELETED\n\n"); + return; + } else { + ctx->r2 = 1; // PFS_ERR_NOPACK + printf("Returned 1: FILE NOT FOUND\n\n"); + } + } } -extern "C" void osPfsChecker_recomp(uint8_t * rdram, recomp_context * ctx) { - ctx->r2 = 1; // PFS_ERR_NOPACK +bool IsFileEmpty(FILE* file, s32 file_no) { + u8 data_buffer[256]; + + fseek(file, 0, SEEK_SET); + fread(data_buffer, 0x100, 1, file); + + long current = ftell(file); + fseek(file, 0, SEEK_END); + long size = ftell(file); + fseek(file, current, SEEK_SET); + + return size == 0; } -extern "C" void osPfsNumFiles_recomp(uint8_t * rdram, recomp_context * ctx) { +// s32 osPfsFileState(OSPfs* pfs, s32 file_no, OSPfsState* state); +extern "C" void osPfsFileState_recomp(uint8_t* rdram, recomp_context* ctx) { + s32 file_no = _arg<1, s32>(rdram, ctx); + OSPfsState* state = _arg<2, OSPfsState*>(rdram, ctx); + + ControllerPak* pak = &sControllerPak[file_no]; + + char filename[100]; + sprintf(filename, "controllerPak_file_%d.sav", file_no); + pak->file = fopen(filename, "rb+"); + if (pak->file == NULL) { + pak->file = fopen(filename, "wb+"); + } + + if (!IsFileEmpty(pak->file, file_no)) { + state->file_size = pak->state.file_size; + state->company_code = pak->state.company_code; + state->game_code = pak->state.game_code; + + for (size_t j = 0; j < ARRAYSIZE(pak->state.game_name); j++) { + state->game_name[j] = pak->state.game_name[j]; + } + for (size_t j = 0; j < ARRAYSIZE(pak->state.ext_name); j++) { + state->ext_name[j] = pak->state.ext_name[j]; + } + + fclose(pak->file); + ctx->r2 = 0; // PFS_NO_ERROR + } else { + fclose(pak->file); + remove(filename); + ctx->r2 = 1; // PFS_ERR_NOPACK + } +} + +// s32 osPfsFindFile(OSPfs* pfs, u16 company_code, u32 game_code, u8* game_name, u8* ext_name, s32* file_no); +extern "C" void osPfsFindFile_recomp(uint8_t* rdram, recomp_context* ctx) { + u16 company_code = _arg<1, u16>(rdram, ctx); + u32 game_code = _arg<2, u32>(rdram, ctx); + u8* game_name = _arg<3, u8*>(rdram, ctx); + u8* ext_name = TO_PTR(u8, MEM_W(0x10, ctx->r29)); + s32* file_no = TO_PTR(s32, MEM_W(0x14, ctx->r29)); + + for (size_t i = 0; i < ARRAYSIZE(sControllerPak); i++) { + if ((sControllerPak[i].state.game_code == game_code) && + (sControllerPak[i].state.company_code == company_code) && + (strcmp(sControllerPak[i].state.game_name, (const char*) game_name) == 0) && + strcmp(sControllerPak[i].state.ext_name, (const char*) ext_name) == 0) { + // File found + *file_no = i; + ctx->r2 = 0; // PFS_NO_ERROR + return; + } + } + + // Open file + *file_no = sFileSelect++; + + char filename[100]; + sprintf(filename, "controllerPak_file_%d.sav", *file_no); + sControllerPak[*file_no].file = fopen(filename, "rb+"); + if (sControllerPak[*file_no].file == NULL) { + sControllerPak[*file_no].file = fopen(filename, "wb+"); + } + + sControllerPak[*file_no].state.company_code = company_code; + sControllerPak[*file_no].state.game_code = game_code; + strcpy(sControllerPak[*file_no].state.game_name, (const char*) game_name); + strcpy(sControllerPak[*file_no].state.ext_name, (const char*) ext_name); + + ctx->r2 = 0; // PFS_NO_ERROR +} + +// s32 osPfsReadWriteFile(OSPfs* pfs, s32 file_no, u8 flag, int offset, int size_in_bytes, u8* data_buffer); +extern "C" void osPfsReadWriteFile_recomp(uint8_t* rdram, recomp_context* ctx) { + s32 file_no = _arg<1, s32>(rdram, ctx); + u8 flag = _arg<2, u8>(rdram, ctx); + s32 offset = _arg<3, s32>(rdram, ctx); + s32 size_in_bytes = (s32) MEM_W(0x10, ctx->r29); + u8* data_buffer = TO_PTR(u8, MEM_W(0x14, ctx->r29)); + + ControllerPak* pak = &sControllerPak[file_no]; + + if (flag == 0) { + fseek(pak->file, offset, SEEK_SET); + fread(data_buffer, size_in_bytes, 1, pak->file); + ByteSwapFile(data_buffer, size_in_bytes); + } else { + ByteSwapFile(data_buffer, size_in_bytes); + fseek(pak->file, offset, SEEK_SET); + fwrite(data_buffer, size_in_bytes, 1, pak->file); + } + + ctx->r2 = 0; // PFS_NO_ERROR +} + +extern "C" void osPfsChecker_recomp(uint8_t* rdram, recomp_context* ctx) { + ctx->r2 = 0; // PFS_NO_ERROR +} + +// s32 osPfsNumFiles(OSPfs* pfs, s32* max_files, s32* files_used); +extern "C" void osPfsNumFiles_recomp(uint8_t* rdram, recomp_context* ctx) { s32* max_files = _arg<1, s32*>(rdram, ctx); s32* files_used = _arg<2, s32*>(rdram, ctx); - *max_files = 0; - *files_used = 0; + u8 files = 0; + for (size_t i = 0; i < ARRAYSIZE(sControllerPak); i++) { + if ((sControllerPak[i].state.company_code != 0) && (sControllerPak[i].state.game_code != 0)) { + files++; + } + } - _return(ctx, 1); // PFS_ERR_NOPACK + *files_used = files; + *max_files = ARRAYSIZE(sControllerPak); + + ctx->r2 = 0; // PFS_NO_ERROR } -extern "C" void osPfsRepairId_recomp(uint8_t * rdram, recomp_context * ctx) { +extern "C" void osPfsRepairId_recomp(uint8_t* rdram, recomp_context* ctx) { _return(ctx, 1); // PFS_ERR_NOPACK } diff --git a/ultramodern/include/ultramodern/ultra64.h b/ultramodern/include/ultramodern/ultra64.h index 71a412f..8b136cf 100644 --- a/ultramodern/include/ultramodern/ultra64.h +++ b/ultramodern/include/ultramodern/ultra64.h @@ -235,6 +235,13 @@ typedef struct { u8 banks; } OSPfs; +typedef struct { + /* 0x00 */ u32 file_size; /* bytes */ + /* 0x04 */ u32 game_code; + /* 0x08 */ u16 company_code; + /* 0x0C */ char ext_name[4]; + /* 0x10 */ char game_name[16]; +} OSPfsState; // size = 0x20 // Controller From ed7db194c4af11cda4dd714e90eca8644c0663f1 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Fri, 18 Jul 2025 03:45:47 -0300 Subject: [PATCH 02/16] get rid of file_no in IsFileEmpty() --- librecomp/src/pak.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/librecomp/src/pak.cpp b/librecomp/src/pak.cpp index df86301..9301286 100644 --- a/librecomp/src/pak.cpp +++ b/librecomp/src/pak.cpp @@ -141,7 +141,7 @@ extern "C" void osPfsDeleteFile_recomp(uint8_t* rdram, recomp_context* ctx) { } } -bool IsFileEmpty(FILE* file, s32 file_no) { +bool IsFileEmpty(FILE* file) { u8 data_buffer[256]; fseek(file, 0, SEEK_SET); @@ -169,7 +169,7 @@ extern "C" void osPfsFileState_recomp(uint8_t* rdram, recomp_context* ctx) { pak->file = fopen(filename, "wb+"); } - if (!IsFileEmpty(pak->file, file_no)) { + if (!IsFileEmpty(pak->file)) { state->file_size = pak->state.file_size; state->company_code = pak->state.company_code; state->game_code = pak->state.game_code; From 7e4a78680a97e36344338a251f8a7518b7bb129b Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sat, 19 Jul 2025 23:22:06 -0300 Subject: [PATCH 03/16] WIP C++ changes --- librecomp/src/pak.cpp | 86 ++++++++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 37 deletions(-) diff --git a/librecomp/src/pak.cpp b/librecomp/src/pak.cpp index 9301286..ab5202d 100644 --- a/librecomp/src/pak.cpp +++ b/librecomp/src/pak.cpp @@ -8,7 +8,7 @@ typedef struct ControllerPak { OSPfsState state; - FILE* file; + std::fstream file; } ControllerPak; static ControllerPak sControllerPak[16]; @@ -84,6 +84,9 @@ extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { s32 file_size_in_bytes = (s32) MEM_W(0x14, ctx->r29); s32* file_no = TO_PTR(s32, MEM_W(0x18, ctx->r29)); + printf("osPfsAllocateFile_recomp was called!\n"); + assert(false); + #if 0 ControllerPak* pak = &sControllerPak[*file_no]; printf("osPfsAllocateFile_recomp:\n"); @@ -92,7 +95,8 @@ extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { char filename[100]; sprintf(filename, "controllerPak_file_%d.sav", *file_no); - pak->file = fopen(filename, "wb+"); + // pak->file = fopen(filename, "wb+"); + //pak->file.open() file_size_in_bytes = (file_size_in_bytes + 31) & ~31; @@ -104,7 +108,7 @@ extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { pak->state.game_code = game_code; strcpy(pak->state.game_name, (const char*) game_name); strcpy(pak->state.ext_name, (const char*) ext_name); - + #endif ctx->r2 = 0; // PFS_NO_ERROR } @@ -141,50 +145,48 @@ extern "C" void osPfsDeleteFile_recomp(uint8_t* rdram, recomp_context* ctx) { } } -bool IsFileEmpty(FILE* file) { - u8 data_buffer[256]; - - fseek(file, 0, SEEK_SET); - fread(data_buffer, 0x100, 1, file); - - long current = ftell(file); - fseek(file, 0, SEEK_END); - long size = ftell(file); - fseek(file, current, SEEK_SET); +bool IsFileEmpty(std::fstream& file) { + file.seekg(0, std::ios::end); + long size = file.tellg(); + file.seekg(0, std::ios::beg); return size == 0; } - +// f.read(ptr, size) and f.write(ptr, size); // s32 osPfsFileState(OSPfs* pfs, s32 file_no, OSPfsState* state); extern "C" void osPfsFileState_recomp(uint8_t* rdram, recomp_context* ctx) { s32 file_no = _arg<1, s32>(rdram, ctx); OSPfsState* state = _arg<2, OSPfsState*>(rdram, ctx); - ControllerPak* pak = &sControllerPak[file_no]; + ControllerPak& pak = sControllerPak[file_no]; char filename[100]; sprintf(filename, "controllerPak_file_%d.sav", file_no); - pak->file = fopen(filename, "rb+"); - if (pak->file == NULL) { - pak->file = fopen(filename, "wb+"); + // pak.file = fopen(filename, "rb+"); + pak.file.open(filename, std::ios::binary | std::ios::app); + if (!pak.file.good()) { + printf("File's not good\n"); + assert(false); } - if (!IsFileEmpty(pak->file)) { - state->file_size = pak->state.file_size; - state->company_code = pak->state.company_code; - state->game_code = pak->state.game_code; + if (!IsFileEmpty(pak.file)) { + state->file_size = pak.state.file_size; + state->company_code = pak.state.company_code; + state->game_code = pak.state.game_code; - for (size_t j = 0; j < ARRAYSIZE(pak->state.game_name); j++) { - state->game_name[j] = pak->state.game_name[j]; + for (size_t j = 0; j < ARRAYSIZE(pak.state.game_name); j++) { + state->game_name[j] = pak.state.game_name[j]; } - for (size_t j = 0; j < ARRAYSIZE(pak->state.ext_name); j++) { - state->ext_name[j] = pak->state.ext_name[j]; + for (size_t j = 0; j < ARRAYSIZE(pak.state.ext_name); j++) { + state->ext_name[j] = pak.state.ext_name[j]; } - fclose(pak->file); + // fclose(pak.file); + pak.file.close(); ctx->r2 = 0; // PFS_NO_ERROR } else { - fclose(pak->file); + // fclose(pak.file); + pak.file.close(); remove(filename); ctx->r2 = 1; // PFS_ERR_NOPACK } @@ -215,9 +217,13 @@ extern "C" void osPfsFindFile_recomp(uint8_t* rdram, recomp_context* ctx) { char filename[100]; sprintf(filename, "controllerPak_file_%d.sav", *file_no); - sControllerPak[*file_no].file = fopen(filename, "rb+"); - if (sControllerPak[*file_no].file == NULL) { - sControllerPak[*file_no].file = fopen(filename, "wb+"); + // sControllerPak[*file_no].file = fopen(filename, "rb+"); + // if (sControllerPak[*file_no].file == NULL) { + // sControllerPak[*file_no].file = fopen(filename, "wb+"); + // } + sControllerPak[*file_no].file.open(filename, std::ios::binary | std::ios::app); + if (!sControllerPak[*file_no].file.good()) { + assert(false); } sControllerPak[*file_no].state.company_code = company_code; @@ -236,16 +242,22 @@ extern "C" void osPfsReadWriteFile_recomp(uint8_t* rdram, recomp_context* ctx) { s32 size_in_bytes = (s32) MEM_W(0x10, ctx->r29); u8* data_buffer = TO_PTR(u8, MEM_W(0x14, ctx->r29)); - ControllerPak* pak = &sControllerPak[file_no]; + ControllerPak& pak = sControllerPak[file_no]; if (flag == 0) { - fseek(pak->file, offset, SEEK_SET); - fread(data_buffer, size_in_bytes, 1, pak->file); + // fseek(pak.file, offset, SEEK_SET); + pak.file.seekg(offset, std::ios::beg); + // fread(data_buffer, size_in_bytes, 1, pak.file); + pak.file.read((char*) data_buffer, size_in_bytes); + // TODO: use a separate buffer for holding the swapped memory ByteSwapFile(data_buffer, size_in_bytes); } else { - ByteSwapFile(data_buffer, size_in_bytes); - fseek(pak->file, offset, SEEK_SET); - fwrite(data_buffer, size_in_bytes, 1, pak->file); + // TODO: use a separate buffer for holding the swapped memory + ByteSwapFile(data_buffer, size_in_bytes); + // fseek(pak.file, offset, SEEK_SET); + pak.file.seekg(offset, std::ios::beg); + // fwrite(data_buffer, size_in_bytes, 1, pak.file); + pak.file.write((char*) data_buffer, size_in_bytes); } ctx->r2 = 0; // PFS_NO_ERROR From 118ad933de78563919f2c5d1378175824ea0e956 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sat, 19 Jul 2025 23:49:59 -0300 Subject: [PATCH 04/16] WIP C++ changes --- librecomp/src/pak.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/librecomp/src/pak.cpp b/librecomp/src/pak.cpp index ab5202d..394ee3e 100644 --- a/librecomp/src/pak.cpp +++ b/librecomp/src/pak.cpp @@ -86,7 +86,7 @@ extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { printf("osPfsAllocateFile_recomp was called!\n"); assert(false); - #if 0 +#if 0 ControllerPak* pak = &sControllerPak[*file_no]; printf("osPfsAllocateFile_recomp:\n"); @@ -108,7 +108,7 @@ extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { pak->state.game_code = game_code; strcpy(pak->state.game_name, (const char*) game_name); strcpy(pak->state.ext_name, (const char*) ext_name); - #endif +#endif ctx->r2 = 0; // PFS_NO_ERROR } @@ -163,7 +163,7 @@ extern "C" void osPfsFileState_recomp(uint8_t* rdram, recomp_context* ctx) { char filename[100]; sprintf(filename, "controllerPak_file_%d.sav", file_no); // pak.file = fopen(filename, "rb+"); - pak.file.open(filename, std::ios::binary | std::ios::app); + pak.file.open(filename, std::ios::binary | std::ios::in | std::ios::out); if (!pak.file.good()) { printf("File's not good\n"); assert(false); @@ -221,7 +221,7 @@ extern "C" void osPfsFindFile_recomp(uint8_t* rdram, recomp_context* ctx) { // if (sControllerPak[*file_no].file == NULL) { // sControllerPak[*file_no].file = fopen(filename, "wb+"); // } - sControllerPak[*file_no].file.open(filename, std::ios::binary | std::ios::app); + sControllerPak[*file_no].file.open(filename, std::ios::binary | std::ios::in | std::ios::out); if (!sControllerPak[*file_no].file.good()) { assert(false); } @@ -253,7 +253,7 @@ extern "C" void osPfsReadWriteFile_recomp(uint8_t* rdram, recomp_context* ctx) { ByteSwapFile(data_buffer, size_in_bytes); } else { // TODO: use a separate buffer for holding the swapped memory - ByteSwapFile(data_buffer, size_in_bytes); + ByteSwapFile(data_buffer, size_in_bytes); // fseek(pak.file, offset, SEEK_SET); pak.file.seekg(offset, std::ios::beg); // fwrite(data_buffer, size_in_bytes, 1, pak.file); From b18f6b3ff895dbf6e050ef17f38a73b778007fc7 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sun, 20 Jul 2025 19:30:14 -0300 Subject: [PATCH 05/16] Refactor. State: OK --- librecomp/src/pak.cpp | 491 +++++++++++++++++++++++++++++++++--------- 1 file changed, 384 insertions(+), 107 deletions(-) diff --git a/librecomp/src/pak.cpp b/librecomp/src/pak.cpp index 394ee3e..6014714 100644 --- a/librecomp/src/pak.cpp +++ b/librecomp/src/pak.cpp @@ -6,12 +6,13 @@ #include "recomp.h" #include "helpers.hpp" +#define MAX_FILES 16 typedef struct ControllerPak { OSPfsState state; std::fstream file; + std::fstream header; } ControllerPak; -static ControllerPak sControllerPak[16]; static int sFileSelect = 0; void ByteSwapFile(u8* buffer, size_t size) { @@ -30,6 +31,9 @@ void ByteSwapFile(u8* buffer, size_t size) { } } +void Pak_WriteHeader(OSPfsState state, s32 file_no) { +} + // s32 osPfsIsPlug(OSMesgQueue* mq, u8* pattern) extern "C" void osPfsIsPlug_recomp(uint8_t* rdram, recomp_context* ctx) { MEM_B(0, ctx->r5) = 1; // *pattern = 1; @@ -46,6 +50,13 @@ extern "C" void osPfsInit_recomp(uint8_t* rdram, recomp_context* ctx) { pfs->channel = channel; pfs->status = 0x1; + ControllerPak pak; + + if (!std::filesystem::exists("controllerPak_header.sav")) { + pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out | std::ios::trunc); + pak.header.close(); + } + ctx->r2 = 0; // PFS_NO_ERROR } @@ -66,7 +77,51 @@ extern "C" void osPfsInitPak_recomp(uint8_t* rdram, recomp_context* ctx) { extern "C" void osPfsFreeBlocks_recomp(uint8_t* rdram, recomp_context* ctx) { s32* bytes_not_used = _arg<1, s32*>(rdram, ctx); - *bytes_not_used = 123 << 8; + // locals: + s32 usedSpace = 0; + + ControllerPak pak; + + // *bytes_not_used = 123 << 8; + + pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); + + if (!pak.header.good()) { + printf("file is not good!\n"); + assert(false); + } + if (!pak.header.is_open()) { + printf("file isn't open!\n"); + assert(false); + } + + for (size_t i = 0; i < 16; i++) { + u32 seek = i * sizeof(OSPfsState); + s32 file_size_in_bytes; + u32 game_code; + u16 company_code; + + // file_size + pak.header.seekg(seek + 0x0, std::ios::beg); + pak.header.read((char*) &file_size_in_bytes, sizeof(file_size_in_bytes)); + // game_code + pak.header.seekg(seek + 0x4, std::ios::beg); + pak.header.read((char*) &game_code, sizeof(game_code)); + // company_code + pak.header.seekg(seek + 0x08, std::ios::beg); + pak.header.read((char*) &company_code, sizeof(company_code)); + + if ((company_code == 0) || (game_code == 0)) { + continue; + } else { + usedSpace += file_size_in_bytes >> 8; + file_size_in_bytes = game_code = company_code = 0; + } + } + + pak.header.close(); + + *bytes_not_used = (123 - usedSpace) << 8; ctx->r2 = 0; // PFS_NO_ERROR } @@ -84,112 +139,177 @@ extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { s32 file_size_in_bytes = (s32) MEM_W(0x14, ctx->r29); s32* file_no = TO_PTR(s32, MEM_W(0x18, ctx->r29)); - printf("osPfsAllocateFile_recomp was called!\n"); - assert(false); + if ((company_code == 0) || (game_code == 0)) { + ctx->r2 = 5; // PFS_ERR_INVALID + return; + } + + ControllerPak pak; + + pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); + + if (!pak.header.good()) { + printf("file is not good!\n"); + assert(false); + } + if (!pak.header.is_open()) { + printf("file isn't open!\n"); + assert(false); + } + u8 freeFileIndex = 0; #if 0 - ControllerPak* pak = &sControllerPak[*file_no]; + /* Search for a free slot */ + for (size_t i = 0; i < 16; i++) { + u32 seek = i * sizeof(OSPfsState); + u32 game_code_; + u16 company_code_; - printf("osPfsAllocateFile_recomp:\n"); + // game_code + pak.header.seekg(seek + 0x4, std::ios::beg); + pak.header.read((char*) &game_code_, sizeof(game_code_)); + // company_code + pak.header.seekg(seek + 0x08, std::ios::beg); + pak.header.read((char*) &company_code_, sizeof(company_code_)); - *file_no = sFileSelect++; + if ((company_code_ == 0) || (game_code_ == 0)) { + freeFileIndex = i; + break; + } + + game_code_ = company_code_ = 0; + } +#endif + /* Set file parameters to header */ + freeFileIndex = 0; + u32 seek = freeFileIndex * 0x20; + + // file_size + pak.header.seekp(seek + 0x0, std::ios::beg); + pak.header.write((char*) &file_size_in_bytes, sizeof(file_size_in_bytes)); + // game_code + pak.header.seekp(seek + 0x4, std::ios::beg); + pak.header.write((char*) &game_code, sizeof(game_code)); + // company_code + pak.header.seekp(seek + 0x08, std::ios::beg); + pak.header.write((char*) &company_code, sizeof(company_code)); + // ext_name + pak.header.seekp(seek + 0x0C, std::ios::beg); + pak.header.write((char*) ext_name, 4); + // game_name + pak.header.seekp(seek + 0x10, std::ios::beg); + pak.header.write((char*) game_name, 16); + + pak.header.close(); + + /* Create empty file */ char filename[100]; - sprintf(filename, "controllerPak_file_%d.sav", *file_no); - // pak->file = fopen(filename, "wb+"); - //pak->file.open() + sprintf(filename, "controllerPak_file_%d.sav", freeFileIndex); + pak.file.open(filename, std::ios::binary | std::ios::in | std::ios::out | std::ios::trunc); file_size_in_bytes = (file_size_in_bytes + 31) & ~31; u8* zero_block = (u8*) malloc(file_size_in_bytes); memset(zero_block, 0, file_size_in_bytes); - fwrite(zero_block, file_size_in_bytes, 1, pak->file); - pak->state.company_code = company_code; - pak->state.game_code = game_code; - strcpy(pak->state.game_name, (const char*) game_name); - strcpy(pak->state.ext_name, (const char*) ext_name); -#endif + pak.file.seekp(0, std::ios::beg); + pak.file.write((char*) zero_block, file_size_in_bytes); + + free(zero_block); + + pak.file.close(); + + *file_no = freeFileIndex; + ctx->r2 = 0; // PFS_NO_ERROR } -// TODO: VALIDATE -// Can't really be validated without a valid controller pak file system header, which is only used -// by the controller pak manager present in games by holding START on boot and not necessary for recomp. -// s32 osPfsDeleteFile(OSPfs* pfs, u16 company_code, u32 game_code, u8* game_name, u8* ext_name); -extern "C" void osPfsDeleteFile_recomp(uint8_t* rdram, recomp_context* ctx) { - u16 company_code = _arg<1, u16>(rdram, ctx); - u32 game_code = _arg<2, u32>(rdram, ctx); - u8* game_name = _arg<3, u8*>(rdram, ctx); - u8* ext_name = TO_PTR(u8, MEM_W(0x10, ctx->r29)); - s32 file_no; - - printf("osPfsDeleteFile_recomp:\n"); - - for (size_t i = 0; i < ARRAYSIZE(sControllerPak); i++) { - if ((sControllerPak[i].state.company_code = company_code) && (sControllerPak[i].state.game_code == game_code) && - (strcmp(sControllerPak[i].state.game_name, (const char*) game_name) == 0) && - strcmp(sControllerPak[i].state.ext_name, (const char*) ext_name) == 0) { - file_no = i; - - char filename[100]; - sprintf(filename, "controllerPak_file_%d.sav", file_no); - remove(filename); - - ctx->r2 = 0; // PFS_NO_ERROR - printf("Returned 0: FILE DELETED\n\n"); - return; - } else { - ctx->r2 = 1; // PFS_ERR_NOPACK - printf("Returned 1: FILE NOT FOUND\n\n"); - } - } -} - bool IsFileEmpty(std::fstream& file) { + + if (!file.good()) { + return 1; + } + file.seekg(0, std::ios::end); long size = file.tellg(); file.seekg(0, std::ios::beg); return size == 0; } -// f.read(ptr, size) and f.write(ptr, size); + // s32 osPfsFileState(OSPfs* pfs, s32 file_no, OSPfsState* state); extern "C" void osPfsFileState_recomp(uint8_t* rdram, recomp_context* ctx) { s32 file_no = _arg<1, s32>(rdram, ctx); OSPfsState* state = _arg<2, OSPfsState*>(rdram, ctx); - ControllerPak& pak = sControllerPak[file_no]; + // locals: + s32 file_size_in_bytes; + u32 game_code; + u16 company_code; + char ext_name[4]; + char game_name[16]; + + // should pass the state of the requested file_no to the incoming state pointer, + // games call this function 16 times, once per bank + // fills the incoming state with the information inside the header of the pak. + + /* Read game info from pak */ + ControllerPak pak; char filename[100]; sprintf(filename, "controllerPak_file_%d.sav", file_no); - // pak.file = fopen(filename, "rb+"); pak.file.open(filename, std::ios::binary | std::ios::in | std::ios::out); - if (!pak.file.good()) { - printf("File's not good\n"); + + if (IsFileEmpty(pak.file)) { + pak.file.close(); + ctx->r2 = 1; // PFS_NO_ERROR + return; + } + pak.file.close(); + + pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); + + if (!pak.header.good()) { + printf("file is not good!\n"); + assert(false); + } + if (!pak.header.is_open()) { + printf("file isn't open!\n"); assert(false); } - if (!IsFileEmpty(pak.file)) { - state->file_size = pak.state.file_size; - state->company_code = pak.state.company_code; - state->game_code = pak.state.game_code; + u32 seek = file_no * sizeof(OSPfsState); - for (size_t j = 0; j < ARRAYSIZE(pak.state.game_name); j++) { - state->game_name[j] = pak.state.game_name[j]; - } - for (size_t j = 0; j < ARRAYSIZE(pak.state.ext_name); j++) { - state->ext_name[j] = pak.state.ext_name[j]; - } + // file_size + pak.header.seekg(seek + 0x0, std::ios::beg); + pak.header.read((char*) &file_size_in_bytes, sizeof(file_size_in_bytes)); + // game_code + pak.header.seekg(seek + 0x4, std::ios::beg); + pak.header.read((char*) &game_code, sizeof(game_code)); + // company_code + pak.header.seekg(seek + 0x08, std::ios::beg); + pak.header.read((char*) &company_code, sizeof(company_code)); + // ext_name + pak.header.seekg(seek + 0x0C, std::ios::beg); + pak.header.read((char*) ext_name, ARRAYSIZE(ext_name)); + // game_name + pak.header.seekg(seek + 0x10, std::ios::beg); + pak.header.read((char*) game_name, ARRAYSIZE(game_name)); - // fclose(pak.file); - pak.file.close(); - ctx->r2 = 0; // PFS_NO_ERROR - } else { - // fclose(pak.file); - pak.file.close(); - remove(filename); - ctx->r2 = 1; // PFS_ERR_NOPACK + pak.header.close(); + + state->file_size = file_size_in_bytes; + state->company_code = game_code; + state->game_code = game_code; + + for (size_t j = 0; j < ARRAYSIZE(game_name); j++) { + state->game_name[j] = game_name[j]; } + for (size_t j = 0; j < ARRAYSIZE(ext_name); j++) { + state->ext_name[j] = ext_name[j]; + } + + ctx->r2 = 0; // PFS_NO_ERROR } // s32 osPfsFindFile(OSPfs* pfs, u16 company_code, u32 game_code, u8* game_name, u8* ext_name, s32* file_no); @@ -198,40 +318,73 @@ extern "C" void osPfsFindFile_recomp(uint8_t* rdram, recomp_context* ctx) { u32 game_code = _arg<2, u32>(rdram, ctx); u8* game_name = _arg<3, u8*>(rdram, ctx); u8* ext_name = TO_PTR(u8, MEM_W(0x10, ctx->r29)); - s32* file_no = TO_PTR(s32, MEM_W(0x14, ctx->r29)); + s32* file_no = TO_PTR(s32, MEM_W(0x14, ctx->r29)); // we should return the index of the file found here - for (size_t i = 0; i < ARRAYSIZE(sControllerPak); i++) { - if ((sControllerPak[i].state.game_code == game_code) && - (sControllerPak[i].state.company_code == company_code) && - (strcmp(sControllerPak[i].state.game_name, (const char*) game_name) == 0) && - strcmp(sControllerPak[i].state.ext_name, (const char*) ext_name) == 0) { - // File found - *file_no = i; - ctx->r2 = 0; // PFS_NO_ERROR - return; - } - } - - // Open file - *file_no = sFileSelect++; + ControllerPak pak; char filename[100]; sprintf(filename, "controllerPak_file_%d.sav", *file_no); - // sControllerPak[*file_no].file = fopen(filename, "rb+"); - // if (sControllerPak[*file_no].file == NULL) { - // sControllerPak[*file_no].file = fopen(filename, "wb+"); - // } - sControllerPak[*file_no].file.open(filename, std::ios::binary | std::ios::in | std::ios::out); - if (!sControllerPak[*file_no].file.good()) { + pak.file.open(filename, std::ios::binary | std::ios::in | std::ios::out); + + if (!std::filesystem::exists(filename) || IsFileEmpty(pak.file)) { + pak.file.close(); + ctx->r2 = 5; // PFS_ERR_INVALID + return; + } + pak.file.close(); + + pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); + + if (!pak.header.good()) { + printf("file is not good!\n"); + assert(false); + } + if (!pak.header.is_open()) { + printf("file isn't open!\n"); assert(false); } - sControllerPak[*file_no].state.company_code = company_code; - sControllerPak[*file_no].state.game_code = game_code; - strcpy(sControllerPak[*file_no].state.game_name, (const char*) game_name); - strcpy(sControllerPak[*file_no].state.ext_name, (const char*) ext_name); + for (size_t i = 0; i < 16; i++) { + // locals: + u32 game_code_; + u16 company_code_; + char ext_name_[4]; + char game_name_[16]; + u32 seek = i * sizeof(OSPfsState); - ctx->r2 = 0; // PFS_NO_ERROR + // game_code + pak.header.seekg(seek + 0x4, std::ios::beg); + pak.header.read((char*) &game_code_, sizeof(game_code_)); + // company_code + pak.header.seekg(seek + 0x08, std::ios::beg); + pak.header.read((char*) &company_code_, sizeof(company_code_)); + // ext_name + pak.header.seekg(seek + 0x0C, std::ios::beg); + pak.header.read((char*) ext_name_, 4); + // game_name + pak.header.seekg(seek + 0x10, std::ios::beg); + pak.header.read((char*) game_name_, 16); + + + + if ((company_code_ == 0) || (game_code_ == 0)) { + continue; + } else { + if ((game_code == game_code_) && (company_code == company_code_) && + (strcmp((const char*) game_name, (const char*) game_name_) == 0) && + strcmp((const char*) ext_name, (const char*) ext_name_) == 0) { + // File found + *file_no = i; + pak.header.close(); + ctx->r2 = 0; // PFS_NO_ERROR + return; + } + } + } + + pak.header.close(); + // File not found + ctx->r2 = 5; // PFS_ERR_INVALID } // s32 osPfsReadWriteFile(OSPfs* pfs, s32 file_no, u8 flag, int offset, int size_in_bytes, u8* data_buffer); @@ -242,24 +395,39 @@ extern "C" void osPfsReadWriteFile_recomp(uint8_t* rdram, recomp_context* ctx) { s32 size_in_bytes = (s32) MEM_W(0x10, ctx->r29); u8* data_buffer = TO_PTR(u8, MEM_W(0x14, ctx->r29)); - ControllerPak& pak = sControllerPak[file_no]; + ControllerPak pak; + + char filename[100]; + sprintf(filename, "controllerPak_file_%d.sav", file_no); + pak.file.open(filename, std::ios::binary | std::ios::in | std::ios::out); + + if (!pak.file.good()) { + printf("file is not good!\n"); + ctx->r2 = 5; // PFS_ERR_INVALID // VALIDATE + return; + // assert(false); + } + if (!pak.file.is_open()) { + printf("file isn't open!\n"); + ctx->r2 = 5; // PFS_ERR_INVALID // VALIDATE + return; + // assert(false); + } if (flag == 0) { - // fseek(pak.file, offset, SEEK_SET); pak.file.seekg(offset, std::ios::beg); - // fread(data_buffer, size_in_bytes, 1, pak.file); pak.file.read((char*) data_buffer, size_in_bytes); // TODO: use a separate buffer for holding the swapped memory ByteSwapFile(data_buffer, size_in_bytes); } else { // TODO: use a separate buffer for holding the swapped memory ByteSwapFile(data_buffer, size_in_bytes); - // fseek(pak.file, offset, SEEK_SET); - pak.file.seekg(offset, std::ios::beg); - // fwrite(data_buffer, size_in_bytes, 1, pak.file); + pak.file.seekp(offset, std::ios::beg); pak.file.write((char*) data_buffer, size_in_bytes); } + pak.file.close(); + ctx->r2 = 0; // PFS_NO_ERROR } @@ -272,19 +440,128 @@ extern "C" void osPfsNumFiles_recomp(uint8_t* rdram, recomp_context* ctx) { s32* max_files = _arg<1, s32*>(rdram, ctx); s32* files_used = _arg<2, s32*>(rdram, ctx); + ControllerPak pak; + + pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); + + if (!pak.header.good()) { + printf("file is not good!\n"); + assert(false); + } + if (!pak.header.is_open()) { + printf("file isn't open!\n"); + assert(false); + } + u8 files = 0; - for (size_t i = 0; i < ARRAYSIZE(sControllerPak); i++) { - if ((sControllerPak[i].state.company_code != 0) && (sControllerPak[i].state.game_code != 0)) { + for (size_t i = 0; i < 16; i++) { + u32 seek = i * sizeof(OSPfsState); + u32 game_code = 0; + u16 company_code = 0; + + // game_code + pak.header.seekg(seek + 0x4, std::ios::beg); + pak.header.read((char*) &game_code, sizeof(game_code)); + // company_code + pak.header.seekg(seek + 0x08, std::ios::beg); + pak.header.read((char*) &company_code, sizeof(company_code)); + + if ((company_code != 0) || (game_code != 0)) { files++; } } + pak.header.close(); + *files_used = files; - *max_files = ARRAYSIZE(sControllerPak); + *max_files = MAX_FILES; ctx->r2 = 0; // PFS_NO_ERROR } +// TODO: Doesn't work, the game is sending NULL game_name, ext_name and company_code for some reason? +// s32 osPfsDeleteFile(OSPfs* pfs, u16 company_code, u32 game_code, u8* game_name, u8* ext_name); +extern "C" void osPfsDeleteFile_recomp(uint8_t* rdram, recomp_context* ctx) { + u16 company_code = _arg<1, u16>(rdram, ctx); + u32 game_code = _arg<2, u32>(rdram, ctx); + u8* game_name = _arg<3, u8*>(rdram, ctx); + u8* ext_name = TO_PTR(u8, MEM_W(0x10, ctx->r29)); + + printf("osPfsDeleteFile_recomp:\n"); + + if (company_code == 0 || game_code == 0) { + ctx->r2 = 5; // PFS_ERR_INVALID + return; + } + + ControllerPak pak; + + pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); + + if (!pak.header.good()) { + printf("file is not good!\n"); + assert(false); + } + if (!pak.header.is_open()) { + printf("file isn't open!\n"); + assert(false); + } + + for (int i = 0; i < MAX_FILES; i++) { + // locals: + u32 game_code_; + u16 company_code_; + char ext_name_[4]; + char game_name_[16]; + u32 seek = i * sizeof(OSPfsState); + + // game_code + pak.header.seekg(seek + 0x4, std::ios::beg); + pak.header.read((char*) &game_code_, sizeof(game_code_)); + // company_code + pak.header.seekg(seek + 0x08, std::ios::beg); + pak.header.read((char*) &company_code_, sizeof(company_code_)); + // ext_name + pak.header.seekg(seek + 0x0C, std::ios::beg); + pak.header.read((char*) ext_name_, 4); + // game_name + pak.header.seekg(seek + 0x10, std::ios::beg); + pak.header.read((char*) game_name_, 16); + + if ((company_code_ == 0) || (game_code_ == 0)) { + continue; + } else { + if ((game_code == game_code_) && (company_code == company_code_) && + (strcmp((const char*) game_name, (const char*) game_name_) == 0) && + strcmp((const char*) ext_name, (const char*) ext_name_) == 0) { + // File found + + // Zero out the header for this file. + u8* zero_block = (u8*) malloc(sizeof(OSPfsState)); + memset(zero_block, 0, sizeof(OSPfsState)); + pak.header.seekp(seek + 0x0, std::ios::beg); + pak.header.write((char*) &zero_block, sizeof(OSPfsState)); + free(zero_block); + + pak.header.close(); + + char filename[100]; + sprintf(filename, "controllerPak_file_%d.sav", i); + remove(filename); + + ctx->r2 = 0; // PFS_NO_ERROR + return; + } + } + } + + pak.header.close(); + + // File not found + ctx->r2 = 5; // PFS_ERR_INVALID + return; +} + extern "C" void osPfsRepairId_recomp(uint8_t* rdram, recomp_context* ctx) { _return(ctx, 1); // PFS_ERR_NOPACK } From c964f29220a540f074a41fd9d036b6a929039651 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sun, 20 Jul 2025 23:00:08 -0300 Subject: [PATCH 06/16] quick fix --- librecomp/src/pak.cpp | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/librecomp/src/pak.cpp b/librecomp/src/pak.cpp index 6014714..c24469d 100644 --- a/librecomp/src/pak.cpp +++ b/librecomp/src/pak.cpp @@ -157,12 +157,12 @@ extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { assert(false); } u8 freeFileIndex = 0; -#if 0 +#if 0 /// THIS IS BROKEN /* Search for a free slot */ - for (size_t i = 0; i < 16; i++) { + for (size_t i = 0; i < MAX_FILES; i++) { u32 seek = i * sizeof(OSPfsState); - u32 game_code_; - u16 company_code_; + u32 game_code_ = 0; + u16 company_code_ = 0; // game_code pak.header.seekg(seek + 0x4, std::ios::beg); @@ -175,12 +175,10 @@ extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { freeFileIndex = i; break; } - - game_code_ = company_code_ = 0; } #endif /* Set file parameters to header */ - freeFileIndex = 0; + // freeFileIndex = 0; u32 seek = freeFileIndex * 0x20; // file_size @@ -322,17 +320,6 @@ extern "C" void osPfsFindFile_recomp(uint8_t* rdram, recomp_context* ctx) { ControllerPak pak; - char filename[100]; - sprintf(filename, "controllerPak_file_%d.sav", *file_no); - pak.file.open(filename, std::ios::binary | std::ios::in | std::ios::out); - - if (!std::filesystem::exists(filename) || IsFileEmpty(pak.file)) { - pak.file.close(); - ctx->r2 = 5; // PFS_ERR_INVALID - return; - } - pak.file.close(); - pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); if (!pak.header.good()) { @@ -365,8 +352,6 @@ extern "C" void osPfsFindFile_recomp(uint8_t* rdram, recomp_context* ctx) { pak.header.seekg(seek + 0x10, std::ios::beg); pak.header.read((char*) game_name_, 16); - - if ((company_code_ == 0) || (game_code_ == 0)) { continue; } else { From e48e7b51375b83f236ff69b0292588106c29edb8 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Mon, 21 Jul 2025 03:58:09 -0300 Subject: [PATCH 07/16] fully working and tested with mk64 and --- librecomp/src/pak.cpp | 140 +++++++++++++----------------------------- 1 file changed, 44 insertions(+), 96 deletions(-) diff --git a/librecomp/src/pak.cpp b/librecomp/src/pak.cpp index c24469d..626fa2b 100644 --- a/librecomp/src/pak.cpp +++ b/librecomp/src/pak.cpp @@ -7,15 +7,13 @@ #include "helpers.hpp" #define MAX_FILES 16 + typedef struct ControllerPak { - OSPfsState state; - std::fstream file; std::fstream header; + std::fstream file; } ControllerPak; -static int sFileSelect = 0; - -void ByteSwapFile(u8* buffer, size_t size) { +void Pfs_ByteSwapFile(u8* buffer, size_t size) { uint8_t c0, c1, c2, c3; for (size_t i = 0; i < size; i += 4) { @@ -31,16 +29,11 @@ void ByteSwapFile(u8* buffer, size_t size) { } } -void Pak_WriteHeader(OSPfsState state, s32 file_no) { -} - -// s32 osPfsIsPlug(OSMesgQueue* mq, u8* pattern) extern "C" void osPfsIsPlug_recomp(uint8_t* rdram, recomp_context* ctx) { - MEM_B(0, ctx->r5) = 1; // *pattern = 1; - ctx->r2 = 0; // PFS_NO_ERROR + MEM_B(0, ctx->r5) = 0b0001; // *pattern = 1; + ctx->r2 = 0; // PFS_NO_ERROR } -// s32 osPfsInit(OSMesgQueue* queue, OSPfs* pfs, int channel) { extern "C" void osPfsInit_recomp(uint8_t* rdram, recomp_context* ctx) { OSMesgQueue* queue = _arg<0, OSMesgQueue*>(rdram, ctx); OSPfs* pfs = _arg<1, OSPfs*>(rdram, ctx); @@ -52,6 +45,7 @@ extern "C" void osPfsInit_recomp(uint8_t* rdram, recomp_context* ctx) { ControllerPak pak; + // If a header file doesn't exist, create it. if (!std::filesystem::exists("controllerPak_header.sav")) { pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out | std::ios::trunc); pak.header.close(); @@ -60,7 +54,6 @@ extern "C" void osPfsInit_recomp(uint8_t* rdram, recomp_context* ctx) { ctx->r2 = 0; // PFS_NO_ERROR } -// s32 osPfsInitPak(OSMesgQueue* queue, OSPfs* pfs, int channel); extern "C" void osPfsInitPak_recomp(uint8_t* rdram, recomp_context* ctx) { OSMesgQueue* queue = _arg<0, OSMesgQueue*>(rdram, ctx); OSPfs* pfs = _arg<1, OSPfs*>(rdram, ctx); @@ -70,36 +63,37 @@ extern "C" void osPfsInitPak_recomp(uint8_t* rdram, recomp_context* ctx) { pfs->channel = channel; pfs->status = 0x1; + ControllerPak pak; + + // If a header file doesn't exist, create it. + if (!std::filesystem::exists("controllerPak_header.sav")) { + pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out | std::ios::trunc); + pak.header.close(); + } + ctx->r2 = 0; // PFS_NO_ERROR } -// s32 osPfsFreeBlocks(OSPfs* pfs, s32* bytes_not_used); extern "C" void osPfsFreeBlocks_recomp(uint8_t* rdram, recomp_context* ctx) { s32* bytes_not_used = _arg<1, s32*>(rdram, ctx); - // locals: - s32 usedSpace = 0; - ControllerPak pak; - // *bytes_not_used = 123 << 8; - pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); if (!pak.header.good()) { - printf("file is not good!\n"); assert(false); } if (!pak.header.is_open()) { - printf("file isn't open!\n"); assert(false); } - for (size_t i = 0; i < 16; i++) { + s32 usedSpace = 0; + for (size_t i = 0; i < MAX_FILES; i++) { u32 seek = i * sizeof(OSPfsState); - s32 file_size_in_bytes; - u32 game_code; - u16 company_code; + s32 file_size_in_bytes = 0; + u32 game_code = 0; + u16 company_code = 0; // file_size pak.header.seekg(seek + 0x0, std::ios::beg); @@ -115,7 +109,6 @@ extern "C" void osPfsFreeBlocks_recomp(uint8_t* rdram, recomp_context* ctx) { continue; } else { usedSpace += file_size_in_bytes >> 8; - file_size_in_bytes = game_code = company_code = 0; } } @@ -126,11 +119,6 @@ extern "C" void osPfsFreeBlocks_recomp(uint8_t* rdram, recomp_context* ctx) { ctx->r2 = 0; // PFS_NO_ERROR } -// TODO: VALIDATE -// Can't really be validated without a valid controller pak file system header, which is only used -// by the controller pak manager present in games by holding START on boot and not necessary for recomp. -// s32 osPfsAllocateFile(OSPfs* pfs, u16 company_code, u32 game_code, u8* game_name, u8* ext_name, -// int file_size_in_bytes, s32* file_no); extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { u16 company_code = _arg<1, u16>(rdram, ctx); u32 game_code = _arg<2, u32>(rdram, ctx); @@ -149,16 +137,14 @@ extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); if (!pak.header.good()) { - printf("file is not good!\n"); assert(false); } if (!pak.header.is_open()) { - printf("file isn't open!\n"); assert(false); } - u8 freeFileIndex = 0; -#if 0 /// THIS IS BROKEN + /* Search for a free slot */ + u8 freeFileIndex = 0; for (size_t i = 0; i < MAX_FILES; i++) { u32 seek = i * sizeof(OSPfsState); u32 game_code_ = 0; @@ -176,10 +162,13 @@ extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { break; } } -#endif + + pak.header.close(); + + pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); + /* Set file parameters to header */ - // freeFileIndex = 0; - u32 seek = freeFileIndex * 0x20; + u32 seek = freeFileIndex * sizeof(OSPfsState); // file_size pak.header.seekp(seek + 0x0, std::ios::beg); @@ -222,20 +211,6 @@ extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { ctx->r2 = 0; // PFS_NO_ERROR } -bool IsFileEmpty(std::fstream& file) { - - if (!file.good()) { - return 1; - } - - file.seekg(0, std::ios::end); - long size = file.tellg(); - file.seekg(0, std::ios::beg); - - return size == 0; -} - -// s32 osPfsFileState(OSPfs* pfs, s32 file_no, OSPfsState* state); extern "C" void osPfsFileState_recomp(uint8_t* rdram, recomp_context* ctx) { s32 file_no = _arg<1, s32>(rdram, ctx); OSPfsState* state = _arg<2, OSPfsState*>(rdram, ctx); @@ -248,31 +223,18 @@ extern "C" void osPfsFileState_recomp(uint8_t* rdram, recomp_context* ctx) { char game_name[16]; // should pass the state of the requested file_no to the incoming state pointer, - // games call this function 16 times, once per bank + // games call this function 16 times, once per file // fills the incoming state with the information inside the header of the pak. /* Read game info from pak */ ControllerPak pak; - char filename[100]; - sprintf(filename, "controllerPak_file_%d.sav", file_no); - pak.file.open(filename, std::ios::binary | std::ios::in | std::ios::out); - - if (IsFileEmpty(pak.file)) { - pak.file.close(); - ctx->r2 = 1; // PFS_NO_ERROR - return; - } - pak.file.close(); - pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); if (!pak.header.good()) { - printf("file is not good!\n"); assert(false); } if (!pak.header.is_open()) { - printf("file isn't open!\n"); assert(false); } @@ -310,29 +272,25 @@ extern "C" void osPfsFileState_recomp(uint8_t* rdram, recomp_context* ctx) { ctx->r2 = 0; // PFS_NO_ERROR } -// s32 osPfsFindFile(OSPfs* pfs, u16 company_code, u32 game_code, u8* game_name, u8* ext_name, s32* file_no); extern "C" void osPfsFindFile_recomp(uint8_t* rdram, recomp_context* ctx) { u16 company_code = _arg<1, u16>(rdram, ctx); u32 game_code = _arg<2, u32>(rdram, ctx); u8* game_name = _arg<3, u8*>(rdram, ctx); u8* ext_name = TO_PTR(u8, MEM_W(0x10, ctx->r29)); - s32* file_no = TO_PTR(s32, MEM_W(0x14, ctx->r29)); // we should return the index of the file found here + s32* file_no = TO_PTR(s32, MEM_W(0x14, ctx->r29)); ControllerPak pak; pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); if (!pak.header.good()) { - printf("file is not good!\n"); assert(false); } if (!pak.header.is_open()) { - printf("file isn't open!\n"); assert(false); } - for (size_t i = 0; i < 16; i++) { - // locals: + for (size_t i = 0; i < MAX_FILES; i++) { u32 game_code_; u16 company_code_; char ext_name_[4]; @@ -368,11 +326,11 @@ extern "C" void osPfsFindFile_recomp(uint8_t* rdram, recomp_context* ctx) { } pak.header.close(); + // File not found ctx->r2 = 5; // PFS_ERR_INVALID } -// s32 osPfsReadWriteFile(OSPfs* pfs, s32 file_no, u8 flag, int offset, int size_in_bytes, u8* data_buffer); extern "C" void osPfsReadWriteFile_recomp(uint8_t* rdram, recomp_context* ctx) { s32 file_no = _arg<1, s32>(rdram, ctx); u8 flag = _arg<2, u8>(rdram, ctx); @@ -386,27 +344,27 @@ extern "C" void osPfsReadWriteFile_recomp(uint8_t* rdram, recomp_context* ctx) { sprintf(filename, "controllerPak_file_%d.sav", file_no); pak.file.open(filename, std::ios::binary | std::ios::in | std::ios::out); - if (!pak.file.good()) { - printf("file is not good!\n"); - ctx->r2 = 5; // PFS_ERR_INVALID // VALIDATE + if (!std::filesystem::exists(filename)) { + ctx->r2 = 5; // PFS_ERR_INVALID + return; + } + if (!pak.file.good()) { + ctx->r2 = 5; // PFS_ERR_INVALID return; - // assert(false); } if (!pak.file.is_open()) { - printf("file isn't open!\n"); - ctx->r2 = 5; // PFS_ERR_INVALID // VALIDATE + ctx->r2 = 5; // PFS_ERR_INVALID return; - // assert(false); } if (flag == 0) { pak.file.seekg(offset, std::ios::beg); pak.file.read((char*) data_buffer, size_in_bytes); // TODO: use a separate buffer for holding the swapped memory - ByteSwapFile(data_buffer, size_in_bytes); + Pfs_ByteSwapFile(data_buffer, size_in_bytes); } else { // TODO: use a separate buffer for holding the swapped memory - ByteSwapFile(data_buffer, size_in_bytes); + Pfs_ByteSwapFile(data_buffer, size_in_bytes); pak.file.seekp(offset, std::ios::beg); pak.file.write((char*) data_buffer, size_in_bytes); } @@ -420,7 +378,6 @@ extern "C" void osPfsChecker_recomp(uint8_t* rdram, recomp_context* ctx) { ctx->r2 = 0; // PFS_NO_ERROR } -// s32 osPfsNumFiles(OSPfs* pfs, s32* max_files, s32* files_used); extern "C" void osPfsNumFiles_recomp(uint8_t* rdram, recomp_context* ctx) { s32* max_files = _arg<1, s32*>(rdram, ctx); s32* files_used = _arg<2, s32*>(rdram, ctx); @@ -430,16 +387,14 @@ extern "C" void osPfsNumFiles_recomp(uint8_t* rdram, recomp_context* ctx) { pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); if (!pak.header.good()) { - printf("file is not good!\n"); assert(false); } if (!pak.header.is_open()) { - printf("file isn't open!\n"); assert(false); } u8 files = 0; - for (size_t i = 0; i < 16; i++) { + for (size_t i = 0; i < MAX_FILES; i++) { u32 seek = i * sizeof(OSPfsState); u32 game_code = 0; u16 company_code = 0; @@ -464,16 +419,12 @@ extern "C" void osPfsNumFiles_recomp(uint8_t* rdram, recomp_context* ctx) { ctx->r2 = 0; // PFS_NO_ERROR } -// TODO: Doesn't work, the game is sending NULL game_name, ext_name and company_code for some reason? -// s32 osPfsDeleteFile(OSPfs* pfs, u16 company_code, u32 game_code, u8* game_name, u8* ext_name); extern "C" void osPfsDeleteFile_recomp(uint8_t* rdram, recomp_context* ctx) { u16 company_code = _arg<1, u16>(rdram, ctx); u32 game_code = _arg<2, u32>(rdram, ctx); u8* game_name = _arg<3, u8*>(rdram, ctx); u8* ext_name = TO_PTR(u8, MEM_W(0x10, ctx->r29)); - printf("osPfsDeleteFile_recomp:\n"); - if (company_code == 0 || game_code == 0) { ctx->r2 = 5; // PFS_ERR_INVALID return; @@ -484,16 +435,13 @@ extern "C" void osPfsDeleteFile_recomp(uint8_t* rdram, recomp_context* ctx) { pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); if (!pak.header.good()) { - printf("file is not good!\n"); assert(false); } if (!pak.header.is_open()) { - printf("file isn't open!\n"); assert(false); } for (int i = 0; i < MAX_FILES; i++) { - // locals: u32 game_code_; u16 company_code_; char ext_name_[4]; @@ -508,10 +456,10 @@ extern "C" void osPfsDeleteFile_recomp(uint8_t* rdram, recomp_context* ctx) { pak.header.read((char*) &company_code_, sizeof(company_code_)); // ext_name pak.header.seekg(seek + 0x0C, std::ios::beg); - pak.header.read((char*) ext_name_, 4); + pak.header.read((char*) ext_name_, sizeof(ext_name_)); // game_name pak.header.seekg(seek + 0x10, std::ios::beg); - pak.header.read((char*) game_name_, 16); + pak.header.read((char*) game_name_, sizeof(game_name_)); if ((company_code_ == 0) || (game_code_ == 0)) { continue; @@ -548,5 +496,5 @@ extern "C" void osPfsDeleteFile_recomp(uint8_t* rdram, recomp_context* ctx) { } extern "C" void osPfsRepairId_recomp(uint8_t* rdram, recomp_context* ctx) { - _return(ctx, 1); // PFS_ERR_NOPACK + _return(ctx, 0); // PFS_NO_ERROR } From bf84e072d1be917b9dfb54c11f3ba3a897ff602b Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Mon, 21 Jul 2025 04:14:15 -0300 Subject: [PATCH 08/16] add padding to OSPfsState --- ultramodern/include/ultramodern/ultra64.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ultramodern/include/ultramodern/ultra64.h b/ultramodern/include/ultramodern/ultra64.h index 8b136cf..7a5dedf 100644 --- a/ultramodern/include/ultramodern/ultra64.h +++ b/ultramodern/include/ultramodern/ultra64.h @@ -239,6 +239,7 @@ typedef struct { /* 0x00 */ u32 file_size; /* bytes */ /* 0x04 */ u32 game_code; /* 0x08 */ u16 company_code; + /* 0x0A */ char pad_0A[2]; /* 0x0C */ char ext_name[4]; /* 0x10 */ char game_name[16]; } OSPfsState; // size = 0x20 From 7361eba6e4cf9b603c77a2ecb390e8bc36f17146 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Mon, 21 Jul 2025 18:38:28 -0300 Subject: [PATCH 09/16] forgot this check --- librecomp/src/pak.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/librecomp/src/pak.cpp b/librecomp/src/pak.cpp index 626fa2b..9e74723 100644 --- a/librecomp/src/pak.cpp +++ b/librecomp/src/pak.cpp @@ -226,6 +226,13 @@ extern "C" void osPfsFileState_recomp(uint8_t* rdram, recomp_context* ctx) { // games call this function 16 times, once per file // fills the incoming state with the information inside the header of the pak. + char filename[100]; + sprintf(filename, "controllerPak_file_%d.sav", file_no); + if (!std::filesystem::exists(filename)) { + ctx->r2 = 5; // PFS_ERR_INVALID + return; + } + /* Read game info from pak */ ControllerPak pak; From 19d26be0aeb7d0946f0a86f821b090f5ab08d398 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Tue, 22 Jul 2025 06:07:41 -0300 Subject: [PATCH 10/16] simplify code and fix DeleteFile bug --- librecomp/src/pak.cpp | 318 ++++++++++++++++++------------------------ 1 file changed, 138 insertions(+), 180 deletions(-) diff --git a/librecomp/src/pak.cpp b/librecomp/src/pak.cpp index 9e74723..c08b1c0 100644 --- a/librecomp/src/pak.cpp +++ b/librecomp/src/pak.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "ultramodern/ultra64.h" #include "ultramodern/ultramodern.hpp" @@ -13,6 +14,79 @@ typedef struct ControllerPak { std::fstream file; } ControllerPak; +// extern std::filesystem::path config_path; +// const std::u8string save_folder = u8"saves"; +// std::filesystem::path save_folder_path = config_path / save_folder; + +void Pfs_PakHeader_Write(u32* file_size, u32* game_code, u16* company_code, u8* ext_name, u8* game_name, u8 fileIndex) { + ControllerPak pak; + + pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); + + if (!pak.header.good()) { + assert(false); + } + if (!pak.header.is_open()) { + assert(false); + } + + /* Set file parameters to header */ + u32 seek = fileIndex * sizeof(OSPfsState); + + // file_size + pak.header.seekp(seek + 0x0, std::ios::beg); + pak.header.write((char*) file_size, 4); + // game_code + pak.header.seekp(seek + 0x4, std::ios::beg); + pak.header.write((char*) game_code, 4); + // company_code + pak.header.seekp(seek + 0x08, std::ios::beg); + pak.header.write((char*) company_code, 2); + // ext_name + pak.header.seekp(seek + 0x0C, std::ios::beg); + pak.header.write((char*) ext_name, 4); + // game_name + pak.header.seekp(seek + 0x10, std::ios::beg); + pak.header.write((char*) game_name, 16); + + pak.header.close(); +} + +void Pfs_PakHeader_Read(u32* file_size, u32* game_code, u16* company_code, char* ext_name, char* game_name, + u8 fileIndex) { + ControllerPak pak; + + pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); + + if (!pak.header.good()) { + assert(false); + } + if (!pak.header.is_open()) { + assert(false); + } + + /* Set file parameters to header */ + u32 seek = fileIndex * sizeof(OSPfsState); + + // file_size + pak.header.seekg(seek + 0x0, std::ios::beg); + pak.header.read((char*) file_size, 4); + // game_code + pak.header.seekg(seek + 0x4, std::ios::beg); + pak.header.read((char*) game_code, 4); + // company_code + pak.header.seekg(seek + 0x08, std::ios::beg); + pak.header.read((char*) company_code, 2); + // ext_name + pak.header.seekg(seek + 0x0C, std::ios::beg); + pak.header.read((char*) ext_name, 4); + // game_name + pak.header.seekg(seek + 0x10, std::ios::beg); + pak.header.read((char*) game_name, 16); + + pak.header.close(); +} + void Pfs_ByteSwapFile(u8* buffer, size_t size) { uint8_t c0, c1, c2, c3; @@ -29,6 +103,12 @@ void Pfs_ByteSwapFile(u8* buffer, size_t size) { } } +void ByteSwapCopy(uint8_t* dst, uint8_t* src, size_t size_bytes) { + for (size_t i = 0; i < size_bytes; i++) { + dst[i] = src[i ^ 3]; + } +} + extern "C" void osPfsIsPlug_recomp(uint8_t* rdram, recomp_context* ctx) { MEM_B(0, ctx->r5) = 0b0001; // *pattern = 1; ctx->r2 = 0; // PFS_NO_ERROR @@ -90,25 +170,18 @@ extern "C" void osPfsFreeBlocks_recomp(uint8_t* rdram, recomp_context* ctx) { s32 usedSpace = 0; for (size_t i = 0; i < MAX_FILES; i++) { - u32 seek = i * sizeof(OSPfsState); - s32 file_size_in_bytes = 0; + u32 file_size = 0; u32 game_code = 0; u16 company_code = 0; + char ext_name[4] = { 0 }; + char game_name[16] = { 0 }; - // file_size - pak.header.seekg(seek + 0x0, std::ios::beg); - pak.header.read((char*) &file_size_in_bytes, sizeof(file_size_in_bytes)); - // game_code - pak.header.seekg(seek + 0x4, std::ios::beg); - pak.header.read((char*) &game_code, sizeof(game_code)); - // company_code - pak.header.seekg(seek + 0x08, std::ios::beg); - pak.header.read((char*) &company_code, sizeof(company_code)); + Pfs_PakHeader_Read(&file_size, &game_code, &company_code, ext_name, game_name, i); if ((company_code == 0) || (game_code == 0)) { continue; } else { - usedSpace += file_size_in_bytes >> 8; + usedSpace += file_size >> 8; } } @@ -124,7 +197,7 @@ extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { u32 game_code = _arg<2, u32>(rdram, ctx); u8* game_name = _arg<3, u8*>(rdram, ctx); u8* ext_name = TO_PTR(u8, MEM_W(0x10, ctx->r29)); - s32 file_size_in_bytes = (s32) MEM_W(0x14, ctx->r29); + u32 file_size = (s32) MEM_W(0x14, ctx->r29); s32* file_no = TO_PTR(s32, MEM_W(0x18, ctx->r29)); if ((company_code == 0) || (game_code == 0)) { @@ -134,28 +207,16 @@ extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { ControllerPak pak; - pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); - - if (!pak.header.good()) { - assert(false); - } - if (!pak.header.is_open()) { - assert(false); - } - /* Search for a free slot */ u8 freeFileIndex = 0; for (size_t i = 0; i < MAX_FILES; i++) { - u32 seek = i * sizeof(OSPfsState); + u32 file_size_ = 0; u32 game_code_ = 0; u16 company_code_ = 0; + char ext_name_[4] = { 0 }; + char game_name_[16] = { 0 }; - // game_code - pak.header.seekg(seek + 0x4, std::ios::beg); - pak.header.read((char*) &game_code_, sizeof(game_code_)); - // company_code - pak.header.seekg(seek + 0x08, std::ios::beg); - pak.header.read((char*) &company_code_, sizeof(company_code_)); + Pfs_PakHeader_Read(&file_size_, &game_code_, &company_code_, ext_name_, game_name_, i); if ((company_code_ == 0) || (game_code_ == 0)) { freeFileIndex = i; @@ -163,30 +224,7 @@ extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { } } - pak.header.close(); - - pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); - - /* Set file parameters to header */ - u32 seek = freeFileIndex * sizeof(OSPfsState); - - // file_size - pak.header.seekp(seek + 0x0, std::ios::beg); - pak.header.write((char*) &file_size_in_bytes, sizeof(file_size_in_bytes)); - // game_code - pak.header.seekp(seek + 0x4, std::ios::beg); - pak.header.write((char*) &game_code, sizeof(game_code)); - // company_code - pak.header.seekp(seek + 0x08, std::ios::beg); - pak.header.write((char*) &company_code, sizeof(company_code)); - // ext_name - pak.header.seekp(seek + 0x0C, std::ios::beg); - pak.header.write((char*) ext_name, 4); - // game_name - pak.header.seekp(seek + 0x10, std::ios::beg); - pak.header.write((char*) game_name, 16); - - pak.header.close(); + Pfs_PakHeader_Write(&file_size, &game_code, &company_code, ext_name, game_name, freeFileIndex); /* Create empty file */ @@ -194,13 +232,13 @@ extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { sprintf(filename, "controllerPak_file_%d.sav", freeFileIndex); pak.file.open(filename, std::ios::binary | std::ios::in | std::ios::out | std::ios::trunc); - file_size_in_bytes = (file_size_in_bytes + 31) & ~31; + file_size = (file_size + 31) & ~31; - u8* zero_block = (u8*) malloc(file_size_in_bytes); - memset(zero_block, 0, file_size_in_bytes); + u8* zero_block = (u8*) malloc(file_size); + memset(zero_block, 0, file_size); pak.file.seekp(0, std::ios::beg); - pak.file.write((char*) zero_block, file_size_in_bytes); + pak.file.write((char*) zero_block, file_size); free(zero_block); @@ -215,57 +253,27 @@ extern "C" void osPfsFileState_recomp(uint8_t* rdram, recomp_context* ctx) { s32 file_no = _arg<1, s32>(rdram, ctx); OSPfsState* state = _arg<2, OSPfsState*>(rdram, ctx); - // locals: - s32 file_size_in_bytes; - u32 game_code; - u16 company_code; - char ext_name[4]; - char game_name[16]; + u32 file_size = 0; + u32 game_code = 0; + u16 company_code = 0; + char ext_name[4] = { 0 }; + char game_name[16] = { 0 }; // should pass the state of the requested file_no to the incoming state pointer, // games call this function 16 times, once per file // fills the incoming state with the information inside the header of the pak. - + // If a header file doesn't exist, create it. char filename[100]; sprintf(filename, "controllerPak_file_%d.sav", file_no); if (!std::filesystem::exists(filename)) { - ctx->r2 = 5; // PFS_ERR_INVALID + ctx->r2 = 5; return; } /* Read game info from pak */ - ControllerPak pak; + Pfs_PakHeader_Read(&file_size, &game_code, &company_code, ext_name, game_name, file_no); - pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); - - if (!pak.header.good()) { - assert(false); - } - if (!pak.header.is_open()) { - assert(false); - } - - u32 seek = file_no * sizeof(OSPfsState); - - // file_size - pak.header.seekg(seek + 0x0, std::ios::beg); - pak.header.read((char*) &file_size_in_bytes, sizeof(file_size_in_bytes)); - // game_code - pak.header.seekg(seek + 0x4, std::ios::beg); - pak.header.read((char*) &game_code, sizeof(game_code)); - // company_code - pak.header.seekg(seek + 0x08, std::ios::beg); - pak.header.read((char*) &company_code, sizeof(company_code)); - // ext_name - pak.header.seekg(seek + 0x0C, std::ios::beg); - pak.header.read((char*) ext_name, ARRAYSIZE(ext_name)); - // game_name - pak.header.seekg(seek + 0x10, std::ios::beg); - pak.header.read((char*) game_name, ARRAYSIZE(game_name)); - - pak.header.close(); - - state->file_size = file_size_in_bytes; + state->file_size = file_size; state->company_code = game_code; state->game_code = game_code; @@ -288,34 +296,14 @@ extern "C" void osPfsFindFile_recomp(uint8_t* rdram, recomp_context* ctx) { ControllerPak pak; - pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); - - if (!pak.header.good()) { - assert(false); - } - if (!pak.header.is_open()) { - assert(false); - } - for (size_t i = 0; i < MAX_FILES; i++) { - u32 game_code_; - u16 company_code_; - char ext_name_[4]; - char game_name_[16]; - u32 seek = i * sizeof(OSPfsState); + u32 file_size_ = 0; + u32 game_code_ = 0; + u16 company_code_ = 0; + char ext_name_[4] = { 0 }; + char game_name_[16] = { 0 }; - // game_code - pak.header.seekg(seek + 0x4, std::ios::beg); - pak.header.read((char*) &game_code_, sizeof(game_code_)); - // company_code - pak.header.seekg(seek + 0x08, std::ios::beg); - pak.header.read((char*) &company_code_, sizeof(company_code_)); - // ext_name - pak.header.seekg(seek + 0x0C, std::ios::beg); - pak.header.read((char*) ext_name_, 4); - // game_name - pak.header.seekg(seek + 0x10, std::ios::beg); - pak.header.read((char*) game_name_, 16); + Pfs_PakHeader_Read(&file_size_, &game_code_, &company_code_, ext_name_, game_name_, i); if ((company_code_ == 0) || (game_code_ == 0)) { continue; @@ -325,15 +313,12 @@ extern "C" void osPfsFindFile_recomp(uint8_t* rdram, recomp_context* ctx) { strcmp((const char*) ext_name, (const char*) ext_name_) == 0) { // File found *file_no = i; - pak.header.close(); ctx->r2 = 0; // PFS_NO_ERROR return; } } } - pak.header.close(); - // File not found ctx->r2 = 5; // PFS_ERR_INVALID } @@ -364,17 +349,17 @@ extern "C" void osPfsReadWriteFile_recomp(uint8_t* rdram, recomp_context* ctx) { return; } + u8* swapBuffer = (u8*) malloc(size_in_bytes); if (flag == 0) { pak.file.seekg(offset, std::ios::beg); - pak.file.read((char*) data_buffer, size_in_bytes); - // TODO: use a separate buffer for holding the swapped memory - Pfs_ByteSwapFile(data_buffer, size_in_bytes); + pak.file.read((char*) swapBuffer, size_in_bytes); + ByteSwapCopy(data_buffer, swapBuffer, size_in_bytes); } else { - // TODO: use a separate buffer for holding the swapped memory - Pfs_ByteSwapFile(data_buffer, size_in_bytes); + ByteSwapCopy(swapBuffer, data_buffer, size_in_bytes); pak.file.seekp(offset, std::ios::beg); - pak.file.write((char*) data_buffer, size_in_bytes); + pak.file.write((char*) swapBuffer, size_in_bytes); } + free(swapBuffer); pak.file.close(); @@ -389,37 +374,21 @@ extern "C" void osPfsNumFiles_recomp(uint8_t* rdram, recomp_context* ctx) { s32* max_files = _arg<1, s32*>(rdram, ctx); s32* files_used = _arg<2, s32*>(rdram, ctx); - ControllerPak pak; - - pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); - - if (!pak.header.good()) { - assert(false); - } - if (!pak.header.is_open()) { - assert(false); - } - u8 files = 0; for (size_t i = 0; i < MAX_FILES; i++) { - u32 seek = i * sizeof(OSPfsState); + u32 file_size = 0; u32 game_code = 0; u16 company_code = 0; + char ext_name[4] = { 0 }; + char game_name[16] = { 0 }; - // game_code - pak.header.seekg(seek + 0x4, std::ios::beg); - pak.header.read((char*) &game_code, sizeof(game_code)); - // company_code - pak.header.seekg(seek + 0x08, std::ios::beg); - pak.header.read((char*) &company_code, sizeof(company_code)); + Pfs_PakHeader_Read(&file_size, &game_code, &company_code, ext_name, game_name, i); if ((company_code != 0) || (game_code != 0)) { files++; } } - pak.header.close(); - *files_used = files; *max_files = MAX_FILES; @@ -439,34 +408,14 @@ extern "C" void osPfsDeleteFile_recomp(uint8_t* rdram, recomp_context* ctx) { ControllerPak pak; - pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); - - if (!pak.header.good()) { - assert(false); - } - if (!pak.header.is_open()) { - assert(false); - } - for (int i = 0; i < MAX_FILES; i++) { - u32 game_code_; - u16 company_code_; - char ext_name_[4]; - char game_name_[16]; - u32 seek = i * sizeof(OSPfsState); + u32 file_size_ = 0; + u32 game_code_ = 0; + u16 company_code_ = 0; + char ext_name_[4] = { 0 }; + char game_name_[16] = { 0 }; - // game_code - pak.header.seekg(seek + 0x4, std::ios::beg); - pak.header.read((char*) &game_code_, sizeof(game_code_)); - // company_code - pak.header.seekg(seek + 0x08, std::ios::beg); - pak.header.read((char*) &company_code_, sizeof(company_code_)); - // ext_name - pak.header.seekg(seek + 0x0C, std::ios::beg); - pak.header.read((char*) ext_name_, sizeof(ext_name_)); - // game_name - pak.header.seekg(seek + 0x10, std::ios::beg); - pak.header.read((char*) game_name_, sizeof(game_name_)); + Pfs_PakHeader_Read(&file_size_, &game_code_, &company_code_, ext_name_, game_name_, i); if ((company_code_ == 0) || (game_code_ == 0)) { continue; @@ -476,11 +425,22 @@ extern "C" void osPfsDeleteFile_recomp(uint8_t* rdram, recomp_context* ctx) { strcmp((const char*) ext_name, (const char*) ext_name_) == 0) { // File found + pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); + + if (!pak.header.good()) { + assert(false); + } + if (!pak.header.is_open()) { + assert(false); + } + + u32 seek = i * sizeof(OSPfsState); + // Zero out the header for this file. u8* zero_block = (u8*) malloc(sizeof(OSPfsState)); memset(zero_block, 0, sizeof(OSPfsState)); pak.header.seekp(seek + 0x0, std::ios::beg); - pak.header.write((char*) &zero_block, sizeof(OSPfsState)); + pak.header.write((char*) zero_block, sizeof(OSPfsState)); free(zero_block); pak.header.close(); @@ -495,8 +455,6 @@ extern "C" void osPfsDeleteFile_recomp(uint8_t* rdram, recomp_context* ctx) { } } - pak.header.close(); - // File not found ctx->r2 = 5; // PFS_ERR_INVALID return; From 9a658b406fd48dd0c3d539c0af3c9bc048024d6f Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Tue, 22 Jul 2025 07:08:31 -0300 Subject: [PATCH 11/16] ARRAY_COUNT --- librecomp/src/pak.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/librecomp/src/pak.cpp b/librecomp/src/pak.cpp index c08b1c0..5911f7c 100644 --- a/librecomp/src/pak.cpp +++ b/librecomp/src/pak.cpp @@ -7,6 +7,7 @@ #include "recomp.h" #include "helpers.hpp" +#define ARRAY_COUNT(arr) (s32)(sizeof(arr) / sizeof(arr[0])) #define MAX_FILES 16 typedef struct ControllerPak { @@ -277,10 +278,10 @@ extern "C" void osPfsFileState_recomp(uint8_t* rdram, recomp_context* ctx) { state->company_code = game_code; state->game_code = game_code; - for (size_t j = 0; j < ARRAYSIZE(game_name); j++) { + for (size_t j = 0; j < ARRAY_COUNT(game_name); j++) { state->game_name[j] = game_name[j]; } - for (size_t j = 0; j < ARRAYSIZE(ext_name); j++) { + for (size_t j = 0; j < ARRAY_COUNT(ext_name); j++) { state->ext_name[j] = ext_name[j]; } From c2a525ed2d1f8c6eb60f10b01d90b93ac01ce0fa Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Tue, 22 Jul 2025 14:45:37 -0300 Subject: [PATCH 12/16] Pak: int32_t queue --- librecomp/src/pak.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librecomp/src/pak.cpp b/librecomp/src/pak.cpp index 5911f7c..56cc7cd 100644 --- a/librecomp/src/pak.cpp +++ b/librecomp/src/pak.cpp @@ -116,7 +116,7 @@ extern "C" void osPfsIsPlug_recomp(uint8_t* rdram, recomp_context* ctx) { } extern "C" void osPfsInit_recomp(uint8_t* rdram, recomp_context* ctx) { - OSMesgQueue* queue = _arg<0, OSMesgQueue*>(rdram, ctx); + int32_t* queue = _arg<0, int32_t*>(rdram, ctx); OSPfs* pfs = _arg<1, OSPfs*>(rdram, ctx); s32 channel = _arg<2, s32>(rdram, ctx); From 33228560d58e1472e06bd39d832bead25a0750c4 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Tue, 22 Jul 2025 15:15:36 -0300 Subject: [PATCH 13/16] pak queue as int32_t --- librecomp/src/pak.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/librecomp/src/pak.cpp b/librecomp/src/pak.cpp index 56cc7cd..57687ba 100644 --- a/librecomp/src/pak.cpp +++ b/librecomp/src/pak.cpp @@ -116,11 +116,11 @@ extern "C" void osPfsIsPlug_recomp(uint8_t* rdram, recomp_context* ctx) { } extern "C" void osPfsInit_recomp(uint8_t* rdram, recomp_context* ctx) { - int32_t* queue = _arg<0, int32_t*>(rdram, ctx); + int32_t queue = _arg<0, int32_t>(rdram, ctx); OSPfs* pfs = _arg<1, OSPfs*>(rdram, ctx); s32 channel = _arg<2, s32>(rdram, ctx); - pfs->queue = (int32_t) queue; + pfs->queue = queue; pfs->channel = channel; pfs->status = 0x1; From ece48700a849a5a9cb47cef7951774362211aa25 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Tue, 22 Jul 2025 15:23:10 -0300 Subject: [PATCH 14/16] forgot to fix osPfsInitPak_recomp --- librecomp/src/pak.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/librecomp/src/pak.cpp b/librecomp/src/pak.cpp index 57687ba..f5751da 100644 --- a/librecomp/src/pak.cpp +++ b/librecomp/src/pak.cpp @@ -136,11 +136,11 @@ extern "C" void osPfsInit_recomp(uint8_t* rdram, recomp_context* ctx) { } extern "C" void osPfsInitPak_recomp(uint8_t* rdram, recomp_context* ctx) { - OSMesgQueue* queue = _arg<0, OSMesgQueue*>(rdram, ctx); + int32_t queue = _arg<0, int32_t>(rdram, ctx); OSPfs* pfs = _arg<1, OSPfs*>(rdram, ctx); s32 channel = _arg<2, s32>(rdram, ctx); - pfs->queue = (int32_t) queue; + pfs->queue = queue; pfs->channel = channel; pfs->status = 0x1; From 1834cef9c9582f093a28560f33145797d2f86664 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Tue, 22 Jul 2025 19:24:12 -0300 Subject: [PATCH 15/16] Pak.cpp: cleanup --- librecomp/src/pak.cpp | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/librecomp/src/pak.cpp b/librecomp/src/pak.cpp index f5751da..e77fb1c 100644 --- a/librecomp/src/pak.cpp +++ b/librecomp/src/pak.cpp @@ -158,17 +158,6 @@ extern "C" void osPfsInitPak_recomp(uint8_t* rdram, recomp_context* ctx) { extern "C" void osPfsFreeBlocks_recomp(uint8_t* rdram, recomp_context* ctx) { s32* bytes_not_used = _arg<1, s32*>(rdram, ctx); - ControllerPak pak; - - pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); - - if (!pak.header.good()) { - assert(false); - } - if (!pak.header.is_open()) { - assert(false); - } - s32 usedSpace = 0; for (size_t i = 0; i < MAX_FILES; i++) { u32 file_size = 0; @@ -186,8 +175,6 @@ extern "C" void osPfsFreeBlocks_recomp(uint8_t* rdram, recomp_context* ctx) { } } - pak.header.close(); - *bytes_not_used = (123 - usedSpace) << 8; ctx->r2 = 0; // PFS_NO_ERROR @@ -206,8 +193,6 @@ extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { return; } - ControllerPak pak; - /* Search for a free slot */ u8 freeFileIndex = 0; for (size_t i = 0; i < MAX_FILES; i++) { @@ -229,6 +214,8 @@ extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { /* Create empty file */ + ControllerPak pak; + char filename[100]; sprintf(filename, "controllerPak_file_%d.sav", freeFileIndex); pak.file.open(filename, std::ios::binary | std::ios::in | std::ios::out | std::ios::trunc); @@ -263,7 +250,7 @@ extern "C" void osPfsFileState_recomp(uint8_t* rdram, recomp_context* ctx) { // should pass the state of the requested file_no to the incoming state pointer, // games call this function 16 times, once per file // fills the incoming state with the information inside the header of the pak. - // If a header file doesn't exist, create it. + char filename[100]; sprintf(filename, "controllerPak_file_%d.sav", file_no); if (!std::filesystem::exists(filename)) { @@ -295,8 +282,6 @@ extern "C" void osPfsFindFile_recomp(uint8_t* rdram, recomp_context* ctx) { u8* ext_name = TO_PTR(u8, MEM_W(0x10, ctx->r29)); s32* file_no = TO_PTR(s32, MEM_W(0x14, ctx->r29)); - ControllerPak pak; - for (size_t i = 0; i < MAX_FILES; i++) { u32 file_size_ = 0; u32 game_code_ = 0; From 381e0704b923c021c25ed7e4e39fae2d2af2338e Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Wed, 23 Jul 2025 05:50:10 -0300 Subject: [PATCH 16/16] osPfsAllocateFile_recomp: add check for max files --- librecomp/src/pak.cpp | 263 ++++++++++++++++++++++++++---------------- 1 file changed, 162 insertions(+), 101 deletions(-) diff --git a/librecomp/src/pak.cpp b/librecomp/src/pak.cpp index e77fb1c..5643a9e 100644 --- a/librecomp/src/pak.cpp +++ b/librecomp/src/pak.cpp @@ -10,7 +10,8 @@ #define ARRAY_COUNT(arr) (s32)(sizeof(arr) / sizeof(arr[0])) #define MAX_FILES 16 -typedef struct ControllerPak { +typedef struct ControllerPak +{ std::fstream header; std::fstream file; } ControllerPak; @@ -19,15 +20,18 @@ typedef struct ControllerPak { // const std::u8string save_folder = u8"saves"; // std::filesystem::path save_folder_path = config_path / save_folder; -void Pfs_PakHeader_Write(u32* file_size, u32* game_code, u16* company_code, u8* ext_name, u8* game_name, u8 fileIndex) { +void Pfs_PakHeader_Write(u32 *file_size, u32 *game_code, u16 *company_code, u8 *ext_name, u8 *game_name, u8 fileIndex) +{ ControllerPak pak; pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); - if (!pak.header.good()) { + if (!pak.header.good()) + { assert(false); } - if (!pak.header.is_open()) { + if (!pak.header.is_open()) + { assert(false); } @@ -36,33 +40,36 @@ void Pfs_PakHeader_Write(u32* file_size, u32* game_code, u16* company_code, u8* // file_size pak.header.seekp(seek + 0x0, std::ios::beg); - pak.header.write((char*) file_size, 4); + pak.header.write((char *)file_size, 4); // game_code pak.header.seekp(seek + 0x4, std::ios::beg); - pak.header.write((char*) game_code, 4); + pak.header.write((char *)game_code, 4); // company_code pak.header.seekp(seek + 0x08, std::ios::beg); - pak.header.write((char*) company_code, 2); + pak.header.write((char *)company_code, 2); // ext_name pak.header.seekp(seek + 0x0C, std::ios::beg); - pak.header.write((char*) ext_name, 4); + pak.header.write((char *)ext_name, 4); // game_name pak.header.seekp(seek + 0x10, std::ios::beg); - pak.header.write((char*) game_name, 16); + pak.header.write((char *)game_name, 16); pak.header.close(); } -void Pfs_PakHeader_Read(u32* file_size, u32* game_code, u16* company_code, char* ext_name, char* game_name, - u8 fileIndex) { +void Pfs_PakHeader_Read(u32 *file_size, u32 *game_code, u16 *company_code, char *ext_name, char *game_name, + u8 fileIndex) +{ ControllerPak pak; pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); - if (!pak.header.good()) { + if (!pak.header.good()) + { assert(false); } - if (!pak.header.is_open()) { + if (!pak.header.is_open()) + { assert(false); } @@ -71,27 +78,29 @@ void Pfs_PakHeader_Read(u32* file_size, u32* game_code, u16* company_code, char* // file_size pak.header.seekg(seek + 0x0, std::ios::beg); - pak.header.read((char*) file_size, 4); + pak.header.read((char *)file_size, 4); // game_code pak.header.seekg(seek + 0x4, std::ios::beg); - pak.header.read((char*) game_code, 4); + pak.header.read((char *)game_code, 4); // company_code pak.header.seekg(seek + 0x08, std::ios::beg); - pak.header.read((char*) company_code, 2); + pak.header.read((char *)company_code, 2); // ext_name pak.header.seekg(seek + 0x0C, std::ios::beg); - pak.header.read((char*) ext_name, 4); + pak.header.read((char *)ext_name, 4); // game_name pak.header.seekg(seek + 0x10, std::ios::beg); - pak.header.read((char*) game_name, 16); + pak.header.read((char *)game_name, 16); pak.header.close(); } -void Pfs_ByteSwapFile(u8* buffer, size_t size) { +void Pfs_ByteSwapFile(u8 *buffer, size_t size) +{ uint8_t c0, c1, c2, c3; - for (size_t i = 0; i < size; i += 4) { + for (size_t i = 0; i < size; i += 4) + { c0 = buffer[i + 0]; c1 = buffer[i + 1]; c2 = buffer[i + 2]; @@ -104,20 +113,24 @@ void Pfs_ByteSwapFile(u8* buffer, size_t size) { } } -void ByteSwapCopy(uint8_t* dst, uint8_t* src, size_t size_bytes) { - for (size_t i = 0; i < size_bytes; i++) { +void ByteSwapCopy(uint8_t *dst, uint8_t *src, size_t size_bytes) +{ + for (size_t i = 0; i < size_bytes; i++) + { dst[i] = src[i ^ 3]; } } -extern "C" void osPfsIsPlug_recomp(uint8_t* rdram, recomp_context* ctx) { +extern "C" void osPfsIsPlug_recomp(uint8_t *rdram, recomp_context *ctx) +{ MEM_B(0, ctx->r5) = 0b0001; // *pattern = 1; ctx->r2 = 0; // PFS_NO_ERROR } -extern "C" void osPfsInit_recomp(uint8_t* rdram, recomp_context* ctx) { +extern "C" void osPfsInit_recomp(uint8_t *rdram, recomp_context *ctx) +{ int32_t queue = _arg<0, int32_t>(rdram, ctx); - OSPfs* pfs = _arg<1, OSPfs*>(rdram, ctx); + OSPfs *pfs = _arg<1, OSPfs *>(rdram, ctx); s32 channel = _arg<2, s32>(rdram, ctx); pfs->queue = queue; @@ -127,7 +140,8 @@ extern "C" void osPfsInit_recomp(uint8_t* rdram, recomp_context* ctx) { ControllerPak pak; // If a header file doesn't exist, create it. - if (!std::filesystem::exists("controllerPak_header.sav")) { + if (!std::filesystem::exists("controllerPak_header.sav")) + { pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out | std::ios::trunc); pak.header.close(); } @@ -135,9 +149,10 @@ extern "C" void osPfsInit_recomp(uint8_t* rdram, recomp_context* ctx) { ctx->r2 = 0; // PFS_NO_ERROR } -extern "C" void osPfsInitPak_recomp(uint8_t* rdram, recomp_context* ctx) { +extern "C" void osPfsInitPak_recomp(uint8_t *rdram, recomp_context *ctx) +{ int32_t queue = _arg<0, int32_t>(rdram, ctx); - OSPfs* pfs = _arg<1, OSPfs*>(rdram, ctx); + OSPfs *pfs = _arg<1, OSPfs *>(rdram, ctx); s32 channel = _arg<2, s32>(rdram, ctx); pfs->queue = queue; @@ -147,7 +162,8 @@ extern "C" void osPfsInitPak_recomp(uint8_t* rdram, recomp_context* ctx) { ControllerPak pak; // If a header file doesn't exist, create it. - if (!std::filesystem::exists("controllerPak_header.sav")) { + if (!std::filesystem::exists("controllerPak_header.sav")) + { pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out | std::ios::trunc); pak.header.close(); } @@ -155,22 +171,27 @@ extern "C" void osPfsInitPak_recomp(uint8_t* rdram, recomp_context* ctx) { ctx->r2 = 0; // PFS_NO_ERROR } -extern "C" void osPfsFreeBlocks_recomp(uint8_t* rdram, recomp_context* ctx) { - s32* bytes_not_used = _arg<1, s32*>(rdram, ctx); +extern "C" void osPfsFreeBlocks_recomp(uint8_t *rdram, recomp_context *ctx) +{ + s32 *bytes_not_used = _arg<1, s32 *>(rdram, ctx); s32 usedSpace = 0; - for (size_t i = 0; i < MAX_FILES; i++) { + for (size_t i = 0; i < MAX_FILES; i++) + { u32 file_size = 0; u32 game_code = 0; u16 company_code = 0; - char ext_name[4] = { 0 }; - char game_name[16] = { 0 }; + char ext_name[4] = {0}; + char game_name[16] = {0}; Pfs_PakHeader_Read(&file_size, &game_code, &company_code, ext_name, game_name, i); - if ((company_code == 0) || (game_code == 0)) { + if ((company_code == 0) || (game_code == 0)) + { continue; - } else { + } + else + { usedSpace += file_size >> 8; } } @@ -180,36 +201,45 @@ extern "C" void osPfsFreeBlocks_recomp(uint8_t* rdram, recomp_context* ctx) { ctx->r2 = 0; // PFS_NO_ERROR } -extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { +extern "C" void osPfsAllocateFile_recomp(uint8_t *rdram, recomp_context *ctx) +{ u16 company_code = _arg<1, u16>(rdram, ctx); u32 game_code = _arg<2, u32>(rdram, ctx); - u8* game_name = _arg<3, u8*>(rdram, ctx); - u8* ext_name = TO_PTR(u8, MEM_W(0x10, ctx->r29)); - u32 file_size = (s32) MEM_W(0x14, ctx->r29); - s32* file_no = TO_PTR(s32, MEM_W(0x18, ctx->r29)); + u8 *game_name = _arg<3, u8 *>(rdram, ctx); + u8 *ext_name = TO_PTR(u8, MEM_W(0x10, ctx->r29)); + u32 file_size = (s32)MEM_W(0x14, ctx->r29); + s32 *file_no = TO_PTR(s32, MEM_W(0x18, ctx->r29)); - if ((company_code == 0) || (game_code == 0)) { + if ((company_code == 0) || (game_code == 0)) + { ctx->r2 = 5; // PFS_ERR_INVALID return; } /* Search for a free slot */ u8 freeFileIndex = 0; - for (size_t i = 0; i < MAX_FILES; i++) { + for (size_t i = 0; i < MAX_FILES; i++) + { u32 file_size_ = 0; u32 game_code_ = 0; u16 company_code_ = 0; - char ext_name_[4] = { 0 }; - char game_name_[16] = { 0 }; + char ext_name_[4] = {0}; + char game_name_[16] = {0}; Pfs_PakHeader_Read(&file_size_, &game_code_, &company_code_, ext_name_, game_name_, i); - if ((company_code_ == 0) || (game_code_ == 0)) { + if ((company_code_ == 0) || (game_code_ == 0)) + { freeFileIndex = i; break; } } + if (freeFileIndex == MAX_FILES) { + ctx->r2 = 8; // PFS_DIR_FULL + return; + } + Pfs_PakHeader_Write(&file_size, &game_code, &company_code, ext_name, game_name, freeFileIndex); /* Create empty file */ @@ -222,11 +252,11 @@ extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { file_size = (file_size + 31) & ~31; - u8* zero_block = (u8*) malloc(file_size); + u8 *zero_block = (u8 *)malloc(file_size); memset(zero_block, 0, file_size); pak.file.seekp(0, std::ios::beg); - pak.file.write((char*) zero_block, file_size); + pak.file.write((char *)zero_block, file_size); free(zero_block); @@ -237,15 +267,16 @@ extern "C" void osPfsAllocateFile_recomp(uint8_t* rdram, recomp_context* ctx) { ctx->r2 = 0; // PFS_NO_ERROR } -extern "C" void osPfsFileState_recomp(uint8_t* rdram, recomp_context* ctx) { +extern "C" void osPfsFileState_recomp(uint8_t *rdram, recomp_context *ctx) +{ s32 file_no = _arg<1, s32>(rdram, ctx); - OSPfsState* state = _arg<2, OSPfsState*>(rdram, ctx); + OSPfsState *state = _arg<2, OSPfsState *>(rdram, ctx); u32 file_size = 0; u32 game_code = 0; u16 company_code = 0; - char ext_name[4] = { 0 }; - char game_name[16] = { 0 }; + char ext_name[4] = {0}; + char game_name[16] = {0}; // should pass the state of the requested file_no to the incoming state pointer, // games call this function 16 times, once per file @@ -253,7 +284,8 @@ extern "C" void osPfsFileState_recomp(uint8_t* rdram, recomp_context* ctx) { char filename[100]; sprintf(filename, "controllerPak_file_%d.sav", file_no); - if (!std::filesystem::exists(filename)) { + if (!std::filesystem::exists(filename)) + { ctx->r2 = 5; return; } @@ -265,38 +297,46 @@ extern "C" void osPfsFileState_recomp(uint8_t* rdram, recomp_context* ctx) { state->company_code = game_code; state->game_code = game_code; - for (size_t j = 0; j < ARRAY_COUNT(game_name); j++) { + for (size_t j = 0; j < ARRAY_COUNT(game_name); j++) + { state->game_name[j] = game_name[j]; } - for (size_t j = 0; j < ARRAY_COUNT(ext_name); j++) { + for (size_t j = 0; j < ARRAY_COUNT(ext_name); j++) + { state->ext_name[j] = ext_name[j]; } ctx->r2 = 0; // PFS_NO_ERROR } -extern "C" void osPfsFindFile_recomp(uint8_t* rdram, recomp_context* ctx) { +extern "C" void osPfsFindFile_recomp(uint8_t *rdram, recomp_context *ctx) +{ u16 company_code = _arg<1, u16>(rdram, ctx); u32 game_code = _arg<2, u32>(rdram, ctx); - u8* game_name = _arg<3, u8*>(rdram, ctx); - u8* ext_name = TO_PTR(u8, MEM_W(0x10, ctx->r29)); - s32* file_no = TO_PTR(s32, MEM_W(0x14, ctx->r29)); + u8 *game_name = _arg<3, u8 *>(rdram, ctx); + u8 *ext_name = TO_PTR(u8, MEM_W(0x10, ctx->r29)); + s32 *file_no = TO_PTR(s32, MEM_W(0x14, ctx->r29)); - for (size_t i = 0; i < MAX_FILES; i++) { + for (size_t i = 0; i < MAX_FILES; i++) + { u32 file_size_ = 0; u32 game_code_ = 0; u16 company_code_ = 0; - char ext_name_[4] = { 0 }; - char game_name_[16] = { 0 }; + char ext_name_[4] = {0}; + char game_name_[16] = {0}; Pfs_PakHeader_Read(&file_size_, &game_code_, &company_code_, ext_name_, game_name_, i); - if ((company_code_ == 0) || (game_code_ == 0)) { + if ((company_code_ == 0) || (game_code_ == 0)) + { continue; - } else { + } + else + { if ((game_code == game_code_) && (company_code == company_code_) && - (strcmp((const char*) game_name, (const char*) game_name_) == 0) && - strcmp((const char*) ext_name, (const char*) ext_name_) == 0) { + (strcmp((const char *)game_name, (const char *)game_name_) == 0) && + strcmp((const char *)ext_name, (const char *)ext_name_) == 0) + { // File found *file_no = i; ctx->r2 = 0; // PFS_NO_ERROR @@ -309,12 +349,13 @@ extern "C" void osPfsFindFile_recomp(uint8_t* rdram, recomp_context* ctx) { ctx->r2 = 5; // PFS_ERR_INVALID } -extern "C" void osPfsReadWriteFile_recomp(uint8_t* rdram, recomp_context* ctx) { +extern "C" void osPfsReadWriteFile_recomp(uint8_t *rdram, recomp_context *ctx) +{ s32 file_no = _arg<1, s32>(rdram, ctx); u8 flag = _arg<2, u8>(rdram, ctx); s32 offset = _arg<3, s32>(rdram, ctx); - s32 size_in_bytes = (s32) MEM_W(0x10, ctx->r29); - u8* data_buffer = TO_PTR(u8, MEM_W(0x14, ctx->r29)); + s32 size_in_bytes = (s32)MEM_W(0x10, ctx->r29); + u8 *data_buffer = TO_PTR(u8, MEM_W(0x14, ctx->r29)); ControllerPak pak; @@ -322,28 +363,34 @@ extern "C" void osPfsReadWriteFile_recomp(uint8_t* rdram, recomp_context* ctx) { sprintf(filename, "controllerPak_file_%d.sav", file_no); pak.file.open(filename, std::ios::binary | std::ios::in | std::ios::out); - if (!std::filesystem::exists(filename)) { + if (!std::filesystem::exists(filename)) + { ctx->r2 = 5; // PFS_ERR_INVALID return; } - if (!pak.file.good()) { + if (!pak.file.good()) + { ctx->r2 = 5; // PFS_ERR_INVALID return; } - if (!pak.file.is_open()) { + if (!pak.file.is_open()) + { ctx->r2 = 5; // PFS_ERR_INVALID return; } - u8* swapBuffer = (u8*) malloc(size_in_bytes); - if (flag == 0) { + u8 *swapBuffer = (u8 *)malloc(size_in_bytes); + if (flag == 0) + { pak.file.seekg(offset, std::ios::beg); - pak.file.read((char*) swapBuffer, size_in_bytes); + pak.file.read((char *)swapBuffer, size_in_bytes); ByteSwapCopy(data_buffer, swapBuffer, size_in_bytes); - } else { + } + else + { ByteSwapCopy(swapBuffer, data_buffer, size_in_bytes); pak.file.seekp(offset, std::ios::beg); - pak.file.write((char*) swapBuffer, size_in_bytes); + pak.file.write((char *)swapBuffer, size_in_bytes); } free(swapBuffer); @@ -352,25 +399,29 @@ extern "C" void osPfsReadWriteFile_recomp(uint8_t* rdram, recomp_context* ctx) { ctx->r2 = 0; // PFS_NO_ERROR } -extern "C" void osPfsChecker_recomp(uint8_t* rdram, recomp_context* ctx) { +extern "C" void osPfsChecker_recomp(uint8_t *rdram, recomp_context *ctx) +{ ctx->r2 = 0; // PFS_NO_ERROR } -extern "C" void osPfsNumFiles_recomp(uint8_t* rdram, recomp_context* ctx) { - s32* max_files = _arg<1, s32*>(rdram, ctx); - s32* files_used = _arg<2, s32*>(rdram, ctx); +extern "C" void osPfsNumFiles_recomp(uint8_t *rdram, recomp_context *ctx) +{ + s32 *max_files = _arg<1, s32 *>(rdram, ctx); + s32 *files_used = _arg<2, s32 *>(rdram, ctx); u8 files = 0; - for (size_t i = 0; i < MAX_FILES; i++) { + for (size_t i = 0; i < MAX_FILES; i++) + { u32 file_size = 0; u32 game_code = 0; u16 company_code = 0; - char ext_name[4] = { 0 }; - char game_name[16] = { 0 }; + char ext_name[4] = {0}; + char game_name[16] = {0}; Pfs_PakHeader_Read(&file_size, &game_code, &company_code, ext_name, game_name, i); - if ((company_code != 0) || (game_code != 0)) { + if ((company_code != 0) || (game_code != 0)) + { files++; } } @@ -381,52 +432,61 @@ extern "C" void osPfsNumFiles_recomp(uint8_t* rdram, recomp_context* ctx) { ctx->r2 = 0; // PFS_NO_ERROR } -extern "C" void osPfsDeleteFile_recomp(uint8_t* rdram, recomp_context* ctx) { +extern "C" void osPfsDeleteFile_recomp(uint8_t *rdram, recomp_context *ctx) +{ u16 company_code = _arg<1, u16>(rdram, ctx); u32 game_code = _arg<2, u32>(rdram, ctx); - u8* game_name = _arg<3, u8*>(rdram, ctx); - u8* ext_name = TO_PTR(u8, MEM_W(0x10, ctx->r29)); + u8 *game_name = _arg<3, u8 *>(rdram, ctx); + u8 *ext_name = TO_PTR(u8, MEM_W(0x10, ctx->r29)); - if (company_code == 0 || game_code == 0) { + if (company_code == 0 || game_code == 0) + { ctx->r2 = 5; // PFS_ERR_INVALID return; } ControllerPak pak; - for (int i = 0; i < MAX_FILES; i++) { + for (int i = 0; i < MAX_FILES; i++) + { u32 file_size_ = 0; u32 game_code_ = 0; u16 company_code_ = 0; - char ext_name_[4] = { 0 }; - char game_name_[16] = { 0 }; + char ext_name_[4] = {0}; + char game_name_[16] = {0}; Pfs_PakHeader_Read(&file_size_, &game_code_, &company_code_, ext_name_, game_name_, i); - if ((company_code_ == 0) || (game_code_ == 0)) { + if ((company_code_ == 0) || (game_code_ == 0)) + { continue; - } else { + } + else + { if ((game_code == game_code_) && (company_code == company_code_) && - (strcmp((const char*) game_name, (const char*) game_name_) == 0) && - strcmp((const char*) ext_name, (const char*) ext_name_) == 0) { + (strcmp((const char *)game_name, (const char *)game_name_) == 0) && + strcmp((const char *)ext_name, (const char *)ext_name_) == 0) + { // File found pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out); - if (!pak.header.good()) { + if (!pak.header.good()) + { assert(false); } - if (!pak.header.is_open()) { + if (!pak.header.is_open()) + { assert(false); } u32 seek = i * sizeof(OSPfsState); // Zero out the header for this file. - u8* zero_block = (u8*) malloc(sizeof(OSPfsState)); + u8 *zero_block = (u8 *)malloc(sizeof(OSPfsState)); memset(zero_block, 0, sizeof(OSPfsState)); pak.header.seekp(seek + 0x0, std::ios::beg); - pak.header.write((char*) zero_block, sizeof(OSPfsState)); + pak.header.write((char *)zero_block, sizeof(OSPfsState)); free(zero_block); pak.header.close(); @@ -446,6 +506,7 @@ extern "C" void osPfsDeleteFile_recomp(uint8_t* rdram, recomp_context* ctx) { return; } -extern "C" void osPfsRepairId_recomp(uint8_t* rdram, recomp_context* ctx) { +extern "C" void osPfsRepairId_recomp(uint8_t *rdram, recomp_context *ctx) +{ _return(ctx, 0); // PFS_NO_ERROR }