diff --git a/source/game/gameutil.c b/source/game/gameutil.c index fffc543..3f179f8 100644 --- a/source/game/gameutil.c +++ b/source/game/gameutil.c @@ -1124,8 +1124,7 @@ u32 BuildCiaFromTmdFile(const char* path_tmd, const char* path_cia, bool force_l (LoadTmdFile(&(cia->tmd), path_tmd) != 0) || (FixCiaHeaderForTmd(&(cia->header), &(cia->tmd)) != 0) || (BuildCiaCert(cia->cert) != 0) || - (BuildFakeTicket(&(cia->ticket), cia->tmd.title_id) != 0) || - (WriteCiaStub(cia, path_cia) != 0)) { + (BuildFakeTicket(&(cia->ticket), cia->tmd.title_id) != 0)) { return 1; } @@ -1134,7 +1133,7 @@ u32 BuildCiaFromTmdFile(const char* path_tmd, const char* path_cia, bool force_l TmdContentChunk* content_list = cia->content_list; u32 content_count = getbe16(tmd->content_count); u8* title_id = tmd->title_id; - bool dlc = !cdn && (memcmp(tmd->title_id, dlc_tid_high, sizeof(dlc_tid_high)) == 0); + bool dlc = (memcmp(tmd->title_id, dlc_tid_high, sizeof(dlc_tid_high)) == 0); if (!content_count) return 1; // get (legit) ticket @@ -1171,13 +1170,34 @@ u32 BuildCiaFromTmdFile(const char* path_tmd, const char* path_cia, bool force_l if (!name_content) return 1; // will not happen name_content++; + // DLC? Check for missing contents first! + if (dlc) for (u32 i = 0; (i < content_count) && (i < TMD_MAX_CONTENTS);) { + FILINFO fno; + TmdContentChunk* chunk = &(content_list[i]); + snprintf(name_content, 256 - (name_content - path_content), + (cdn) ? "%08lx" : (dlc && !cdn) ? "00000000/%08lx.app" : "%08lx.app", getbe32(chunk->id)); + if ((fvx_stat(path_content, &fno) != FR_OK) || (fno.fsize != (u32) getbe64(chunk->size))) + memmove(chunk, chunk + 1, ((--content_count) - i) * sizeof(TmdContentChunk)); + else i++; + } + if (!content_count) return 1; + if (content_count < (u16) getbe16(tmd->content_count)) { + if (!ShowPrompt(true, "ID %016llX\nIncomplete DLC (%u missing)\nContinue?", + getbe64(title_id), getbe16(tmd->content_count) - content_count)) return 1; + tmd->content_count[0] = (content_count >> 8) & 0xFF; + tmd->content_count[1] = content_count & 0xFF; + memcpy(tmd->contentinfo[0].cmd_count, tmd->content_count, 2); + if (FixCiaHeaderForTmd(&(cia->header), tmd) != 0) return 1; + } + // insert contents u8 titlekey[16] = { 0xFF }; if ((GetTitleKey(titlekey, &(cia->ticket)) != 0) && force_legit) return 1; + if (WriteCiaStub(cia, path_cia) != 0) return 1; for (u32 i = 0; (i < content_count) && (i < TMD_MAX_CONTENTS); i++) { TmdContentChunk* chunk = &(content_list[i]); snprintf(name_content, 256 - (name_content - path_content), - (cdn) ? "%08lx" : (dlc) ? "00000000/%08lx.app" : "%08lx.app", getbe32(chunk->id)); + (cdn) ? "%08lx" : (dlc && !cdn) ? "00000000/%08lx.app" : "%08lx.app", getbe32(chunk->id)); if (InsertCiaContent(path_cia, path_content, 0, (u32) getbe64(chunk->size), chunk, titlekey, force_legit, false, cdn) != 0) { ShowPrompt(false, "ID %016llX.%08lX\nInsert content failed", getbe64(title_id), getbe32(chunk->id)); return 1; diff --git a/source/virtual/vff.c b/source/virtual/vff.c index a925dfa..7dca181 100644 --- a/source/virtual/vff.c +++ b/source/virtual/vff.c @@ -66,6 +66,19 @@ FRESULT fvx_sync (FIL* fp) { return f_sync( fp ); } +FRESULT fvx_stat (const TCHAR* path, FILINFO* fno) { + if (GetVirtualSource(path)) { + VirtualFile vfile; + if (!GetVirtualFile(&vfile, path)) return FR_NO_PATH; + fno->fsize = vfile.size; + fno->fdate = fno->ftime = 0; + fno->fattrib = (vfile.flags & VFLAG_DIR) ? AM_DIR : 0; + // could be better... + if (_USE_LFN != 0) GetVirtualFilename(fno->fname, &vfile, _MAX_LFN + 1); + return FR_OK; + } else return fa_stat(path, fno); +} + FRESULT fvx_qread (const TCHAR* path, void* buff, FSIZE_t ofs, UINT btr, UINT* br) { FIL fp; FRESULT res; diff --git a/source/virtual/vff.h b/source/virtual/vff.h index 01e016a..5ba7c19 100644 --- a/source/virtual/vff.h +++ b/source/virtual/vff.h @@ -14,6 +14,7 @@ FRESULT fvx_write (FIL* fp, const void* buff, UINT btw, UINT* bw); FRESULT fvx_close (FIL* fp); FRESULT fvx_lseek (FIL* fp, FSIZE_t ofs); FRESULT fvx_sync (FIL* fp); +FRESULT fvx_stat (const TCHAR* path, FILINFO* fno); // additional quick read / write functions FRESULT fvx_qread (const TCHAR* path, void* buff, FSIZE_t ofs, UINT btr, UINT* br);