Add trimmer tool for FIRM, NAND images, NCSD, NCCH, NDS

Fixes #392
This commit is contained in:
d0k3 2018-07-16 01:07:59 +02:00
parent f9ece57eb0
commit 81ad8a2c1e
6 changed files with 84 additions and 2 deletions

View File

@ -53,6 +53,7 @@
#define FTYPE_KEYBUILD(tp) (tp&(BIN_KEYDB|BIN_LEGKEY)) #define FTYPE_KEYBUILD(tp) (tp&(BIN_KEYDB|BIN_LEGKEY))
#define FTYPE_TITLEINFO(tp) (tp&(GAME_SMDH|GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_TMD|GAME_NDS|GAME_GBA|GAME_TAD|GAME_3DSX)) #define FTYPE_TITLEINFO(tp) (tp&(GAME_SMDH|GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_TMD|GAME_NDS|GAME_GBA|GAME_TAD|GAME_3DSX))
#define FTYPE_RENAMABLE(tp) (tp&(GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_NDS|GAME_GBA)) #define FTYPE_RENAMABLE(tp) (tp&(GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_NDS|GAME_GBA))
#define FTYPE_TRIMABLE(tp) (tp&(IMG_NAND|GAME_NCCH|GAME_NCSD|GAME_NDS|SYS_FIRM))
#define FTYPE_TRANSFERABLE(tp) ((u64) (tp&(IMG_FAT|FLAG_CTR)) == (u64) (IMG_FAT|FLAG_CTR)) #define FTYPE_TRANSFERABLE(tp) ((u64) (tp&(IMG_FAT|FLAG_CTR)) == (u64) (IMG_FAT|FLAG_CTR))
#define FTYPE_NCSDFIXABLE(tp) (tp&(HDR_NAND|NOIMG_NAND)) #define FTYPE_NCSDFIXABLE(tp) (tp&(HDR_NAND|NOIMG_NAND))
#define FTYPE_HASCODE(tp) (((u64) (tp&(GAME_NCCH|FLAG_CXI)) == (u64) (GAME_NCCH|FLAG_CXI))|(tp&GAME_NCSD)) #define FTYPE_HASCODE(tp) (((u64) (tp&(GAME_NCCH|FLAG_CXI)) == (u64) (GAME_NCCH|FLAG_CXI))|(tp&GAME_NCSD))

View File

@ -1,4 +1,3 @@
#include "sddata.h"
#include "virtual.h" #include "virtual.h"
#include "ffconf.h" #include "ffconf.h"
#include "vff.h" #include "vff.h"

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "common.h" #include "common.h"
#include "sddata.h"
#include "ff.h" #include "ff.h"
#define AM_VRT 0x40 // Virtual (FILINFO FAT attribute) #define AM_VRT 0x40 // Virtual (FILINFO FAT attribute)

View File

