mirror of
https://github.com/rvtr/TDT.git
synced 2025-10-31 13:51:07 -04:00
TADs now install!
This commit is contained in:
parent
aea4371a6a
commit
6786ee2cea
8
Makefile
8
Makefile
@ -13,11 +13,11 @@ export TOPDIR := $(CURDIR)
|
|||||||
NITRO_FILES :=
|
NITRO_FILES :=
|
||||||
|
|
||||||
# These set the information text in the nds file
|
# These set the information text in the nds file
|
||||||
GAME_TITLE := NAND Title Manager
|
GAME_TITLE := TAD Delivery Tool
|
||||||
GAME_SUBTITLE1 := JeffRuLz, Pk11
|
GAME_SUBTITLE1 := JeffRuLz, Pk11, rmc
|
||||||
|
|
||||||
GAME_CODE := HTNA
|
GAME_CODE := 4TDA
|
||||||
GAME_LABEL := NANDTM_TAD
|
GAME_LABEL := TAD_DELIVERY
|
||||||
|
|
||||||
include $(DEVKITARM)/ds_rules
|
include $(DEVKITARM)/ds_rules
|
||||||
|
|
||||||
|
|||||||
@ -157,12 +157,7 @@ static void generateList(Menu* m)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (strcasecmp(strrchr(ent->d_name, '.'), ".nds") == 0 ||
|
if (strcasecmp(strrchr(ent->d_name, '.'), ".tad") == 0)
|
||||||
strcasecmp(strrchr(ent->d_name, '.'), ".app") == 0 ||
|
|
||||||
strcasecmp(strrchr(ent->d_name, '.'), ".dsi") == 0 ||
|
|
||||||
strcasecmp(strrchr(ent->d_name, '.'), ".ids") == 0 ||
|
|
||||||
strcasecmp(strrchr(ent->d_name, '.'), ".srl") == 0 ||
|
|
||||||
strcasecmp(strrchr(ent->d_name, '.'), ".cia") == 0)
|
|
||||||
{
|
{
|
||||||
if (count < m->page * ITEMS_PER_PAGE)
|
if (count < m->page * ITEMS_PER_PAGE)
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|||||||
@ -352,7 +352,7 @@ static void _createTicket(tDSiHeader *h, char* ticketPath)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool install(char* fpath, bool systemTitle)
|
bool install(char* tadPath, bool systemTitle)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
@ -365,6 +365,7 @@ bool install(char* fpath, bool systemTitle)
|
|||||||
|
|
||||||
//start installation
|
//start installation
|
||||||
clearScreen(&bottomScreen);
|
clearScreen(&bottomScreen);
|
||||||
|
char* fpath = decryptTad(tadPath);
|
||||||
|
|
||||||
tDSiHeader* h = getRomHeader(fpath);
|
tDSiHeader* h = getRomHeader(fpath);
|
||||||
|
|
||||||
@ -694,13 +695,7 @@ bool install(char* fpath, bool systemTitle)
|
|||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
if (romIsCia(fpath)) {
|
result = copyFile(fpath, appPath);
|
||||||
result = copyFilePart(fpath, 0x3900, fileSize, appPath);
|
|
||||||
} else if (romIsTad(fpath)) {
|
|
||||||
result = decryptTad(fpath);
|
|
||||||
} else {
|
|
||||||
result = copyFile(fpath, appPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -186,13 +186,7 @@ static void generateList(Menu* m)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (strcasecmp(strrchr(ent->d_name, '.'), ".nds") == 0 ||
|
if (strcasecmp(strrchr(ent->d_name, '.'), ".tad") == 0)
|
||||||
strcasecmp(strrchr(ent->d_name, '.'), ".app") == 0 ||
|
|
||||||
strcasecmp(strrchr(ent->d_name, '.'), ".dsi") == 0 ||
|
|
||||||
strcasecmp(strrchr(ent->d_name, '.'), ".ids") == 0 ||
|
|
||||||
strcasecmp(strrchr(ent->d_name, '.'), ".srl") == 0 ||
|
|
||||||
strcasecmp(strrchr(ent->d_name, '.'), ".tad") == 0 ||
|
|
||||||
strcasecmp(strrchr(ent->d_name, '.'), ".cia") == 0)
|
|
||||||
{
|
{
|
||||||
if (count < m->page * ITEMS_PER_PAGE)
|
if (count < m->page * ITEMS_PER_PAGE)
|
||||||
count += 1;
|
count += 1;
|
||||||
@ -238,7 +232,7 @@ static void printItem(Menu* m)
|
|||||||
if (m->items[m->cursor].directory)
|
if (m->items[m->cursor].directory)
|
||||||
clearScreen(&topScreen);
|
clearScreen(&topScreen);
|
||||||
else
|
else
|
||||||
printRomInfo(m->items[m->cursor].value);
|
printTadInfo(m->items[m->cursor].value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int subMenu()
|
static int subMenu()
|
||||||
|
|||||||
@ -11,8 +11,6 @@ bool programEnd = false;
|
|||||||
bool sdnandMode = true;
|
bool sdnandMode = true;
|
||||||
bool unlaunchFound = false;
|
bool unlaunchFound = false;
|
||||||
bool unlaunchPatches = false;
|
bool unlaunchPatches = false;
|
||||||
bool devkpFound = false;
|
|
||||||
bool launcherDSiFound = false;
|
|
||||||
bool arm7Exiting = false;
|
bool arm7Exiting = false;
|
||||||
bool charging = false;
|
bool charging = false;
|
||||||
u8 batteryLevel = 0;
|
u8 batteryLevel = 0;
|
||||||
@ -57,32 +55,30 @@ static int _mainMenu(int cursor)
|
|||||||
//top screen
|
//top screen
|
||||||
clearScreen(&topScreen);
|
clearScreen(&topScreen);
|
||||||
|
|
||||||
iprintf("\t\tNAND Title Manager\n");
|
iprintf("\t\tTAD Delivery Tool\n");
|
||||||
iprintf("\t\t\tmodified from\n");
|
iprintf("\t\t\tmodified from\n");
|
||||||
iprintf("\tTitle Manager for HiyaCFW\n");
|
iprintf("\tTitle Manager for HiyaCFW\n");
|
||||||
|
iprintf("\tand Nand Title Manager\n");
|
||||||
iprintf("\nversion %s\n", VERSION);
|
iprintf("\nversion %s\n", VERSION);
|
||||||
iprintf("\n\n\x1B[41mWARNING:\x1B[47m This tool can write to\nyour internal NAND!\n\nThis always has a risk, albeit\nlow, of \x1B[41mbricking\x1B[47m your system\nand should be done with caution!\n");
|
iprintf("\n\n\x1B[41mWARNING:\x1B[47m This tool can write to\nyour internal NAND!\n\nThis always has a risk, albeit\nlow, of \x1B[41mbricking\x1B[47m your system\nand should be done with caution!\n");
|
||||||
iprintf("\n\t \x1B[46mhttps://dsi.cfw.guide\x1B[47m\n");
|
iprintf("\n\t \x1B[46mhttps://dsi.cfw.guide\x1B[47m\n");
|
||||||
iprintf("\n\n \x1B[46mgithub.com/Epicpkmn11/NTM/wiki\x1B[47m\n");
|
iprintf("\n\n \x1B[46mgithub.com/rvtr/TDT\x1B[47m\n");
|
||||||
iprintf("\x1b[22;0HJeff - 2018-2019");
|
iprintf("\x1b[22;0HJeff - 2018-2019");
|
||||||
iprintf("\x1b[23;0HPk11 - 2022-2023");
|
iprintf("\x1b[23;0HPk11 - 2022-2023");
|
||||||
|
iprintf("\x1b[24;0Hrmc - 2024-2024");
|
||||||
|
|
||||||
//menu
|
//menu
|
||||||
Menu* m = newMenu();
|
Menu* m = newMenu();
|
||||||
setMenuHeader(m, "MAIN MENU");
|
setMenuHeader(m, "MAIN MENU");
|
||||||
|
|
||||||
char modeStr[32], datamanStr[32], launcherStr[32];
|
char modeStr[32];
|
||||||
sprintf(modeStr, "Mode: %s", sdnandMode ? "SDNAND" : "\x1B[41mSysNAND\x1B[47m");
|
sprintf(modeStr, "Mode: %s", sdnandMode ? "SDNAND" : "\x1B[41mSysNAND\x1B[47m");
|
||||||
sprintf(datamanStr, "\x1B[%02omEnable Data Management", devkpFound ? 037 : 047);
|
|
||||||
sprintf(launcherStr, "\x1B[%02omUninstall region mod", launcherDSiFound ? 047 : 037);
|
|
||||||
addMenuItem(m, modeStr, NULL, 0);
|
addMenuItem(m, modeStr, NULL, 0);
|
||||||
addMenuItem(m, "Install", NULL, 0);
|
addMenuItem(m, "Install", NULL, 0);
|
||||||
addMenuItem(m, "Titles", NULL, 0);
|
addMenuItem(m, "Titles", NULL, 0);
|
||||||
addMenuItem(m, "Restore", NULL, 0);
|
//addMenuItem(m, "Restore", NULL, 0);
|
||||||
addMenuItem(m, "Test", NULL, 0);
|
addMenuItem(m, "Test", NULL, 0);
|
||||||
addMenuItem(m, "Fix FAT copy mismatch", NULL, 0);
|
addMenuItem(m, "Fix FAT copy mismatch", NULL, 0);
|
||||||
addMenuItem(m, datamanStr, NULL, 0);
|
|
||||||
addMenuItem(m, launcherStr, NULL, 0);
|
|
||||||
addMenuItem(m, "\x1B[47mExit", NULL, 0);
|
addMenuItem(m, "\x1B[47mExit", NULL, 0);
|
||||||
|
|
||||||
m->cursor = cursor;
|
m->cursor = cursor;
|
||||||
@ -207,19 +203,13 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
else if (!unlaunchPatches)
|
else if (!unlaunchPatches)
|
||||||
{
|
{
|
||||||
messageBox("Unlaunch's Launcher Patches are\nnot enabled. You will need to\nprovide TMD files or reinstall.\n\n\x1B[46mhttps://dsi.cfw.guide/\x1B[47m");
|
messageBox("Unlaunch's Launcher Patches are\nnot enabled. You will need these\nif you patch any TADs.\n\n\x1B[46mhttps://dsi.cfw.guide/\x1B[47m");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//check for dev.kp (Data Management visible)
|
|
||||||
devkpFound = (access("sd:/sys/dev.kp", F_OK) == 0);
|
|
||||||
|
|
||||||
//check for launcher.dsi (Language patcher)
|
|
||||||
launcherDSiFound = (access("nand:/launcher.dsi", F_OK) == 0);
|
|
||||||
|
|
||||||
messageBox("\x1B[41mWARNING:\x1B[47m This tool can write to\nyour internal NAND!\n\nThis always has a risk, albeit\nlow, of \x1B[41mbricking\x1B[47m your system\nand should be done with caution!\n\nIf you have not yet done so,\nyou should make a NAND backup.");
|
messageBox("\x1B[41mWARNING:\x1B[47m This tool can write to\nyour internal NAND!\n\nThis always has a risk, albeit\nlow, of \x1B[41mbricking\x1B[47m your system\nand should be done with caution!\n\nIf you have not yet done so,\nyou should make a NAND backup.");
|
||||||
|
|
||||||
messageBox("If you are following a video\nguide, please stop.\n\nVideo guides for console moddingare often outdated or straight\nup incorrect to begin with.\n\nThe recommended guide for\nmodding your DSi is:\n\n\x1B[46mhttps://dsi.cfw.guide/\x1B[47m\n\nFor more information on using\nNTM, see the official wiki:\n\n\x1B[46mhttps://github.com/Epicpkmn11/\n\t\t\t\t\t\t\t\tNTM/wiki\x1B[47m");
|
messageBox("If you are following a video\nguide, please stop.\n\nVideo guides for console moddingare often outdated or straight\nup incorrect to begin with.\n\nThe recommended guide for\nmodding your DSi is:\n\n\x1B[46mhttps://dsi.cfw.guide/\x1B[47m\n\nFor more information on using\nTDT, see the official repo:\n\n\x1B[46mhttps://github.com/rvtr/TDT\x1B[47m");
|
||||||
//main menu
|
//main menu
|
||||||
int cursor = 0;
|
int cursor = 0;
|
||||||
|
|
||||||
@ -231,7 +221,6 @@ int main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
case MAIN_MENU_MODE:
|
case MAIN_MENU_MODE:
|
||||||
sdnandMode = !sdnandMode;
|
sdnandMode = !sdnandMode;
|
||||||
devkpFound = (access(sdnandMode ? "sd:/sys/dev.kp" : "nand:/sys/dev.kp", F_OK) == 0);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MAIN_MENU_INSTALL:
|
case MAIN_MENU_INSTALL:
|
||||||
@ -241,11 +230,11 @@ int main(int argc, char **argv)
|
|||||||
case MAIN_MENU_TITLES:
|
case MAIN_MENU_TITLES:
|
||||||
titleMenu();
|
titleMenu();
|
||||||
break;
|
break;
|
||||||
|
/*
|
||||||
case MAIN_MENU_BACKUP:
|
case MAIN_MENU_BACKUP:
|
||||||
backupMenu();
|
backupMenu();
|
||||||
break;
|
break;
|
||||||
|
*/
|
||||||
case MAIN_MENU_TEST:
|
case MAIN_MENU_TEST:
|
||||||
testMenu();
|
testMenu();
|
||||||
break;
|
break;
|
||||||
@ -259,35 +248,6 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MAIN_MENU_DATA_MANAGEMENT:
|
|
||||||
if (!devkpFound && (choiceBox("Make Data Management visible\nin System Settings?") == YES) && (sdnandMode || nandio_unlock_writing()))
|
|
||||||
{
|
|
||||||
//ensure sys folder exists
|
|
||||||
if(access(sdnandMode ? "sd:/sys" : "nand:/sys", F_OK) != 0)
|
|
||||||
mkdir(sdnandMode ? "sd:/sys" : "nand:/sys", 0777);
|
|
||||||
|
|
||||||
//create empty file
|
|
||||||
FILE *file = fopen(sdnandMode ? "sd:/sys/dev.kp" : "nand:/sys/dev.kp", "wb");
|
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
if(!sdnandMode)
|
|
||||||
nandio_lock_writing();
|
|
||||||
devkpFound = (access(sdnandMode ? "sd:/sys/dev.kp" : "nand:/sys/dev.kp", F_OK) == 0);
|
|
||||||
messageBox("Data Management is now visible\nin System Settings.\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MAIN_MENU_LANGUAGE_PATCHER:
|
|
||||||
if (launcherDSiFound && (choiceBox("Uninstall the language patched\nDSi Menu? (launcher.dsi)") == YES) && nandio_unlock_writing())
|
|
||||||
{
|
|
||||||
//delete launcher.dsi
|
|
||||||
remove("nand:/launcher.dsi");
|
|
||||||
|
|
||||||
nandio_lock_writing();
|
|
||||||
launcherDSiFound = (access("nand:/launcher.dsi", F_OK) == 0);
|
|
||||||
messageBox("The language patched DSi Menu\nhas been removed.\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MAIN_MENU_EXIT:
|
case MAIN_MENU_EXIT:
|
||||||
programEnd = true;
|
programEnd = true;
|
||||||
break;
|
break;
|
||||||
|
|||||||
226
arm9/src/rom.c
226
arm9/src/rom.c
@ -1,6 +1,7 @@
|
|||||||
#include "rom.h"
|
#include "rom.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
|
#include "tad.h"
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <nds.h>
|
#include <nds.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
@ -19,11 +20,7 @@ tDSiHeader* getRomHeader(char const* fpath)
|
|||||||
|
|
||||||
if (h)
|
if (h)
|
||||||
{
|
{
|
||||||
if (romIsCia(fpath))
|
fseek(f, 0, SEEK_SET);
|
||||||
fseek(f, 0x3900, SEEK_SET);
|
|
||||||
else
|
|
||||||
fseek(f, 0, SEEK_SET);
|
|
||||||
|
|
||||||
fread(h, sizeof(tDSiHeader), 1, f);
|
fread(h, sizeof(tDSiHeader), 1, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,11 +47,7 @@ tNDSBanner* getRomBanner(char const* fpath)
|
|||||||
|
|
||||||
if (b)
|
if (b)
|
||||||
{
|
{
|
||||||
if (romIsCia(fpath))
|
fseek(f, 0, SEEK_SET);
|
||||||
fseek(f, 0x3900, SEEK_SET);
|
|
||||||
else
|
|
||||||
fseek(f, 0, SEEK_SET);
|
|
||||||
|
|
||||||
fseek(f, h->ndshdr.bannerOffset, SEEK_CUR);
|
fseek(f, h->ndshdr.bannerOffset, SEEK_CUR);
|
||||||
fread(b, sizeof(tNDSBanner), 1, f);
|
fread(b, sizeof(tNDSBanner), 1, f);
|
||||||
}
|
}
|
||||||
@ -146,106 +139,99 @@ void printRomInfo(char const* fpath)
|
|||||||
tDSiHeader* h = getRomHeader(fpath);
|
tDSiHeader* h = getRomHeader(fpath);
|
||||||
tNDSBanner* b = getRomBanner(fpath);
|
tNDSBanner* b = getRomBanner(fpath);
|
||||||
|
|
||||||
if (!isDsiHeader(h))
|
if (!b)
|
||||||
{
|
{
|
||||||
iprintf("Could not read dsi header.\n");
|
iprintf("Could not read banner.\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!b)
|
//proper title
|
||||||
{
|
{
|
||||||
iprintf("Could not read banner.\n");
|
char gameTitle[128+1];
|
||||||
|
getGameTitle(b, gameTitle, true);
|
||||||
|
|
||||||
|
iprintf("%s\n\n", gameTitle);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
//file size
|
||||||
{
|
{
|
||||||
//proper title
|
iprintf("Size: ");
|
||||||
{
|
unsigned long long romSize = getRomSize(fpath);
|
||||||
char gameTitle[128+1];
|
printBytes(romSize);
|
||||||
getGameTitle(b, gameTitle, true);
|
//size in blocks, rounded up
|
||||||
|
iprintf(" (%lld blocks)\n", ((romSize / BYTES_PER_BLOCK) * BYTES_PER_BLOCK + BYTES_PER_BLOCK) / BYTES_PER_BLOCK);
|
||||||
iprintf("%s\n\n", gameTitle);
|
|
||||||
}
|
|
||||||
|
|
||||||
//file size
|
|
||||||
{
|
|
||||||
iprintf("Size: ");
|
|
||||||
unsigned long long romSize = getRomSize(fpath);
|
|
||||||
printBytes(romSize);
|
|
||||||
//size in blocks, rounded up
|
|
||||||
iprintf(" (%lld blocks)\n", ((romSize / BYTES_PER_BLOCK) * BYTES_PER_BLOCK + BYTES_PER_BLOCK) / BYTES_PER_BLOCK);
|
|
||||||
}
|
|
||||||
|
|
||||||
iprintf("Label: %.12s\n", h->ndshdr.gameTitle);
|
|
||||||
iprintf("Game Code: %.4s\n", h->ndshdr.gameCode);
|
|
||||||
|
|
||||||
//system type
|
|
||||||
{
|
|
||||||
iprintf("Unit Code: ");
|
|
||||||
|
|
||||||
switch (h->ndshdr.unitCode)
|
|
||||||
{
|
|
||||||
case 0: iprintf("NDS"); break;
|
|
||||||
case 2: iprintf("NDS+DSi"); break;
|
|
||||||
case 3: iprintf("DSi"); break;
|
|
||||||
default: iprintf("unknown");
|
|
||||||
}
|
|
||||||
|
|
||||||
iprintf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
//application type
|
|
||||||
{
|
|
||||||
iprintf("Program Type: ");
|
|
||||||
|
|
||||||
switch (h->ndshdr.reserved1[7])
|
|
||||||
{
|
|
||||||
case 0x3: iprintf("Normal"); break;
|
|
||||||
case 0xB: iprintf("Sys"); break;
|
|
||||||
case 0xF: iprintf("Debug/Sys"); break;
|
|
||||||
default: iprintf("unknown");
|
|
||||||
}
|
|
||||||
|
|
||||||
iprintf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
//DSi title ids
|
|
||||||
{
|
|
||||||
if (h->tid_high == 0x00030004 ||
|
|
||||||
h->tid_high == 0x00030005 ||
|
|
||||||
h->tid_high == 0x00030011 || // TID for software in TWL SDK
|
|
||||||
h->tid_high == 0x00030015 ||
|
|
||||||
h->tid_high == 0x00030017 ||
|
|
||||||
h->tid_high == 0x00030000)
|
|
||||||
{
|
|
||||||
iprintf("Title ID: %08x %08x\n", (unsigned int)h->tid_high, (unsigned int)h->tid_low);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//print full file path
|
|
||||||
iprintf("\n%s\n", fpath);
|
|
||||||
|
|
||||||
//print extra files
|
|
||||||
int extensionPos = strrchr(fpath, '.') - fpath;
|
|
||||||
char temp[PATH_MAX];
|
|
||||||
strcpy(temp, fpath);
|
|
||||||
strcpy(temp + extensionPos, ".tmd");
|
|
||||||
//DSi TMDs are 520, TMDs from NUS are 2,312. If 2,312 we can simply trim it to 520
|
|
||||||
int tmdSize = getFileSizePath(temp);
|
|
||||||
if (access(temp, F_OK) == 0)
|
|
||||||
printf("\t\x1B[%om%s\n\x1B[47m", (tmdSize == 520 || tmdSize == 2312) ? 047 : 041, strrchr(temp, '/') + 1);
|
|
||||||
|
|
||||||
strcpy(temp + extensionPos, ".pub");
|
|
||||||
if (access(temp, F_OK) == 0)
|
|
||||||
printf("\t\x1B[%om%s\n\x1B[47m", (getFileSizePath(temp) == h->public_sav_size) ? 047 : 041, strrchr(temp, '/') + 1);
|
|
||||||
|
|
||||||
strcpy(temp + extensionPos, ".prv");
|
|
||||||
if (access(temp, F_OK) == 0)
|
|
||||||
printf("\t\x1B[%om%s\n\x1B[47m", (getFileSizePath(temp) == h->private_sav_size) ? 047 : 041, strrchr(temp, '/') + 1);
|
|
||||||
|
|
||||||
strcpy(temp + extensionPos, ".bnr");
|
|
||||||
if (access(temp, F_OK) == 0)
|
|
||||||
printf("\t\x1B[%om%s\n\x1B[47m", (getFileSizePath(temp) == 0x4000) ? 047 : 041, strrchr(temp, '/') + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iprintf("Label: %.12s\n", h->ndshdr.gameTitle);
|
||||||
|
iprintf("Game Code: %.4s\n", h->ndshdr.gameCode);
|
||||||
|
|
||||||
|
//system type
|
||||||
|
{
|
||||||
|
iprintf("Unit Code: ");
|
||||||
|
|
||||||
|
switch (h->ndshdr.unitCode)
|
||||||
|
{
|
||||||
|
case 0: iprintf("NDS"); break;
|
||||||
|
case 2: iprintf("NDS+DSi"); break;
|
||||||
|
case 3: iprintf("DSi"); break;
|
||||||
|
default: iprintf("unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
iprintf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//application type
|
||||||
|
{
|
||||||
|
iprintf("Program Type: ");
|
||||||
|
|
||||||
|
switch (h->ndshdr.reserved1[7])
|
||||||
|
{
|
||||||
|
case 0x3: iprintf("Normal"); break;
|
||||||
|
case 0xB: iprintf("Sys"); break;
|
||||||
|
case 0xF: iprintf("Debug/Sys"); break;
|
||||||
|
default: iprintf("unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
iprintf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//DSi title ids
|
||||||
|
{
|
||||||
|
if (h->tid_high == 0x00030004 ||
|
||||||
|
h->tid_high == 0x00030005 ||
|
||||||
|
h->tid_high == 0x00030011 || // TID for software in TWL SDK
|
||||||
|
h->tid_high == 0x00030015 ||
|
||||||
|
h->tid_high == 0x00030017 ||
|
||||||
|
h->tid_high == 0x00030000)
|
||||||
|
{
|
||||||
|
iprintf("Title ID: %08x %08x\n", (unsigned int)h->tid_high, (unsigned int)h->tid_low);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//print full file path
|
||||||
|
iprintf("\n%s\n", fpath);
|
||||||
|
|
||||||
|
//print extra files
|
||||||
|
int extensionPos = strrchr(fpath, '.') - fpath;
|
||||||
|
char temp[PATH_MAX];
|
||||||
|
strcpy(temp, fpath);
|
||||||
|
strcpy(temp + extensionPos, ".tmd");
|
||||||
|
//DSi TMDs are 520, TMDs from NUS are 2,312. If 2,312 we can simply trim it to 520
|
||||||
|
int tmdSize = getFileSizePath(temp);
|
||||||
|
if (access(temp, F_OK) == 0)
|
||||||
|
printf("\t\x1B[%om%s\n\x1B[47m", (tmdSize == 520 || tmdSize == 2312) ? 047 : 041, strrchr(temp, '/') + 1);
|
||||||
|
|
||||||
|
strcpy(temp + extensionPos, ".pub");
|
||||||
|
if (access(temp, F_OK) == 0)
|
||||||
|
printf("\t\x1B[%om%s\n\x1B[47m", (getFileSizePath(temp) == h->public_sav_size) ? 047 : 041, strrchr(temp, '/') + 1);
|
||||||
|
|
||||||
|
strcpy(temp + extensionPos, ".prv");
|
||||||
|
if (access(temp, F_OK) == 0)
|
||||||
|
printf("\t\x1B[%om%s\n\x1B[47m", (getFileSizePath(temp) == h->private_sav_size) ? 047 : 041, strrchr(temp, '/') + 1);
|
||||||
|
|
||||||
|
strcpy(temp + extensionPos, ".bnr");
|
||||||
|
if (access(temp, F_OK) == 0)
|
||||||
|
printf("\t\x1B[%om%s\n\x1B[47m", (getFileSizePath(temp) == 0x4000) ? 047 : 041, strrchr(temp, '/') + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(b);
|
free(b);
|
||||||
@ -261,42 +247,10 @@ unsigned long long getRomSize(char const* fpath)
|
|||||||
|
|
||||||
if (f)
|
if (f)
|
||||||
{
|
{
|
||||||
//cia
|
fseek(f, 0, SEEK_END);
|
||||||
if (romIsCia(fpath))
|
size = ftell(f);
|
||||||
{
|
|
||||||
unsigned char bytes[4] = { 0 };
|
|
||||||
fseek(f, 0x38D0, SEEK_SET);
|
|
||||||
fread(bytes, 4, 1, f);
|
|
||||||
size = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fseek(f, 0, SEEK_END);
|
|
||||||
size = ftell(f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return size;
|
return size;
|
||||||
}
|
|
||||||
|
|
||||||
bool romIsCia(char const* fpath)
|
|
||||||
{
|
|
||||||
if (!fpath) return false;
|
|
||||||
return (strstr(fpath, ".cia") != NULL || strstr(fpath, ".CIA") != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool romIsTad(char const* fpath)
|
|
||||||
{
|
|
||||||
if (!fpath) return false;
|
|
||||||
return (strstr(fpath, ".tad") != NULL || strstr(fpath, ".TAD") != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isDsiHeader(tDSiHeader* h)
|
|
||||||
{
|
|
||||||
if (!h) return false;
|
|
||||||
|
|
||||||
u16 crc16 = swiCRC16(0xFFFF, h, 0x15E);
|
|
||||||
|
|
||||||
return h->ndshdr.headerCRC16 == crc16;
|
|
||||||
}
|
}
|
||||||
@ -17,7 +17,6 @@ void printRomInfo(char const* fpath);
|
|||||||
|
|
||||||
unsigned long long getRomSize(char const* fpath);
|
unsigned long long getRomSize(char const* fpath);
|
||||||
|
|
||||||
bool romIsCia(char const* fpath);
|
bool romIsSrl(char const* fpath);
|
||||||
bool isDsiHeader(tDSiHeader* h);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -440,6 +440,7 @@ int getMenuSlotsFree()
|
|||||||
const char* dirs[] = {
|
const char* dirs[] = {
|
||||||
"00030004",
|
"00030004",
|
||||||
"00030005",
|
"00030005",
|
||||||
|
"0003000f",
|
||||||
"00030015",
|
"00030015",
|
||||||
"00030017"
|
"00030017"
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include "tad.h"
|
#include "tad.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
|
#include "rom.h"
|
||||||
|
#include "main.h"
|
||||||
#include "nand/twltool/dsi.h"
|
#include "nand/twltool/dsi.h"
|
||||||
#include <nds/ndstypes.h>
|
#include <nds/ndstypes.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
@ -41,6 +43,7 @@ const unsigned char debuggerKey[] = {
|
|||||||
0xA2, 0xFD, 0xDD, 0xF2 ,0xE4, 0x23, 0x57, 0x4A,
|
0xA2, 0xFD, 0xDD, 0xF2 ,0xE4, 0x23, 0x57, 0x4A,
|
||||||
0xE7, 0xED, 0x86, 0x57, 0xB5, 0xAB, 0x19, 0xD3
|
0xE7, 0xED, 0x86, 0x57, 0xB5, 0xAB, 0x19, 0xD3
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t hdrSize;
|
uint32_t hdrSize;
|
||||||
uint16_t tadType;
|
uint16_t tadType;
|
||||||
@ -174,7 +177,7 @@ int decryptTad(char const* src)
|
|||||||
iprintf("\n--------------------------------\nCopying output files:\n");
|
iprintf("\n--------------------------------\nCopying output files:\n");
|
||||||
// Sorry for copy pasting, I'll make this a routine later
|
// Sorry for copy pasting, I'll make this a routine later
|
||||||
iprintf(" Copying TMD...\n");
|
iprintf(" Copying TMD...\n");
|
||||||
FILE *tmdFile = fopen("sd:/_nds/tadtests/tmp/tmd.srl", "wb");
|
FILE *tmdFile = fopen("sd:/_nds/tadtests/tmp/temp.tmd", "wb");
|
||||||
fseek(file, tad.tmdOffset, SEEK_SET);
|
fseek(file, tad.tmdOffset, SEEK_SET);
|
||||||
for (int i = 0; i < swap_endian_u32(header.tmdSize); i++) {
|
for (int i = 0; i < swap_endian_u32(header.tmdSize); i++) {
|
||||||
char ch = fgetc(file);
|
char ch = fgetc(file);
|
||||||
@ -183,7 +186,7 @@ int decryptTad(char const* src)
|
|||||||
fclose(tmdFile);
|
fclose(tmdFile);
|
||||||
|
|
||||||
iprintf(" Copying ticket...\n");
|
iprintf(" Copying ticket...\n");
|
||||||
FILE *ticketFile = fopen("sd:/_nds/tadtests/tmp/ticket.srl", "wb");
|
FILE *ticketFile = fopen("sd:/_nds/tadtests/tmp/temp.tik", "wb");
|
||||||
fseek(file, tad.ticketOffset, SEEK_SET);
|
fseek(file, tad.ticketOffset, SEEK_SET);
|
||||||
for (int i = 0; i < swap_endian_u32(header.ticketSize); i++) {
|
for (int i = 0; i < swap_endian_u32(header.ticketSize); i++) {
|
||||||
char ch = fgetc(file);
|
char ch = fgetc(file);
|
||||||
@ -192,7 +195,7 @@ int decryptTad(char const* src)
|
|||||||
fclose(ticketFile);
|
fclose(ticketFile);
|
||||||
|
|
||||||
iprintf(" Copying SRL...\n");
|
iprintf(" Copying SRL...\n");
|
||||||
FILE *srlFile = fopen("sd:/_nds/tadtests/tmp/srl_enc.srl", "wb");
|
FILE *srlFile = fopen("sd:/_nds/tadtests/tmp/temp.srl.enc", "wb");
|
||||||
fseek(file, tad.srlOffset, SEEK_SET);
|
fseek(file, tad.srlOffset, SEEK_SET);
|
||||||
for (int i = 0; i < swap_endian_u32(header.srlSize); i++) {
|
for (int i = 0; i < swap_endian_u32(header.srlSize); i++) {
|
||||||
char ch = fgetc(file);
|
char ch = fgetc(file);
|
||||||
@ -209,7 +212,7 @@ int decryptTad(char const* src)
|
|||||||
|
|
||||||
iprintf("Decrypting SRL:\n\n");
|
iprintf("Decrypting SRL:\n\n");
|
||||||
iprintf(" Finding title key...\n");
|
iprintf(" Finding title key...\n");
|
||||||
FILE *ticket = fopen("sd:/_nds/tadtests/tmp/ticket.srl", "rb");
|
FILE *ticket = fopen("sd:/_nds/tadtests/tmp/temp.tik", "rb");
|
||||||
unsigned char title_key_enc[16];
|
unsigned char title_key_enc[16];
|
||||||
fseek(ticket, 447, SEEK_SET);
|
fseek(ticket, 447, SEEK_SET);
|
||||||
fread(title_key_enc, 1, 16, ticket);
|
fread(title_key_enc, 1, 16, ticket);
|
||||||
@ -251,19 +254,22 @@ int decryptTad(char const* src)
|
|||||||
iprintf("\n Decrypting SRL chunks...\n");
|
iprintf("\n Decrypting SRL chunks...\n");
|
||||||
unsigned char srl_buffer_enc[16];
|
unsigned char srl_buffer_enc[16];
|
||||||
unsigned char srl_buffer_dec[16];
|
unsigned char srl_buffer_dec[16];
|
||||||
|
// Should be fine as a hardcoded string. Content IV is based off of the content index. (index # with zerobyte padding)
|
||||||
|
// All TADs I've only ever a single content. It might be a good idea to add something down the line in case a weird
|
||||||
|
// TAD pops up, but until then this should do.
|
||||||
unsigned char content_iv[] = {
|
unsigned char content_iv[] = {
|
||||||
0x00, 0x00, 0x00, 0x00 ,0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00 ,0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
};
|
};
|
||||||
FILE *srlFile_enc = fopen("sd:/_nds/tadtests/tmp/srl_enc.srl", "rb");
|
FILE *srlFile_enc = fopen("sd:/_nds/tadtests/tmp/temp.srl.enc", "rb");
|
||||||
fseek(srlFile_enc, 0, SEEK_SET);
|
fseek(srlFile_enc, 0, SEEK_SET);
|
||||||
FILE *srlFile_dec = fopen("sd:/_nds/tadtests/tmp/tad.srl", "wb");
|
FILE *srlFile_dec = fopen("sd:/_nds/tadtests/tmp/temp.srl", "wb");
|
||||||
fseek(srlFile_dec, 0, SEEK_SET);
|
fseek(srlFile_dec, 0, SEEK_SET);
|
||||||
|
|
||||||
for (int i = 0; i < swap_endian_u32(header.srlSize);) {
|
for (int i = 0; i < swap_endian_u32(header.srlSize);) {
|
||||||
fread(srl_buffer_enc, 1, 16, srlFile_enc);
|
fread(srl_buffer_enc, 1, 16, srlFile_enc);
|
||||||
/* ===== silly debug ===== */
|
/* ===== silly debug ===== */
|
||||||
iprintf("%ld - %d / %ld", ftell(file), i, swap_endian_u32(header.srlSize));
|
iprintf("%ld - %d / %ld\n", ftell(file), i, swap_endian_u32(header.srlSize));
|
||||||
/* ===== end of debug ===== */
|
/* ===== end of debug ===== */
|
||||||
|
|
||||||
decrypt_cbc(title_key_dec, content_iv, srl_buffer_enc, 16, 16, srl_buffer_dec);
|
decrypt_cbc(title_key_dec, content_iv, srl_buffer_enc, 16, 16, srl_buffer_dec);
|
||||||
@ -272,9 +278,75 @@ int decryptTad(char const* src)
|
|||||||
}
|
}
|
||||||
fclose(srlFile_enc);
|
fclose(srlFile_enc);
|
||||||
fclose(srlFile_dec);
|
fclose(srlFile_dec);
|
||||||
iprintf("\nDone everything!");
|
iprintf("\nReady to install!");
|
||||||
|
return "sd:/_nds/tadtests/tmp/temp.srl";
|
||||||
|
}
|
||||||
|
|
||||||
//return copyFilePart(src, 0, size, dst);
|
void printTadInfo(char const* fpath)
|
||||||
return 0;
|
{
|
||||||
|
clearScreen(&topScreen);
|
||||||
|
if (!fpath) return;
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t srlCompany;
|
||||||
|
uint32_t srlTidLow;
|
||||||
|
uint32_t srlTidHigh;
|
||||||
|
unsigned char srlVerLow = 0x00;
|
||||||
|
unsigned char srlVerHigh = 0x00;
|
||||||
|
|
||||||
|
FILE *file = fopen(fpath, "rb");
|
||||||
|
Header header;
|
||||||
|
fread(&header, sizeof(Header), 1, file);
|
||||||
|
iprintf("Parsing TAD header:\n");
|
||||||
|
Tad tad;
|
||||||
|
tad.hdrOffset = 0;
|
||||||
|
// All offsets in the TAD are aligned to 64 bytes.
|
||||||
|
tad.certOffset = round_up(swap_endian_u32(header.hdrSize), 64);
|
||||||
|
tad.crlOffset = round_up(tad.certOffset + swap_endian_u32(header.certSize), 64);
|
||||||
|
tad.ticketOffset = round_up(tad.crlOffset + swap_endian_u32(header.crlSize), 64);
|
||||||
|
tad.tmdOffset = round_up(tad.ticketOffset + swap_endian_u32(header.ticketSize), 64);
|
||||||
|
tad.srlOffset = round_up(tad.tmdOffset + swap_endian_u32(header.tmdSize), 64);
|
||||||
|
tad.metaOffset = round_up(tad.srlOffset + swap_endian_u32(header.srlSize), 64);
|
||||||
|
// Get info from TMD.
|
||||||
|
fseek(file, swap_endian_u32(tad.tmdOffset)+396, SEEK_SET);
|
||||||
|
fread(srlTidHigh, 1, 4, file);
|
||||||
|
fread(srlTidLow, 1, 4, file);
|
||||||
|
fseek(file, swap_endian_u32(tad.tmdOffset)+408, SEEK_SET);
|
||||||
|
fread(srlCompany, 1, 4, file);
|
||||||
|
fseek(file, swap_endian_u32(tad.tmdOffset)+476, SEEK_SET);
|
||||||
|
fread(srlVerHigh, 1, 1, file);
|
||||||
|
fread(srlVerLow, 1, 1, file);
|
||||||
|
|
||||||
|
iprintf(" tadVersion: %u\n", swap_endian_u16(header.tadVersion));
|
||||||
|
iprintf(" certSize: %lu\n", swap_endian_u32(header.certSize));
|
||||||
|
iprintf(" certOffset: %lu\n", tad.certOffset);
|
||||||
|
iprintf(" crlSize: %lu\n", swap_endian_u32(header.crlSize));
|
||||||
|
iprintf(" crlOffset: %lu\n", tad.crlOffset);
|
||||||
|
iprintf(" ticketSize: %lu\n", swap_endian_u32(header.ticketSize));
|
||||||
|
iprintf(" ticketOffset: %lu\n", tad.ticketOffset);
|
||||||
|
iprintf(" tmdSize: %lu\n", swap_endian_u32(header.tmdSize));
|
||||||
|
iprintf(" tmdOffset: %lu\n", tad.tmdOffset);
|
||||||
|
iprintf(" srlSize: %lu\n", swap_endian_u32(header.srlSize));
|
||||||
|
iprintf(" srlOffset: %lu\n", tad.srlOffset);
|
||||||
|
iprintf(" metaSize: %lu\n", swap_endian_u32(header.metaSize));
|
||||||
|
iprintf(" metaOffset: %lu\n", tad.metaOffset);
|
||||||
|
|
||||||
|
//proper title
|
||||||
|
// TODO! Might not be possible though :((
|
||||||
|
|
||||||
|
//size in blocks, rounded up
|
||||||
|
iprintf("Size: (%ld blocks)\n", ((swap_endian_u32(header.srlSize) / BYTES_PER_BLOCK) * BYTES_PER_BLOCK + BYTES_PER_BLOCK) / BYTES_PER_BLOCK);
|
||||||
|
|
||||||
|
iprintf("Game Code: %c\n", (char)srlTidLow);
|
||||||
|
|
||||||
|
iprintf("Game Version: %u.%u (NUS: v%u)\n", srlVerHigh * 256, srlVerLow, (srlVerHigh * 256) + srlVerLow);
|
||||||
|
|
||||||
|
iprintf("Company Code: %c (%lu)\n", (char)srlCompany, srlCompany);
|
||||||
|
|
||||||
|
// Print program type based on TID high?
|
||||||
|
iprintf("Title ID: %08lx %08lx", srlTidHigh, srlTidLow);
|
||||||
|
|
||||||
|
//print full file path
|
||||||
|
iprintf("\n%s\n", fpath);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -92,6 +92,7 @@ static void generateList(Menu* m)
|
|||||||
const char* dirs[] = {
|
const char* dirs[] = {
|
||||||
"00030004",
|
"00030004",
|
||||||
"00030005",
|
"00030005",
|
||||||
|
//"0003000f",
|
||||||
"00030015",
|
"00030015",
|
||||||
"00030017"
|
"00030017"
|
||||||
};
|
};
|
||||||
@ -100,17 +101,12 @@ static void generateList(Menu* m)
|
|||||||
{ // 00030004
|
{ // 00030004
|
||||||
NULL //nothing blacklisted
|
NULL //nothing blacklisted
|
||||||
},
|
},
|
||||||
{ // 00030005
|
{ // 0003000f
|
||||||
"484e44", // DS Download Play
|
"484e43", // WiFi Firmware
|
||||||
"484e45", // PictoChat
|
|
||||||
"484e49", // Nintendo DSi Camera
|
|
||||||
"484e4a", // Nintendo Zone
|
|
||||||
"484e4b", // Nintendo DSi Sound
|
|
||||||
NULL
|
NULL
|
||||||
},
|
},
|
||||||
{ // 00030015
|
{ // 00030015
|
||||||
"484e42", // System Settings
|
"484e42", // System Settings
|
||||||
"484e46", // Nintendo DSi Shop
|
|
||||||
NULL
|
NULL
|
||||||
},
|
},
|
||||||
{ // 00030017
|
{ // 00030017
|
||||||
@ -159,8 +155,7 @@ static void generateList(Menu* m)
|
|||||||
blacklisted = true;
|
blacklisted = true;
|
||||||
|
|
||||||
// also blacklist specific all-region titles
|
// also blacklist specific all-region titles
|
||||||
if ((strcmp("484e4441", ent->d_name) == 0) || // Download Play
|
if ((strcmp("484e4341", ent->d_name) == 0) || // WiFi Firmware
|
||||||
(strcmp("484e4541", ent->d_name) == 0) || // PictoChat
|
|
||||||
(strcmp("34544e41", ent->d_name) == 0)) // TwlNmenu
|
(strcmp("34544e41", ent->d_name) == 0)) // TwlNmenu
|
||||||
blacklisted = true;
|
blacklisted = true;
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
icon.bmp
BIN
icon.bmp
Binary file not shown.
|
Before Width: | Height: | Size: 586 B After Width: | Height: | Size: 2.1 KiB |
Loading…
Reference in New Issue
Block a user