From d8aeb056cbfdef485b10c30ef9e8094b159e961f Mon Sep 17 00:00:00 2001 From: d0k3 Date: Fri, 24 Jul 2020 17:22:55 +0200 Subject: [PATCH] Fix CMD & NCSD handling --- arm9/source/filesys/filetype.c | 2 +- arm9/source/game/cmd.c | 68 ++++++++++++++++++++-------------- arm9/source/game/cmd.h | 10 ++--- arm9/source/game/tie.c | 2 +- arm9/source/utils/gameutil.c | 22 +++++------ arm9/source/utils/nandcmac.c | 2 +- 6 files changed, 57 insertions(+), 49 deletions(-) diff --git a/arm9/source/filesys/filetype.c b/arm9/source/filesys/filetype.c index f88b197..14c4a70 100644 --- a/arm9/source/filesys/filetype.c +++ b/arm9/source/filesys/filetype.c @@ -124,7 +124,7 @@ u64 IdentifyFileType(const char* path) { (memcmp(data, threedsx_magic, sizeof(threedsx_magic)) == 0)) { return GAME_3DSX; // 3DSX (executable) file } else if ((fsize > sizeof(CmdHeader)) && - CheckCmdSize((CmdHeader*) data, fsize) == 0) { + (CMD_SIZE((CmdHeader*) data) == fsize)) { return GAME_CMD; // CMD file } else if ((fsize > sizeof(NcchInfoHeader)) && (GetNcchInfoVersion((NcchInfoHeader*) data)) && diff --git a/arm9/source/game/cmd.c b/arm9/source/game/cmd.c index 34c3fc8..24048a2 100644 --- a/arm9/source/game/cmd.c +++ b/arm9/source/game/cmd.c @@ -1,50 +1,62 @@ #include "cmd.h" -u32 CheckCmdSize(CmdHeader* cmd, u64 fsize) { - u64 cmdsize = sizeof(CmdHeader) + - (cmd->n_entries * sizeof(u32)) + - (cmd->n_cmacs * sizeof(u32)) + - (cmd->n_entries * 0x10); - - return (fsize == cmdsize) ? 0 : 1; -} - -u32 BuildCmdData(CmdHeader* cmd, TitleMetaData* tmd) { +CmdHeader* BuildAllocCmdData(TitleMetaData* tmd) { + CmdHeader proto; + CmdHeader* cmd = NULL; u32 content_count = getbe16(tmd->content_count); + u32 max_cnt_id = 0; - // header basic info - cmd->cmd_id = 0x1; - cmd->n_entries = content_count; - cmd->n_cmacs = content_count; + // sanity check + if (!content_count) + return NULL; + + // find max content id + TmdContentChunk* chunk = (TmdContentChunk*) (tmd + 1); + for (u32 i = 0; (i < content_count) && (i < TMD_MAX_CONTENTS); i++, chunk++) + if (getbe32(chunk->id) > max_cnt_id) max_cnt_id = getbe32(chunk->id); + + // allocate memory for CMD / basic setup + proto.cmd_id = 1; + proto.n_entries = max_cnt_id + 1; + proto.n_cmacs = content_count; + proto.unknown = 1; + cmd = (CmdHeader*) malloc(CMD_SIZE(&proto)); + if (!cmd) return NULL; + memcpy(cmd, &proto, sizeof(CmdHeader)); cmd->unknown = 0x0; // this means no CMACs, only valid for NAND // copy content ids u32* cnt_id = (u32*) (cmd + 1); - u32* cnt_id_cpy = cnt_id + content_count; - TmdContentChunk* chunk = (TmdContentChunk*) (tmd + 1); + u32* cnt_id_2nd = cnt_id + cmd->n_entries; + chunk = (TmdContentChunk*) (tmd + 1); + memset(cnt_id, 0xFF, cmd->n_entries * sizeof(u32)); for (u32 i = 0; (i < content_count) && (i < TMD_MAX_CONTENTS); i++, chunk++) { - cnt_id[i] = getbe32(chunk->id); - cnt_id_cpy[i] = cnt_id[i]; + u32 chunk_id = getbe32(chunk->id); + cnt_id[chunk_id] = chunk_id; + *(cnt_id_2nd++) = chunk_id; } // bubble sort the second content id list - u32 b = 0; - while ((b < content_count) && (b < TMD_MAX_CONTENTS)) { - for (b = 1; (b < content_count) && (b < TMD_MAX_CONTENTS); b++) { - if (cnt_id_cpy[b] < cnt_id_cpy[b-1]) { - u32 swp = cnt_id_cpy[b]; - cnt_id_cpy[b] = cnt_id_cpy[b-1]; - cnt_id_cpy[b-1] = swp; + bool bs_finished = false; + cnt_id_2nd = cnt_id + cmd->n_entries; + while (!bs_finished) { + bs_finished = true; + for (u32 b = 1; b < cmd->n_cmacs; b++) { + if (cnt_id_2nd[b] < cnt_id_2nd[b-1]) { + u32 swp = cnt_id_2nd[b]; + cnt_id_2nd[b] = cnt_id_2nd[b-1]; + cnt_id_2nd[b-1] = swp; + bs_finished = false; } } } // set CMACs to 0xFF - u8* cnt_cmac = (u8*) (cnt_id + (2*cmd->n_entries)); + u8* cnt_cmac = (u8*) (cnt_id_2nd + cmd->n_cmacs); memset(cmd->cmac, 0xFF, 0x10); - memset(cnt_cmac, 0xFF, 0x10 * content_count); + memset(cnt_cmac, 0xFF, 0x10 * cmd->n_entries); // we still need to fix / set the CMACs inside the CMD file! - return 0; + return cmd; } diff --git a/arm9/source/game/cmd.h b/arm9/source/game/cmd.h index d425ae9..dee4f5e 100644 --- a/arm9/source/game/cmd.h +++ b/arm9/source/game/cmd.h @@ -3,9 +3,10 @@ #include "common.h" #include "tmd.h" -#define CMD_SIZE_N(n) (sizeof(CmdHeader) + ((n)*(sizeof(u32)+sizeof(u32)+0x10))) -#define CMD_SIZE_NS(n) (sizeof(CmdHeader) + ((n)*(sizeof(u32)+sizeof(u32)))) - +#define CMD_SIZE(cmd) (sizeof(CmdHeader) + \ + (((cmd)->n_entries) * sizeof(u32)) + \ + (((cmd)->n_cmacs) * sizeof(u32)) + \ + (((cmd)->unknown) ? (((cmd)->n_entries) * 0x10) : 0)) // from: http://3dbrew.org/wiki/Titles#Data_Structure typedef struct { @@ -19,5 +20,4 @@ typedef struct { // followed by CMACs (may contain garbage) } __attribute__((packed, aligned(4))) CmdHeader; -u32 CheckCmdSize(CmdHeader* cmd, u64 fsize); -u32 BuildCmdData(CmdHeader* cmd, TitleMetaData* tmd); +CmdHeader* BuildAllocCmdData(TitleMetaData* tmd); diff --git a/arm9/source/game/tie.c b/arm9/source/game/tie.c index 1d1db74..c5430ff 100644 --- a/arm9/source/game/tie.c +++ b/arm9/source/game/tie.c @@ -25,7 +25,7 @@ u32 BuildTitleInfoEntryTmd(TitleInfoEntry* tie, TitleMetaData* tmd, bool sd) { tie->title_size = (align_size * 3) + // base folder + 'content' + 'cmd' align(TMD_SIZE_N(content_count), align_size) + // TMD - align(CMD_SIZE_N(content_count), align_size); // CMD + align_size; // CMD, placeholder for (u32 i = 0; (i < content_count) && (i < TMD_MAX_CONTENTS); i++, chunk++) { if (getbe32(chunk->id) == 1) has_id1 = true; // will be useful later tie->title_size += align(getbe64(chunk->size), align_size); diff --git a/arm9/source/utils/gameutil.c b/arm9/source/utils/gameutil.c index ac55f5c..aeba53e 100644 --- a/arm9/source/utils/gameutil.c +++ b/arm9/source/utils/gameutil.c @@ -1402,10 +1402,9 @@ u32 InstallCiaSystemData(CiaStub* cia, const char* drv) { return 1; // build the cmd - cmd = (CmdHeader*) malloc(CMD_SIZE_N(content_count)); + cmd = BuildAllocCmdData(tmd); if (!cmd) return 1; - BuildCmdData(cmd, tmd); - if (!syscmd) cmd->unknown = 0xFFFFFFFE; // mark this as custom built + cmd->unknown = 0xFFFFFFFE; // mark this as custom built // generate all the paths snprintf(path_titledb, 32, "%2.2s/dbs/title.db", @@ -1423,8 +1422,7 @@ u32 InstallCiaSystemData(CiaStub* cia, const char* drv) { fvx_rmkpath(path_tmd); fvx_rmkpath(path_cmd); if ((fvx_qwrite(path_tmd, tmd, 0, TMD_SIZE_N(content_count), NULL) != FR_OK) || - (fvx_qwrite(path_cmd, cmd, 0, - syscmd ? CMD_SIZE_NS(content_count) : CMD_SIZE_N(content_count), NULL) != FR_OK)) { + (fvx_qwrite(path_cmd, cmd, 0, CMD_SIZE(cmd), NULL) != FR_OK)) { free(cmd); return 1; } @@ -1963,7 +1961,7 @@ u32 BuildInstallFromNcsdFile(const char* path_ncsd, const char* path_dest, bool if ((!install && (InsertCiaContent(path_dest, path_ncsd, offset, size, chunk++, NULL, false, (i == 0), false) != 0)) || (install && (InstallCiaContent(path_dest, path_ncsd, - offset, size, chunk, title_id, NULL, (i == 0)) != 0))) { + offset, size, chunk++, title_id, NULL, (i == 0)) != 0))) { free(cia); return 1; } @@ -2161,9 +2159,8 @@ u32 InstallGameFile(const char* path, bool to_emunand, bool force_nand) { to_sd = true; // does the title.db exist? - if (to_sd && !fvx_qsize(to_emunand ? "B:/dbs/title.db" : "A:/dbs/title.db")) - to_sd = false; - if (!to_sd && !fvx_qsize(to_emunand ? "4:/dbs/title.db" : "1:/dbs/title.db")) + if ((to_sd && !fvx_qsize(to_emunand ? "B:/dbs/title.db" : "A:/dbs/title.db")) || + (!to_sd && !fvx_qsize(to_emunand ? "4:/dbs/title.db" : "1:/dbs/title.db"))) return 1; // now we know the correct drive @@ -2401,7 +2398,7 @@ u32 TrimGameFile(const char* path) { u32 LoadSmdhFromGameFile(const char* path, Smdh* smdh) { u64 filetype = IdentifyFileType(path); - + if (filetype & GAME_SMDH) { // SMDH file UINT btr; if ((fvx_qread(path, smdh, 0, sizeof(Smdh), &btr) == FR_OK) || (btr == sizeof(Smdh))) return 0; @@ -2410,8 +2407,7 @@ u32 LoadSmdhFromGameFile(const char* path, Smdh* smdh) { } else if (filetype & GAME_NCSD) { // NCSD file if (LoadExeFsFile(smdh, path, NCSD_CNT0_OFFSET, "icon", sizeof(Smdh), NULL) == 0) return 0; } else if (filetype & GAME_CIA) { // CIA file - CiaInfo info; - + CiaInfo info; if ((fvx_qread(path, &info, 0, 0x20, NULL) != FR_OK) || (GetCiaInfo(&info, (CiaHeader*) &info) != 0)) return 1; if ((info.offset_meta) && (fvx_qread(path, smdh, info.offset_meta + 0x400, sizeof(Smdh), NULL) == FR_OK)) return 0; @@ -2479,7 +2475,7 @@ u32 ShowGameFileTitleInfoF(const char* path, u16* screen, bool clear) { if (GetTmdContentPath(path_content, path) != 0) return 1; path = path_content; } - + void* buffer = (void*) malloc(max(sizeof(Smdh), sizeof(TwlIconData))); Smdh* smdh = (Smdh*) buffer; TwlIconData* twl_icon = (TwlIconData*) buffer; diff --git a/arm9/source/utils/nandcmac.c b/arm9/source/utils/nandcmac.c index c709c5a..a0aedf8 100644 --- a/arm9/source/utils/nandcmac.c +++ b/arm9/source/utils/nandcmac.c @@ -374,7 +374,7 @@ u32 CheckFixCmdCmac(const char* path, bool fix) { // read the full file to memory and check it (we may write it back later) if ((fvx_qread(path, cmd_data, 0, cmd_size, NULL) != FR_OK) || - (CheckCmdSize(cmd, cmd_size) != 0)) { + (CMD_SIZE(cmd) != cmd_size)) { free(cmd_data); return 1; }