Skip to content

Commit 98c1b25

Browse files
committed
Allow fixing improperly decrypted NCSD/NCCH
... use "verify" for this. Also, there's a hint now when trying to CIA convert such files.
1 parent 940284c commit 98c1b25

File tree

2 files changed

+53
-23
lines changed

2 files changed

+53
-23
lines changed

arm9/source/godmode.c

+12-1
Original file line numberDiff line numberDiff line change
@@ -1524,12 +1524,23 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
15241524
else ShowPrompt(false, "%lu/%lu %ss built ok", n_success, n_marked, type);
15251525
if (n_success) ShowPrompt(false, "%lu files written to %s", n_success, OUTPUT_PATH);
15261526
if (n_success && in_output_path) GetDirContents(current_dir, current_path);
1527+
if (n_success != (n_marked - n_other)) {
1528+
ShowPrompt(false, "%lu file(s) failed conversion.\nVerification is recommended.",
1529+
n_marked - (n_success + n_other));
1530+
}
15271531
} else {
15281532
if (((user_select != cxi_dump) && (BuildCiaFromGameFile(file_path, force_legit) == 0)) ||
15291533
((user_select == cxi_dump) && (DumpCxiSrlFromTmdFile(file_path) == 0))) {
15301534
ShowPrompt(false, "%s\n%s built to %s", pathstr, type, OUTPUT_PATH);
15311535
if (in_output_path) GetDirContents(current_dir, current_path);
1532-
} else ShowPrompt(false, "%s\n%s build failed", pathstr, type);
1536+
} else {
1537+
ShowPrompt(false, "%s\n%s build failed", pathstr, type);
1538+
if ((filetype & (GAME_NCCH|GAME_NCSD)) &&
1539+
ShowPrompt(true, "%s\nfile failed conversion.\n \nVerify now?", pathstr)) {
1540+
ShowPrompt(false, "%s\nVerification %s", pathstr,
1541+
(VerifyGameFile(file_path) == 0) ? "success" : "failed");
1542+
}
1543+
}
15331544
}
15341545
return 0;
15351546
}

arm9/source/utils/gameutil.c

+41-22
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,16 @@
1313
#define CRYPTO_DECRYPT NCCH_NOCRYPTO
1414
#define CRYPTO_ENCRYPT NCCH_STDCRYPTO
1515

