diff --git a/src/asset/asset.c b/src/asset/asset.c index a7a6358..b381954 100644 --- a/src/asset/asset.c +++ b/src/asset/asset.c @@ -10,13 +10,136 @@ #include "util/string.h" #include "assert/assert.h" #include "asset/assettype.h" +#include "engine/engine.h" errorret_t assetInit(void) { memoryZero(&ASSET, sizeof(asset_t)); + + // Engine may have been provided the launch path + if(ENGINE.argc > 0) { + // This first arg is the executable, so on most platforms it is say + // "/path/file" or "C:\Path\file.exe". On PSP this would be something + // like "ms0:/PSP/GAME/DUSK/EBOOT.PBP" or if we are debugging it is + // "host0:/Dusk.prx" + + // Get the directory of the executable + char_t buffer[FILENAME_MAX]; + stringCopy(buffer, ENGINE.argv[0], FILENAME_MAX); + size_t len = strlen(buffer); + + // Normalize slashes + for(size_t i = 0; i < FILENAME_MAX; i++) { + if(buffer[i] == '\0') break; + if(buffer[i] == '\\') buffer[i] = '/'; + } + + // Now find the last slash + char_t *end = buffer + len - 1; + do { + end--; + if(*end == '/') { + *end = '\0'; + break; + } + } while(end != buffer); + + + // Did we find a slash? + if(end != buffer) { + // We found the directory, set as system path + stringCopy(ASSET.systemPath, buffer, FILENAME_MAX); + } + } // Default system path, intended to be overridden by the platform stringCopy(ASSET.systemPath, ".", FILENAME_MAX); + // PSP specific time. + #if PSP + assertTrue(ENGINE.argc >= 1, "PSP requires launch argument."); + + // PSP is given either host0:/Dusk.prx (debugging) OR the PBP file. + if(stringEndsWith(ENGINE.argv[0], ".pbp") || ASSET_PBP_READ_PBP_FROM_HOST) { + const char_t *pbpPath = ( + ASSET_PBP_READ_PBP_FROM_HOST ? "./EBOOT.PBP" : ENGINE.argv[0] + ); + ASSET.pbpFile = fopen(pbpPath, "rb"); + if(ASSET.pbpFile == NULL) { + errorThrow("Failed to open PBP file: %s", pbpPath); + } + + // Get size of PBP file. + if(fseek(ASSET.pbpFile, 0, SEEK_END) != 0) { + fclose(ASSET.pbpFile); + errorThrow("Failed to seek to end of PBP file : %s", pbpPath); + } + size_t pbpSize = ftell(ASSET.pbpFile); + + // Rewind to start + if(fseek(ASSET.pbpFile, 0, SEEK_SET) != 0) { + fclose(ASSET.pbpFile); + errorThrow("Failed to seek to start of PBP file : %s", pbpPath); + } + + // Read the PBP header + size_t read = fread( + &ASSET.pbpHeader, + 1, + sizeof(assetpbp_t), + ASSET.pbpFile + ); + if(read != sizeof(assetpbp_t)) { + fclose(ASSET.pbpFile); + errorThrow("Failed to read PBP header", pbpPath); + } + + if(memoryCompare( + ASSET.pbpHeader.signature, + ASSET_PBP_SIGNATURE, + sizeof(ASSET_PBP_SIGNATURE) + ) != 0) { + fclose(ASSET.pbpFile); + errorThrow("Invalid PBP signature in file: %s", pbpPath); + } + + // If we seek to the PSAR offset, we can read the WAD file from there + if(fseek(ASSET.pbpFile, ASSET.pbpHeader.psarOffset, SEEK_SET) != 0) { + fclose(ASSET.pbpFile); + errorThrow("Failed to seek to PSAR offset in PBP file: %s", pbpPath); + } + + zip_uint64_t zipPsarOffset = (zip_uint64_t)ASSET.pbpHeader.psarOffset; + zip_int64_t zipPsarSize = (zip_int64_t)( + pbpSize - ASSET.pbpHeader.psarOffset + ); + + zip_source_t *psarSource = zip_source_filep_create( + ASSET.pbpFile, + zipPsarOffset, + zipPsarSize, + NULL + ); + if(psarSource == NULL) { + fclose(ASSET.pbpFile); + errorThrow("Failed to create zip source in PBP file: %s", pbpPath); + } + + ASSET.zip = zip_open_from_source( + psarSource, + ZIP_RDONLY, + NULL + ); + if(ASSET.zip == NULL) { + zip_source_free(psarSource); + fclose(ASSET.pbpFile); + errorThrow("Failed to open zip from PBP file: %s", pbpPath); + } + + errorOk(); + } + #endif + + // Open zip file char_t searchPath[FILENAME_MAX]; const char_t **path = ASSET_SEARCH_PATHS; @@ -29,6 +152,7 @@ errorret_t assetInit(void) { ); // Try open + printf("Trying to open asset at: %s\n", searchPath); ASSET.zip = zip_open(searchPath, ZIP_RDONLY, NULL); if(ASSET.zip == NULL) continue; break;// Found! @@ -125,4 +249,11 @@ void assetDispose(void) { zip_close(ASSET.zip); ASSET.zip = NULL; } + + #if PSP + if(ASSET.pbpFile != NULL) { + fclose(ASSET.pbpFile); + ASSET.pbpFile = NULL; + } + #endif } \ No newline at end of file diff --git a/src/asset/asset.h b/src/asset/asset.h index 7b760d2..63d18ab 100644 --- a/src/asset/asset.h +++ b/src/asset/asset.h @@ -11,10 +11,21 @@ #if ASSET_TYPE == wad #if PSP + #define ASSET_PBP_READ_PBP_FROM_HOST 0 + #define ASSET_PBP_SIGNATURE_LEN 4 + #define ASSET_PBP_SIGNATURE "\0PBP" + typedef struct { - uint8_t signature[4]; - uint16_t version[2]; - unsigned int offset[8]; + char_t signature[ASSET_PBP_SIGNATURE_LEN]; + uint32_t version; + uint32_t sfoOffset; + uint32_t icon0Offset; + uint32_t icon1Offset; + uint32_t pic0Offset; + uint32_t pic1Offset; + uint32_t snd0Offset; + uint32_t pspOffset; + uint32_t psarOffset; } assetpbp_t; #endif #else @@ -44,6 +55,11 @@ typedef struct { zip_t *zip; char_t systemPath[FILENAME_MAX]; uint8_t assetCount; + + #if PSP + FILE *pbpFile; + assetpbp_t pbpHeader; + #endif } asset_t; static asset_t ASSET; diff --git a/src/engine/engine.c b/src/engine/engine.c index 6df9bf2..3aa60ec 100644 --- a/src/engine/engine.c +++ b/src/engine/engine.c @@ -18,9 +18,11 @@ engine_t ENGINE; -errorret_t engineInit(void) { +errorret_t engineInit(const int32_t argc, const char_t **argv) { memoryZero(&ENGINE, sizeof(engine_t)); ENGINE.running = true; + ENGINE.argc = argc; + ENGINE.argv = argv; // Init systems. Order is important. timeInit(); diff --git a/src/engine/engine.h b/src/engine/engine.h index 42db298..b75d350 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -11,14 +11,19 @@ typedef struct { bool_t running; + int32_t argc; + const char_t **argv; } engine_t; extern engine_t ENGINE; /** * Initializes the engine. + * + * @param argc The argument count from main(). + * @param argv The argument vector from main(). */ -errorret_t engineInit(void); +errorret_t engineInit(const int32_t argc, const char_t **argv); /** * Updates the engine. diff --git a/src/main.c b/src/main.c index 2d463cd..d62883d 100644 --- a/src/main.c +++ b/src/main.c @@ -11,28 +11,14 @@ #include "input/input.h" int main(int argc, char **argv) { - // Write out launch args - printf("Launching Dusk with %d args:\n", argc); - for(int i = 0; i < argc; i++) { - printf(" Arg %d: %s\n", i, argv[i]); - } - errorret_t ret; // Init engine - ret = engineInit(); + ret = engineInit(argc, (const char_t **)argv); if(ret.code != ERROR_OK) { errorCatch(errorPrint(ret)); return ret.code; } - - // Setup system path on asset manager - if(argc > 0) { - stringCopy( - ASSET.systemPath, argv[0], - sizeof(ASSET.systemPath) / sizeof(char_t) - ); - } // Begin main loop do {