@ -1029,6 +1029,8 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
bool key_buildable = (FTYPE_KEYBUILD(filetype)) && !in_output_path && !((drvtype & DRV_VIRTUAL) && (drvtype & DRV_SYSNAND)); bool key_buildable = (FTYPE_KEYBUILD(filetype)) && !in_output_path && !((drvtype & DRV_VIRTUAL) && (drvtype & DRV_SYSNAND));
bool titleinfo = (FTYPE_TITLEINFO(filetype)); bool titleinfo = (FTYPE_TITLEINFO(filetype));
bool renamable = (FTYPE_RENAMABLE(filetype)); bool renamable = (FTYPE_RENAMABLE(filetype));
bool trimable = (FTYPE_TRIMABLE(filetype)) && !(drvtype & DRV_VIRTUAL) && !(drvtype & DRV_ALIAS) &&
!(drvtype & DRV_CTRNAND) && !(drvtype & DRV_TWLNAND) && !(drvtype & DRV_IMAGE);
bool transferable = (FTYPE_TRANSFERABLE(filetype) && IS_A9LH && (drvtype & DRV_FAT)); bool transferable = (FTYPE_TRANSFERABLE(filetype) && IS_A9LH && (drvtype & DRV_FAT));
bool hsinjectable = (FTYPE_HASCODE(filetype)); bool hsinjectable = (FTYPE_HASCODE(filetype));
bool extrcodeable = (FTYPE_HASCODE(filetype)); bool extrcodeable = (FTYPE_HASCODE(filetype));
@ -1056,7 +1058,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
extrcodeable = (FTYPE_HASCODE(filetype_cxi)); extrcodeable = (FTYPE_HASCODE(filetype_cxi));
} }
bool special_opt = mountable || verificable || decryptable || encryptable || cia_buildable || cia_buildable_legit || cxi_dumpable || tik_buildable || key_buildable || titleinfo || renamable || transferable || hsinjectable || restorable || xorpadable || ebackupable || ncsdfixable || extrcodeable || extrdiffable || keyinitable || keyinstallable || bootable || scriptable || fontable || viewable || installable || agbexportable || agbimportable; bool special_opt = mountable || verificable || decryptable || encryptable || cia_buildable || cia_buildable_legit || cxi_dumpable || tik_buildable || key_buildable || titleinfo || renamable || trimable || transferable || hsinjectable || restorable || xorpadable || ebackupable || ncsdfixable || extrcodeable || extrdiffable || keyinitable || keyinstallable || bootable || scriptable || fontable || viewable || installable || agbexportable || agbimportable;
char pathstr[32+1]; char pathstr[32+1];
TruncateString(pathstr, file_path, 32, 8); TruncateString(pathstr, file_path, 32, 8);
@ -1244,6 +1246,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
int hsinject = (hsinjectable) ? ++n_opt : -1; int hsinject = (hsinjectable) ? ++n_opt : -1;
int extrcode = (extrcodeable) ? ++n_opt : -1; int extrcode = (extrcodeable) ? ++n_opt : -1;
int extrdiff = (extrdiffable) ? ++n_opt : -1; int extrdiff = (extrdiffable) ? ++n_opt : -1;
int trim = (trimable) ? ++n_opt : -1;
int rename = (renamable) ? ++n_opt : -1; int rename = (renamable) ? ++n_opt : -1;
int xorpad = (xorpadable) ? ++n_opt : -1; int xorpad = (xorpadable) ? ++n_opt : -1;
int xorpad_inplace = (xorpadable) ? ++n_opt : -1; int xorpad_inplace = (xorpadable) ? ++n_opt : -1;
@ -1272,6 +1275,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
if (verify > 0) optionstr[verify-1] = "Verify file"; if (verify > 0) optionstr[verify-1] = "Verify file";
if (ctrtransfer > 0) optionstr[ctrtransfer-1] = "Transfer image to CTRNAND"; if (ctrtransfer > 0) optionstr[ctrtransfer-1] = "Transfer image to CTRNAND";
if (hsinject > 0) optionstr[hsinject-1] = "Inject to H&S"; if (hsinject > 0) optionstr[hsinject-1] = "Inject to H&S";
if (trim > 0) optionstr[trim-1] = "Trim file";
if (rename > 0) optionstr[rename-1] = "Rename file"; if (rename > 0) optionstr[rename-1] = "Rename file";
if (xorpad > 0) optionstr[xorpad-1] = "Build XORpads (SD output)"; if (xorpad > 0) optionstr[xorpad-1] = "Build XORpads (SD output)";
if (xorpad_inplace > 0) optionstr[xorpad_inplace-1] = "Build XORpads (inplace)"; if (xorpad_inplace > 0) optionstr[xorpad_inplace-1] = "Build XORpads (inplace)";
@ -1556,6 +1560,30 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
(BuildKeyDb(file_path, true) == 0) ? "success" : "failed"); (BuildKeyDb(file_path, true) == 0) ? "success" : "failed");
return 0; return 0;
} }
else if (user_select == trim) { // -> Game file trimmer
u64 trimsize = GetGameFileTrimmedSize(file_path);
u64 currentsize = FileGetSize(file_path);
char tsizestr[32];
char csizestr[32];
char dsizestr[32];
FormatBytes(tsizestr, trimsize);
FormatBytes(csizestr, currentsize);
FormatBytes(dsizestr, currentsize - trimsize);
if (!trimsize || trimsize > currentsize) {
ShowPrompt(false, "%s\nFile can't be trimmed.", pathstr);
} else if (trimsize == currentsize) {
ShowPrompt(false, "%s\nFile is already trimmed.", pathstr);
} else if (ShowPrompt(true, "%s\nCurrent size: %s\nTrimmed size: %s\nDifference: %s\n \nTrim this file?",
pathstr, csizestr, tsizestr, dsizestr)) {
if (TrimGameFile(file_path) != 0) ShowPrompt(false, "%s\nTrimming failed.", pathstr);
else {
ShowPrompt(false, "%s\nTrimmed by %s.", pathstr, dsizestr);
GetDirContents(current_dir, current_path);
}
}
return 0;
}
else if (user_select == rename) { // -> Game file renamer else if (user_select == rename) { // -> Game file renamer
if ((n_marked > 1) && ShowPrompt(true, "Try to rename all %lu selected files?", n_marked)) { if ((n_marked > 1) && ShowPrompt(true, "Try to rename all %lu selected files?", n_marked)) {
u32 n_success = 0; u32 n_success = 0;

View File

@ -1,6 +1,7 @@
#include "gameutil.h" #include "gameutil.h"
#include "disadiff.h" #include "disadiff.h"
#include "game.h" #include "game.h"
#include "nand.h" // so that we can trim NAND images
#include "hid.h" #include "hid.h"
#include "ui.h" #include "ui.h"
#include "fs.h" #include "fs.h"
@ -1654,6 +1655,56 @@ u32 ExtractDataFromDisaDiff(const char* path) {
return ret; return ret;
} }
u64 GetGameFileTrimmedSize(const char* path) {
u64 filetype = IdentifyFileType(path);
u64 trimsize = 0;
if (filetype & GAME_NDS) {
TwlHeader hdr;
if (fvx_qread(path, &hdr, 0, sizeof(TwlHeader), NULL) != FR_OK)
return 0;
if (hdr.unit_code != 0x00) // DSi or NDS+DSi
trimsize = hdr.ntr_twl_rom_size;
else trimsize = hdr.ntr_rom_size; // regular NDS
} else {
u8 hdr[0x200];
if (fvx_qread(path, &hdr, 0, 0x200, NULL) != FR_OK)
return 0;
if (filetype & IMG_NAND)
trimsize = GetNandNcsdMinSizeSectors((NandNcsdHeader*) (void*) hdr) * 0x200;
else if (filetype & SYS_FIRM)
trimsize = GetFirmSize((FirmHeader*) (void*) hdr);
else if (filetype & GAME_NCSD)
trimsize = GetNcsdTrimmedSize((NcsdHeader*) (void*) hdr);
else if (filetype & GAME_NCCH)
trimsize = ((NcchHeader*) (void*) hdr)->size * NCCH_MEDIA_UNIT;
}
// safety check for file size
if (trimsize > fvx_qsize(path))
trimsize = 0;
return trimsize;
}
u32 TrimGameFile(const char* path) {
u64 trimsize = GetGameFileTrimmedSize(path);
if (!trimsize) return 1;
// actual truncate routine - FAT only
FIL fp;
if (fx_open(&fp, path, FA_WRITE | FA_OPEN_EXISTING) != FR_OK)
return 1;
if ((f_lseek(&fp, (u32) trimsize) != FR_OK) || (f_truncate(&fp) != FR_OK)) {
fx_close(&fp);
return 1;
}
fx_close(&fp);
// all done
return 0;
}
u32 LoadSmdhFromGameFile(const char* path, Smdh* smdh) { u32 LoadSmdhFromGameFile(const char* path, Smdh* smdh) {
u64 filetype = IdentifyFileType(path); u64 filetype = IdentifyFileType(path);

View File

@ -9,6 +9,8 @@ u32 BuildCiaFromGameFile(const char* path, bool force_legit);
u32 DumpCxiSrlFromTmdFile(const char* path); u32 DumpCxiSrlFromTmdFile(const char* path);
u32 ExtractCodeFromCxiFile(const char* path, const char* path_out, char* extstr); u32 ExtractCodeFromCxiFile(const char* path, const char* path_out, char* extstr);
u32 ExtractDataFromDisaDiff(const char* path); u32 ExtractDataFromDisaDiff(const char* path);
u64 GetGameFileTrimmedSize(const char* path);
u32 TrimGameFile(const char* path);
u32 ShowGameFileTitleInfo(const char* path); u32 ShowGameFileTitleInfo(const char* path);
u32 GetTmdContentPath(char* path_content, const char* path_tmd); u32 GetTmdContentPath(char* path_content, const char* path_tmd);
u32 BuildNcchInfoXorpads(const char* destdir, const char* path); u32 BuildNcchInfoXorpads(const char* destdir, const char* path);