16-
u32 GetNcchHeaders(NcchHeader* ncch, NcchExtHeader* exthdr, ExeFsHeader* exefs, FIL* file) {
16+
u32 GetNcchHeaders(NcchHeader* ncch, NcchExtHeader* exthdr, ExeFsHeader* exefs, FIL* file, bool nocrypto) {
1717
u32 offset_ncch = fvx_tell(file);
1818
UINT btr;
19-
20-
if ((fvx_read(file, ncch, sizeof(NcchHeader), &btr) != FR_OK) ||
21-
(ValidateNcchHeader(ncch) != 0))
22-
return 1;
19+
20+
if (fvx_read(file, ncch, sizeof(NcchHeader), &btr) != FR_OK) return 1;
21+
if (nocrypto) {
22+
ncch->flags[3] = 0x00;
23+
ncch->flags[7] = (ncch->flags[7] & ~0x21) | 0x04;
24+
}
25+
if (ValidateNcchHeader(ncch) != 0) return 1;
2326

2427
if (exthdr) {
2528
if (!ncch->size_exthdr) return 1;
@@ -71,7 +74,7 @@ u32 LoadNcchHeaders(NcchHeader* ncch, NcchExtHeader* exthdr, ExeFsHeader* exefs,
7174
if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
7275
return 1;
7376
fvx_lseek(&file, offset);
74-
if (GetNcchHeaders(ncch, exthdr, exefs, &file) != 0) {
77+
if (GetNcchHeaders(ncch, exthdr, exefs, &file, false) != 0) {
7578
fvx_close(&file);
7679
return 1;
7780
}
@@ -137,7 +140,7 @@ u32 LoadExeFsFile(void* data, const char* path, u32 offset, const char* name, u3
137140
if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
138141
return 1;
139142
fvx_lseek(&file, offset);
140-
if ((GetNcchHeaders(&ncch, NULL, &exefs, &file) != 0) ||
143+
if ((GetNcchHeaders(&ncch, NULL, &exefs, &file, false) != 0) ||
141144
(!ncch.size_exefs)) {
142145
fvx_close(&file);
143146
return 1;
@@ -304,6 +307,7 @@ u32 VerifyTmdContent(const char* path, u64 offset, TmdContentChunk* chunk, const
304307
}
305308

306309
u32 VerifyNcchFile(const char* path, u32 offset, u32 size) {
310+
bool cryptofix = false;
307311
NcchHeader ncch;
308312
NcchExtHeader exthdr;
309313
ExeFsHeader exefs;
@@ -316,35 +320,49 @@ u32 VerifyNcchFile(const char* path, u32 offset, u32 size) {
316320
if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
317321
return 1;
318322

323+
// fetch and check NCCH header
319324
fvx_lseek(&file, offset);
320-
if (GetNcchHeaders(&ncch, NULL, NULL, &file) != 0) {
325+
if (GetNcchHeaders(&ncch, NULL, NULL, &file, cryptofix) != 0) {
321326
if (!offset) ShowPrompt(false, "%s\nError: Not a NCCH file", pathstr);
322327
fvx_close(&file);
323328
return 1;
324329
}
325-
326-
fvx_lseek(&file, offset);
327-
if (ncch.size_exthdr && (GetNcchHeaders(&ncch, &exthdr, NULL, &file) != 0)) {
328-
if (!offset) ShowPrompt(false, "%s\nError: Missing ExtHeader", pathstr);
330+
331+
// check NCCH size
332+
if (!size) size = fvx_size(&file) - offset;
333+
if ((fvx_size(&file) < offset) || (size < ncch.size * NCCH_MEDIA_UNIT)) {
334+
if (!offset) ShowPrompt(false, "%s\nError: File is too small", pathstr);
329335
fvx_close(&file);
330336
return 1;
331337
}
332338

339+
// fetch and check ExeFS header
333340
fvx_lseek(&file, offset);
334-
if (ncch.size_exefs && (GetNcchHeaders(&ncch, NULL, &exefs, &file) != 0)) {
335-
if (!offset) ShowPrompt(false, "%s\nError: Bad ExeFS header", pathstr);
336-
fvx_close(&file);
337-
return 1;
341+
if (ncch.size_exefs && (GetNcchHeaders(&ncch, NULL, &exefs, &file, cryptofix) != 0)) {
342+
bool borkedflags = false;
343+
if (ncch.size_exefs && NCCH_ENCRYPTED(&ncch)) {
344+
// disable crypto, try again
345+
cryptofix = true;
346+
fvx_lseek(&file, offset);
347+
if ((GetNcchHeaders(&ncch, NULL, &exefs, &file, cryptofix) == 0) &&
348+
ShowPrompt(true, "%s\nError: Bad crypto flags\n \nAttempt to fix?", pathstr))
349+
borkedflags = true;
350+
}
351+
if (!borkedflags) {
352+
if (!offset) ShowPrompt(false, "%s\nError: Bad ExeFS header", pathstr);
353+
fvx_close(&file);
354+
return 1;
355+
}
338356
}
339-
340-
// size checks
341-
if (!size) size = fvx_size(&file) - offset;
342-
if ((fvx_size(&file) < offset) || (size < ncch.size * NCCH_MEDIA_UNIT)) {
343-
if (!offset) ShowPrompt(false, "%s\nError: File is too small", pathstr);
357+
358+
// fetch and check ExtHeader
359+
fvx_lseek(&file, offset);
360+
if (ncch.size_exthdr && (GetNcchHeaders(&ncch, &exthdr, NULL, &file, cryptofix) != 0)) {
361+
if (!offset) ShowPrompt(false, "%s\nError: Missing ExtHeader", pathstr);
344362
fvx_close(&file);
345363
return 1;
346364
}
347-
365+
348366
// check / setup crypto
349367
if (SetupNcchCrypto(&ncch, NCCH_NOCRYPTO) != 0) {
350368
if (!offset) ShowPrompt(false, "%s\nError: Crypto not set up", pathstr);
@@ -481,6 +499,7 @@ u32 VerifyNcchFile(const char* path, u32 offset, u32 size) {
481499
}
482500

483501
fvx_close(&file);
502+
if (cryptofix) fvx_qwrite(path, &ncch, offset, sizeof(NcchHeader), NULL);
484503
return ver_exthdr|ver_exefs|ver_romfs;
485504
}
486505

0 commit comments

Comments
 (0)