diff --git a/source/godmode.c b/source/godmode.c index d41f457..22b1ed0 100644 --- a/source/godmode.c +++ b/source/godmode.c @@ -1186,7 +1186,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur return 0; } else if (user_select == extrcode) { // -> Extract code ShowString("%s\nExtracting .code, please wait...", pathstr); - if (ExtractCodeFromCxiFile(curr_entry->path) == 0) { + if (ExtractCodeFromCxiFile(curr_entry->path, NULL) == 0) { ShowPrompt(false, "%s\n.code extracted to " OUTPUT_PATH, pathstr); } else ShowPrompt(false, "%s\n.code extract failed", pathstr); return 0; diff --git a/source/utils/gameutil.c b/source/utils/gameutil.c index e6684a2..c9e4c9f 100644 --- a/source/utils/gameutil.c +++ b/source/utils/gameutil.c @@ -1402,7 +1402,7 @@ u32 DumpCxiSrlFromTmdFile(const char* path) { return 0; } -u32 ExtractCodeFromCxiFile(const char* path) { +u32 ExtractCodeFromCxiFile(const char* path, const char* path_out) { u8* code = (u8*) TEMP_BUFFER; u32 code_max_size = TEMP_BUFFER_SIZE; @@ -1419,9 +1419,13 @@ u32 ExtractCodeFromCxiFile(const char* path) { if ((exthdr.flag & 0x1) && (DecompressCodeLzss(code, &code_size, code_max_size) != 0)) return 1; - // build output path + // build or take over output path char dest[256]; - snprintf(dest, 256, OUTPUT_PATH "/%016llX%s%s", ncch.programId, (exthdr.flag & 0x1) ? ".dec" : "", EXEFS_CODE_NAME); + if (!path_out) { + // ensure the output dir exists + if (fvx_rmkdir(OUTPUT_PATH) != FR_OK) return 1; + snprintf(dest, 256, OUTPUT_PATH "/%016llX%s%s", ncch.programId, (exthdr.flag & 0x1) ? ".dec" : "", EXEFS_CODE_NAME); + } else strncpy(dest, path_out, 256); // write output file fvx_unlink(dest); diff --git a/source/utils/gameutil.h b/source/utils/gameutil.h index 47232a2..a5c8b7d 100644 --- a/source/utils/gameutil.h +++ b/source/utils/gameutil.h @@ -7,7 +7,7 @@ u32 CheckEncryptedGameFile(const char* path); u32 CryptGameFile(const char* path, bool inplace, bool encrypt); u32 BuildCiaFromGameFile(const char* path, bool force_legit); u32 DumpCxiSrlFromTmdFile(const char* path); -u32 ExtractCodeFromCxiFile(const char* path); +u32 ExtractCodeFromCxiFile(const char* path, const char* path_out); u32 ShowGameFileTitleInfo(const char* path); u32 BuildNcchInfoXorpads(const char* destdir, const char* path); u32 CheckHealthAndSafetyInject(const char* hsdrv); diff --git a/source/utils/scripting.c b/source/utils/scripting.c index c4df5b6..f719aeb 100644 --- a/source/utils/scripting.c +++ b/source/utils/scripting.c @@ -69,6 +69,7 @@ typedef enum { CMD_ID_DECRYPT, CMD_ID_ENCRYPT, CMD_ID_BUILDCIA, + CMD_ID_EXTRCODE, CMD_ID_BOOT, CMD_ID_SWITCHSD, CMD_ID_REBOOT, @@ -109,6 +110,7 @@ Gm9ScriptCmd cmd_list[] = { { CMD_ID_DECRYPT , "decrypt" , 1, 0 }, { CMD_ID_ENCRYPT , "encrypt" , 1, 0 }, { CMD_ID_BUILDCIA, "buildcia", 1, _FLG('l') }, + { CMD_ID_EXTRCODE, "extrcode", 2, 0 }, { CMD_ID_BOOT , "boot" , 1, 0 }, { CMD_ID_SWITCHSD, "switchsd", 1, 0 }, { CMD_ID_REBOOT , "reboot" , 0, 0 }, @@ -591,6 +593,16 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) { } else if (id == CMD_ID_BUILDCIA) { ret = (BuildCiaFromGameFile(argv[0], (flags & _FLG('n'))) == 0); if (err_str) snprintf(err_str, _ERR_STR_LEN, "build CIA failed"); + } else if (id == CMD_ID_EXTRCODE) { + u32 filetype = IdentifyFileType(argv[0]); + if ((filetype&(GAME_NCCH|FLAG_CXI)) != (GAME_NCCH|FLAG_CXI)) { + ret = false; + if (err_str) snprintf(err_str, _ERR_STR_LEN, "not a CXI file"); + } else { + ShowString("Extracting .code, please wait..."); + ret = (ExtractCodeFromCxiFile(argv[0], argv[1]) == 0); + if (err_str) snprintf(err_str, _ERR_STR_LEN, "extract .code failed"); + } } else if (id == CMD_ID_BOOT) { size_t firm_size = FileGetData(argv[0], TEMP_BUFFER, TEMP_BUFFER_SIZE, 0); ret = firm_size && (firm_size < TEMP_BUFFER_SIZE) &&