From 20d277205620e2bd30b86639b255f8d110a1fcb8 Mon Sep 17 00:00:00 2001 From: d0k3 Date: Fri, 17 Nov 2017 02:48:01 +0100 Subject: [PATCH] DSiWare Export -> TAD --- arm9/source/filesys/filetype.c | 6 +-- arm9/source/filesys/sddata.c | 18 +++---- arm9/source/game/dsiwareexp.c | 24 --------- arm9/source/game/game.h | 2 +- arm9/source/game/tad.c | 24 +++++++++ arm9/source/game/{dsiwareexp.h => tad.h} | 30 +++++------ arm9/source/utils/gameutil.c | 2 +- arm9/source/virtual/vgame.c | 69 ++++++++++++------------ 8 files changed, 88 insertions(+), 87 deletions(-) delete mode 100644 arm9/source/game/dsiwareexp.c create mode 100644 arm9/source/game/tad.c rename arm9/source/game/{dsiwareexp.h => tad.h} (54%) diff --git a/arm9/source/filesys/filetype.c b/arm9/source/filesys/filetype.c index 45a4058..d5c90b9 100644 --- a/arm9/source/filesys/filetype.c +++ b/arm9/source/filesys/filetype.c @@ -129,9 +129,9 @@ u64 IdentifyFileType(const char* path) { return type; } else if ((strncmp(path + 2, "/Nintendo DSiWare/", 18) == 0) && (sscanf(fname, "%08lx.bin", &id) == 1) && (strncasecmp(ext, "bin", 4) == 0)) { - DsiWareExpHeader hdr; - if ((FileGetData(path, &hdr, DSIWEXP_HEADER_LEN, DSIWEXP_HEADER_OFFSET) == DSIWEXP_HEADER_LEN) && - (strncmp(hdr.magic, DSIWEXP_HEADER_MAGIC, strlen(DSIWEXP_HEADER_MAGIC)) == 0)) + TadHeader hdr; + if ((FileGetData(path, &hdr, TAD_HEADER_LEN, TAD_HEADER_OFFSET) == TAD_HEADER_LEN) && + (strncmp(hdr.magic, TAD_HEADER_MAGIC, strlen(TAD_HEADER_MAGIC)) == 0)) return GAME_TAD; } else if ((strnlen(fname, 16) == 8) && (sscanf(fname, "%08lx", &id) == 1)) { char path_cdn[256]; diff --git a/arm9/source/filesys/sddata.c b/arm9/source/filesys/sddata.c index f4cd370..c8aea7d 100644 --- a/arm9/source/filesys/sddata.c +++ b/arm9/source/filesys/sddata.c @@ -1,5 +1,5 @@ #include "sddata.h" -#include "dsiwareexp.h" +#include "tad.h" #include "aes.h" #include "sha.h" @@ -56,26 +56,26 @@ FilCryptInfo* fx_find_cryptinfo(FIL* fptr) { FRESULT fx_decrypt_dsiware (FIL* fp, void* buff, FSIZE_t ofs, UINT len) { const u32 mode = AES_CNT_TITLEKEY_DECRYPT_MODE; - const u32 num_tbl = sizeof(DsiWareExpContentTable) / sizeof(u32); + const u32 num_tbl = sizeof(TadContentTable) / sizeof(u32); const FSIZE_t ofs0 = f_tell(fp); u8 __attribute__((aligned(16))) iv[AES_BLOCK_SIZE]; u32 tbl[num_tbl]; - u8 hdr[DSIWEXP_HEADER_LEN]; + u8 hdr[TAD_HEADER_LEN]; FRESULT res; UINT br; // read and decrypt header - if ((res = f_lseek(fp, DSIWEXP_HEADER_OFFSET)) != FR_OK) return res; - if ((res = f_read(fp, hdr, DSIWEXP_HEADER_LEN, &br)) != FR_OK) return res; - if (br != DSIWEXP_HEADER_LEN) return FR_DENIED; - memcpy(iv, hdr + DSIWEXP_HEADER_LEN - AES_BLOCK_SIZE, AES_BLOCK_SIZE); - cbc_decrypt(hdr, hdr, sizeof(DsiWareExpHeader) / AES_BLOCK_SIZE, mode, iv); + if ((res = f_lseek(fp, TAD_HEADER_OFFSET)) != FR_OK) return res; + if ((res = f_read(fp, hdr, TAD_HEADER_LEN, &br)) != FR_OK) return res; + if (br != TAD_HEADER_LEN) return FR_DENIED; + memcpy(iv, hdr + TAD_HEADER_LEN - AES_BLOCK_SIZE, AES_BLOCK_SIZE); + cbc_decrypt(hdr, hdr, sizeof(TadHeader) / AES_BLOCK_SIZE, mode, iv); // setup the table - if (BuildDsiWareExportContentTable(tbl, hdr) != 0) return FR_DENIED; + if (BuildTadContentTable(tbl, hdr) != 0) return FR_DENIED; if (tbl[num_tbl-1] > f_size(fp)) return FR_DENIED; // obviously missing data diff --git a/arm9/source/game/dsiwareexp.c b/arm9/source/game/dsiwareexp.c deleted file mode 100644 index 71f9117..0000000 --- a/arm9/source/game/dsiwareexp.c +++ /dev/null @@ -1,24 +0,0 @@ -#include "dsiwareexp.h" - - -u32 BuildDsiWareExportContentTable(void* table, void* header) { - DsiWareExpHeader* hdr = (DsiWareExpHeader*) header; - DsiWareExpContentTable* tbl = (DsiWareExpContentTable*) table; - - if (strncmp(hdr->magic, DSIWEXP_HEADER_MAGIC, strlen(DSIWEXP_HEADER_MAGIC)) != 0) - return 1; - - tbl->banner_end = 0 + sizeof(DsiWareExpBanner) + sizeof(DsiWareExpBlockMetaData); - tbl->header_end = tbl->banner_end + sizeof(DsiWareExpHeader) + sizeof(DsiWareExpBlockMetaData); - tbl->footer_end = tbl->header_end + sizeof(DsiWareExpFooter) + sizeof(DsiWareExpBlockMetaData); - - u32 content_end_last = tbl->footer_end; - for (u32 i = 0; i < DSIWEXP_NUM_CONTENT; i++) { - tbl->content_end[i] = content_end_last; - if (!hdr->content_size[i]) continue; // non-existant section - tbl->content_end[i] += align(hdr->content_size[i], 0x10) + sizeof(DsiWareExpBlockMetaData); - content_end_last = tbl->content_end[i]; - } - - return 0; -} diff --git a/arm9/source/game/game.h b/arm9/source/game/game.h index 8130b36..c45b3d3 100644 --- a/arm9/source/game/game.h +++ b/arm9/source/game/game.h @@ -11,6 +11,6 @@ #include "codelzss.h" #include "nds.h" #include "gba.h" -#include "dsiwareexp.h" +#include "tad.h" #include "3dsx.h" #include "ncchinfo.h" diff --git a/arm9/source/game/tad.c b/arm9/source/game/tad.c new file mode 100644 index 0000000..927b345 --- /dev/null +++ b/arm9/source/game/tad.c @@ -0,0 +1,24 @@ +#include "tad.h" + + +u32 BuildTadContentTable(void* table, void* header) { + TadHeader* hdr = (TadHeader*) header; + TadContentTable* tbl = (TadContentTable*) table; + + if (strncmp(hdr->magic, TAD_HEADER_MAGIC, strlen(TAD_HEADER_MAGIC)) != 0) + return 1; + + tbl->banner_end = 0 + sizeof(TadBanner) + sizeof(TadBlockMetaData); + tbl->header_end = tbl->banner_end + sizeof(TadHeader) + sizeof(TadBlockMetaData); + tbl->footer_end = tbl->header_end + sizeof(TadFooter) + sizeof(TadBlockMetaData); + + u32 content_end_last = tbl->footer_end; + for (u32 i = 0; i < TAD_NUM_CONTENT; i++) { + tbl->content_end[i] = content_end_last; + if (!hdr->content_size[i]) continue; // non-existant section + tbl->content_end[i] += align(hdr->content_size[i], 0x10) + sizeof(TadBlockMetaData); + content_end_last = tbl->content_end[i]; + } + + return 0; +} diff --git a/arm9/source/game/dsiwareexp.h b/arm9/source/game/tad.h similarity index 54% rename from arm9/source/game/dsiwareexp.h rename to arm9/source/game/tad.h index bd74f7f..db1fde2 100644 --- a/arm9/source/game/dsiwareexp.h +++ b/arm9/source/game/tad.h @@ -3,32 +3,32 @@ #include "common.h" #include "nds.h" -#define DSIWEXP_NUM_CONTENT 11 -#define DSIWEXP_HEADER_MAGIC "3FDT" -#define DSIWEXP_BANNER_OFFSET 0 -#define DSIWEXP_BANNER_LEN (sizeof(DsiWareExpBanner) + sizeof(DsiWareExpBlockMetaData)) -#define DSIWEXP_HEADER_OFFSET (DSIWEXP_BANNER_OFFSET + DSIWEXP_BANNER_LEN) -#define DSIWEXP_HEADER_LEN (sizeof(DsiWareExpHeader) + sizeof(DsiWareExpBlockMetaData)) +#define TAD_NUM_CONTENT 11 +#define TAD_HEADER_MAGIC "3FDT" +#define TAD_BANNER_OFFSET 0 +#define TAD_BANNER_LEN (sizeof(TadBanner) + sizeof(TadBlockMetaData)) +#define TAD_HEADER_OFFSET (TAD_BANNER_OFFSET + TAD_BANNER_LEN) +#define TAD_HEADER_LEN (sizeof(TadHeader) + sizeof(TadBlockMetaData)) typedef struct { u32 banner_end; u32 header_end; u32 footer_end; - u32 content_end[DSIWEXP_NUM_CONTENT]; -} __attribute__((packed)) DsiWareExpContentTable; + u32 content_end[TAD_NUM_CONTENT]; +} __attribute__((packed)) TadContentTable; // see: https://www.3dbrew.org/wiki/DSiWare_Exports#Block_Metadata typedef struct { u8 cmac[16]; u8 iv0[16]; -} __attribute__((packed)) DsiWareExpBlockMetaData; +} __attribute__((packed)) TadBlockMetaData; // see: https://www.3dbrew.org/wiki/DSiWare_Exports#File_Structure_v2 typedef struct { TwlIconData icon_data; u8 unknown[0x4000 - sizeof(TwlIconData)]; -} __attribute__((packed)) DsiWareExpBanner; +} __attribute__((packed)) TadBanner; // see: https://www.3dbrew.org/wiki/DSiWare_Exports#Header_2 typedef struct { @@ -39,21 +39,21 @@ typedef struct { u8 cbc_test_block[0x10]; u64 title_id; u64 unknown0; - u32 content_size[DSIWEXP_NUM_CONTENT]; + u32 content_size[TAD_NUM_CONTENT]; u8 unknown1[0x30]; u8 tmd_reserved[0x3E]; u8 padding[0x0E]; -} __attribute__((packed)) DsiWareExpHeader; +} __attribute__((packed)) TadHeader; // see: https://www.3dbrew.org/wiki/DSiWare_Exports#Footer typedef struct { u8 banner_sha256[0x20]; u8 header_sha256[0x20]; - u8 content_sha256[DSIWEXP_NUM_CONTENT][0x20]; + u8 content_sha256[TAD_NUM_CONTENT][0x20]; u8 ecdsa_signature[0x3C]; u8 ecdsa_apcert[0x180]; u8 ecdsa_ctcert[0x180]; u8 padding[0x4]; -} __attribute__((packed)) DsiWareExpFooter; +} __attribute__((packed)) TadFooter; -u32 BuildDsiWareExportContentTable(void* table, void* header); +u32 BuildTadContentTable(void* table, void* header); diff --git a/arm9/source/utils/gameutil.c b/arm9/source/utils/gameutil.c index dd9376f..9d2ddb5 100644 --- a/arm9/source/utils/gameutil.c +++ b/arm9/source/utils/gameutil.c @@ -1548,7 +1548,7 @@ u32 ShowGameFileTitleInfo(const char* path) { if (LoadSmdhFromGameFile(path, smdh) == 0) return ShowSmdhTitleInfo(smdh); else if ((LoadTwlMetaData(path, NULL, twl_icon) == 0) || - ((itype & GAME_TAD) && (fvx_qread(path, twl_icon, DSIWEXP_BANNER_OFFSET, sizeof(TwlIconData), NULL) == FR_OK))) + ((itype & GAME_TAD) && (fvx_qread(path, twl_icon, TAD_BANNER_OFFSET, sizeof(TwlIconData), NULL) == FR_OK))) return ShowTwlIconTitleInfo(twl_icon); else return ShowGbaFileTitleInfo(path); } diff --git a/arm9/source/virtual/vgame.c b/arm9/source/virtual/vgame.c index d0a2779..5cfe94e 100644 --- a/arm9/source/virtual/vgame.c +++ b/arm9/source/virtual/vgame.c @@ -4,7 +4,7 @@ #include "aes.h" #define VFLAG_NO_CRYPTO (1UL<<18) -#define VFLAG_DSIWARE (1UL<<19) +#define VFLAG_TAD (1UL<<19) #define VFLAG_CIA_CONTENT (1UL<<20) #define VFLAG_NDS (1UL<<21) #define VFLAG_NITRO_DIR (1UL<<22) @@ -17,7 +17,7 @@ #define VFLAG_NCCH (1UL<<29) #define VFLAG_EXEFS (1UL<<30) #define VFLAG_ROMFS (1UL<<31) -#define VFLAG_GAMEDIR (VFLAG_FIRM|VFLAG_CIA|VFLAG_NCSD|VFLAG_NCCH|VFLAG_EXEFS|VFLAG_ROMFS|VFLAG_LV3|VFLAG_NDS|VFLAG_NITRO_DIR|VFLAG_NITRO|VFLAG_DSIWARE) +#define VFLAG_GAMEDIR (VFLAG_FIRM|VFLAG_CIA|VFLAG_NCSD|VFLAG_NCCH|VFLAG_EXEFS|VFLAG_ROMFS|VFLAG_LV3|VFLAG_NDS|VFLAG_NITRO_DIR|VFLAG_NITRO|VFLAG_TAD) #define VFLAG_NCCH_CRYPTO (VFLAG_EXEFS_FILE|VFLAG_EXTHDR|VFLAG_EXEFS|VFLAG_ROMFS|VFLAG_LV3|VFLAG_NCCH) #define NAME_FIRM_HEADER "header.bin" @@ -61,28 +61,28 @@ #define NAME_NDS_BANNER "banner.bin" #define NAME_NDS_DATADIR "data" -#define NAME_DSIWE_BANNER "banner.bin" -#define NAME_DSIWE_HEADER "header.bin" -#define NAME_DSIWE_FOOTER "footer.bin" -#define NAME_DSIWE_TYPES "tmd", "srl", "02.unk", \ +#define NAME_TAD_BANNER "banner.bin" +#define NAME_TAD_HEADER "header.bin" +#define NAME_TAD_FOOTER "footer.bin" +#define NAME_TAD_TYPES "tmd", "srl", "02.unk", \ "03.unk", "04.unk", "05.unk", \ "06.unk", "07.unk", "08.unk", \ "public.sav", "banner.sav", "11.unk" -#define NAME_DSIWE_CONTENT "%016llX.%s" // titleid.type +#define NAME_TAD_CONTENT "%016llX.%s" // titleid.type static u64 vgame_type = 0; static u32 base_vdir = 0; static VirtualFile* templates_cia = (VirtualFile*) VGAME_BUFFER; // first 56kb reserved (enough for 1024 entries) -static VirtualFile* templates_dsiwe = (VirtualFile*) (VGAME_BUFFER + 0xDC00); // 1kb reserved (enough for 18 entries) +static VirtualFile* templates_tad = (VirtualFile*) (VGAME_BUFFER + 0xDC00); // 1kb reserved (enough for 18 entries) static VirtualFile* templates_firm = (VirtualFile*) (VGAME_BUFFER + 0xE000); // 2kb reserved (enough for 36 entries) static VirtualFile* templates_ncsd = (VirtualFile*) (VGAME_BUFFER + 0xE800); // 2kb reserved (enough for 36 entries) static VirtualFile* templates_ncch = (VirtualFile*) (VGAME_BUFFER + 0xF000); // 1kb reserved (enough for 18 entries) static VirtualFile* templates_nds = (VirtualFile*) (VGAME_BUFFER + 0xF400); // 1kb reserved (enough for 18 entries) static VirtualFile* templates_exefs = (VirtualFile*) (VGAME_BUFFER + 0xF800); // 2kb reserved (enough for 36 entries) static int n_templates_cia = -1; -static int n_templates_dsiwe = -1; +static int n_templates_tad = -1; static int n_templates_firm = -1; static int n_templates_ncsd = -1; static int n_templates_ncch = -1; @@ -101,7 +101,7 @@ static u64 offset_lv3fd = (u64) -1; static u64 offset_nds = (u64) -1; static u64 offset_nitro = (u64) -1; static u64 offset_ccnt = (u64) -1; -static u64 offset_dsiwe = (u64) -1; +static u64 offset_tad = (u64) -1; static u32 index_ccnt = (u32) -1; static CiaStub* cia = (CiaStub*) (void*) (VGAME_BUFFER + 0x10000); // 61kB reserved - should be enough by far @@ -661,53 +661,53 @@ bool BuildVGameFirmDir(void) { return true; } -bool BuildVGameDsiWareDir(void) { - const char* name_type[] = { NAME_DSIWE_TYPES }; - VirtualFile* templates = templates_dsiwe; +bool BuildVGameTadDir(void) { + const char* name_type[] = { NAME_TAD_TYPES }; + VirtualFile* templates = templates_tad; u32 content_offset = 0; u32 n = 0; // read header, setup table - DsiWareExpContentTable tbl; - DsiWareExpHeader hdr; - ReadGameImageBytes(&hdr, DSIWEXP_HEADER_OFFSET, DSIWEXP_HEADER_LEN); - if (BuildDsiWareExportContentTable(&tbl, &hdr) != 0) { - n_templates_dsiwe = 0; + TadContentTable tbl; + TadHeader hdr; + ReadGameImageBytes(&hdr, TAD_HEADER_OFFSET, TAD_HEADER_LEN); + if (BuildTadContentTable(&tbl, &hdr) != 0) { + n_templates_tad = 0; return false; } // banner - strncpy(templates[n].name, NAME_DSIWE_BANNER, 32); + strncpy(templates[n].name, NAME_TAD_BANNER, 32); templates[n].offset = content_offset; - templates[n].size = tbl.banner_end - content_offset - sizeof(DsiWareExpBlockMetaData); + templates[n].size = tbl.banner_end - content_offset - sizeof(TadBlockMetaData); templates[n].keyslot = 0xFF; templates[n].flags = 0; content_offset = tbl.banner_end; n++; // header - strncpy(templates[n].name, NAME_DSIWE_HEADER, 32); + strncpy(templates[n].name, NAME_TAD_HEADER, 32); templates[n].offset = content_offset; - templates[n].size = tbl.header_end - content_offset - sizeof(DsiWareExpBlockMetaData); + templates[n].size = tbl.header_end - content_offset - sizeof(TadBlockMetaData); templates[n].keyslot = 0xFF; templates[n].flags = 0; content_offset = tbl.header_end; n++; // footer - strncpy(templates[n].name, NAME_DSIWE_FOOTER, 32); + strncpy(templates[n].name, NAME_TAD_FOOTER, 32); templates[n].offset = content_offset; - templates[n].size = tbl.footer_end - content_offset - sizeof(DsiWareExpBlockMetaData); + templates[n].size = tbl.footer_end - content_offset - sizeof(TadBlockMetaData); templates[n].keyslot = 0xFF; templates[n].flags = 0; content_offset = tbl.footer_end; n++; // contents - for (u32 i = 0; i < DSIWEXP_NUM_CONTENT; content_offset = tbl.content_end[i++]) { + for (u32 i = 0; i < TAD_NUM_CONTENT; content_offset = tbl.content_end[i++]) { if (!hdr.content_size[i]) continue; // nothing in section // use proper names, fix TMD handling - snprintf(templates[n].name, 32, NAME_DSIWE_CONTENT, hdr.title_id, name_type[i]); + snprintf(templates[n].name, 32, NAME_TAD_CONTENT, hdr.title_id, name_type[i]); templates[n].offset = content_offset; templates[n].size = hdr.content_size[i]; templates[n].keyslot = 0xFF; @@ -715,7 +715,7 @@ bool BuildVGameDsiWareDir(void) { n++; } - n_templates_dsiwe = n; + n_templates_tad = n; return true; } @@ -734,6 +734,7 @@ u64 InitVGameDrive(void) { // prerequisite: game file mounted as image offset_lv3fd = (u64) -1; offset_nds = (u64) -1; offset_nitro = (u64) -1; + offset_tad = (u64) -1; base_vdir = (type & SYS_FIRM ) ? VFLAG_FIRM : @@ -743,7 +744,7 @@ u64 InitVGameDrive(void) { // prerequisite: game file mounted as image (type & GAME_EXEFS) ? VFLAG_EXEFS : (type & GAME_ROMFS) ? VFLAG_ROMFS : (type & GAME_NDS ) ? VFLAG_NDS : - (type & GAME_TAD ) ? VFLAG_DSIWARE : 0; + (type & GAME_TAD ) ? VFLAG_TAD : 0; if (!base_vdir) return 0; vgame_type = type; @@ -790,9 +791,9 @@ bool OpenVGameDir(VirtualDir* vdir, VirtualFile* ventry) { ((SetupArm9BinaryCrypto(a9l)) == 0)) offset_a9bin = arm9s->offset + ARM9BIN_OFFSET; if (!BuildVGameFirmDir()) return false; - } else if ((vdir->flags & VFLAG_DSIWARE) && (offset_dsiwe != vdir->offset)) { - offset_dsiwe = vdir->offset; // always zero(!) - if (!BuildVGameDsiWareDir()) return false; + } else if ((vdir->flags & VFLAG_TAD) && (offset_tad != vdir->offset)) { + offset_tad = vdir->offset; // always zero(!) + if (!BuildVGameTadDir()) return false; } else if ((vdir->flags & VFLAG_CIA) && (offset_cia != vdir->offset)) { CiaInfo info; if ((ReadImageBytes((u8*) cia, 0, 0x20) != 0) || @@ -1018,9 +1019,9 @@ bool ReadVGameDir(VirtualFile* vfile, VirtualDir* vdir) { } else if (vdir->flags & VFLAG_NDS) { templates = templates_nds; n = n_templates_nds; - } else if (vdir->flags & VFLAG_DSIWARE) { - templates = templates_dsiwe; - n = n_templates_dsiwe; + } else if (vdir->flags & VFLAG_TAD) { + templates = templates_tad; + n = n_templates_tad; } else if (vdir->flags & VFLAG_LV3) { return ReadVGameDirLv3(vfile, vdir); } else if (vdir->flags & VFLAG_NITRO) {