diff --git a/arm9/source/game/nds.h b/arm9/source/game/nds.h index c7e17a8..0931f00 100644 --- a/arm9/source/game/nds.h +++ b/arm9/source/game/nds.h @@ -102,28 +102,32 @@ typedef struct { // extended mode stuff (DSi only) u8 ignored0[0x30]; // ignored u32 region_flags; - u8 ignored1[0xC]; // ignored + u32 access_control; + u32 arm7_scfg_ext7; + u8 reserved2[3]; + u8 srl_flag; u32 arm9i_rom_offset; - u32 reserved2; + u32 reserved3; u32 arm9i_load_adress; u32 arm9i_size; u32 arm7i_rom_offset; u32 unknown1; u32 arm7i_load_adress; u32 arm7i_size; - u8 ignored2[0x30]; // ignored + u8 ignored1[0x30]; // ignored u32 ntr_twl_rom_size; u8 unknown2[12]; - u8 ignored3[0x10]; // ignored + u8 ignored2[0x10]; // ignored u64 title_id; u32 pubsav_size; u32 prvsav_size; - u8 reserved3[176]; + u8 reserved4[176]; u8 unknown3[0x10]; - u8 ignored4[0xD00]; // ignored + u8 ignored3[0xD00]; // ignored } PACKED_STRUCT TwlHeader; u32 ValidateTwlHeader(TwlHeader* twl); +u32 BuildTwlSaveHeader(void* sav, u32 size); u32 LoadTwlMetaData(const char* path, TwlHeader* hdr, TwlIconData* icon); u32 GetTwlTitle(char* desc, const TwlIconData* twl_icon); u32 GetTwlIcon(u16* icon, const TwlIconData* twl_icon); diff --git a/arm9/source/game/tmd.c b/arm9/source/game/tmd.c index d98f4fa..93e8d0f 100644 --- a/arm9/source/game/tmd.c +++ b/arm9/source/game/tmd.c @@ -76,7 +76,7 @@ u32 FixTmdHashes(TitleMetaData* tmd) { return 0; } -u32 BuildFakeTmd(TitleMetaData* tmd, u8* title_id, u32 n_contents, u32 save_size, u32 twl_privsave_size) { +u32 BuildFakeTmd(TitleMetaData* tmd, u8* title_id, u32 n_contents, u32 save_size, u32 twl_privsave_size, u8 twl_flag) { static const u8 sig_type[4] = { TMD_SIG_TYPE }; // safety check: number of contents if (n_contents > TMD_MAX_CONTENTS) return 1; // potential incompatibility here (!) @@ -91,6 +91,7 @@ u32 BuildFakeTmd(TitleMetaData* tmd, u8* title_id, u32 n_contents, u32 save_size tmd->title_type[3] = 0x40; // whatever for (u32 i = 0; i < 4; i++) tmd->save_size[i] = (save_size >> (i*8)) & 0xFF; // le save size for (u32 i = 0; i < 4; i++) tmd->twl_privsave_size[i] = (twl_privsave_size >> (i*8)) & 0xFF; // le privsave size + tmd->twl_flag = twl_flag; tmd->content_count[0] = (u8) ((n_contents >> 8) & 0xFF); tmd->content_count[1] = (u8) (n_contents & 0xFF); memset(tmd->contentinfo_hash, 0xFF, 0x20); // placeholder (hash) diff --git a/arm9/source/game/tmd.h b/arm9/source/game/tmd.h index 9bc6104..8baa5b8 100644 --- a/arm9/source/game/tmd.h +++ b/arm9/source/game/tmd.h @@ -62,5 +62,5 @@ u32 ValidateTmdSignature(TitleMetaData* tmd); u32 VerifyTmd(TitleMetaData* tmd); u32 GetTmdCtr(u8* ctr, TmdContentChunk* chunk); u32 FixTmdHashes(TitleMetaData* tmd); -u32 BuildFakeTmd(TitleMetaData* tmd, u8* title_id, u32 n_contents, u32 save_size, u32 twl_privsave_size); +u32 BuildFakeTmd(TitleMetaData* tmd, u8* title_id, u32 n_contents, u32 save_size, u32 twl_privsave_size, u8 twl_flag); u32 BuildTmdCert(u8* tmdcert); diff --git a/arm9/source/utils/gameutil.c b/arm9/source/utils/gameutil.c index 6f40012..cca29ad 100644 --- a/arm9/source/utils/gameutil.c +++ b/arm9/source/utils/gameutil.c @@ -2011,7 +2011,7 @@ u32 BuildInstallFromNcchFile(const char* path_ncch, const char* path_dest, bool if ((BuildCiaHeader(&(cia->header), TICKET_COMMON_SIZE) != 0) || (BuildCiaCert(cia->cert) != 0) || (BuildFakeTicket((Ticket*)&(cia->ticket), title_id) != 0) || - (BuildFakeTmd(&(cia->tmd), title_id, 1, save_size, 0)) || + (BuildFakeTmd(&(cia->tmd), title_id, 1, save_size, 0, 0)) || (FixCiaHeaderForTmd(&(cia->header), &(cia->tmd)) != 0) || (!install && (WriteCiaStub(cia, path_dest) != 0))) { free(cia); @@ -2081,7 +2081,7 @@ u32 BuildInstallFromNcsdFile(const char* path_ncsd, const char* path_dest, bool if ((BuildCiaHeader(&(cia->header), TICKET_COMMON_SIZE) != 0) || (BuildCiaCert(cia->cert) != 0) || (BuildFakeTicket((Ticket*)&(cia->ticket), title_id) != 0) || - (BuildFakeTmd(&(cia->tmd), title_id, content_count, save_size, 0)) || + (BuildFakeTmd(&(cia->tmd), title_id, content_count, save_size, 0, 0)) || (FixCiaHeaderForTmd(&(cia->header), &(cia->tmd)) != 0) || (!install && (WriteCiaStub(cia, path_dest) != 0))) { free(cia); @@ -2146,17 +2146,19 @@ u32 BuildInstallFromNdsFile(const char* path_nds, const char* path_dest, bool in u8 title_id[8]; u32 save_size = 0; u32 privsave_size = 0; + u8 twl_flag = 0; // Init progress bar if (!ShowProgress(0, 0, path_nds)) return 1; - // load TWL header, get save sizes && title id + // load TWL header, get save sizes, srl flag && title id if (fvx_qread(path_nds, &twl, 0, sizeof(TwlHeader), NULL) != FR_OK) return 1; for (u32 i = 0; i < 8; i++) title_id[i] = (twl.title_id >> ((7-i)*8)) & 0xFF; save_size = twl.pubsav_size; privsave_size = twl.prvsav_size; + twl_flag = twl.srl_flag; // some basic sanity checks // see: https://problemkaputt.de/gbatek.htm#dsicartridgeheader @@ -2176,7 +2178,7 @@ u32 BuildInstallFromNdsFile(const char* path_nds, const char* path_dest, bool in if ((BuildCiaHeader(&(cia->header), TICKET_COMMON_SIZE) != 0) || (BuildCiaCert(cia->cert) != 0) || (BuildFakeTicket((Ticket*)&(cia->ticket), title_id) != 0) || - (BuildFakeTmd(&(cia->tmd), title_id, 1, save_size, privsave_size)) || + (BuildFakeTmd(&(cia->tmd), title_id, 1, save_size, privsave_size, twl_flag)) || (FixCiaHeaderForTmd(&(cia->header), &(cia->tmd)) != 0) || (!install && (WriteCiaStub(cia, path_dest) != 0))) { free(cia);