mirror of
https://github.com/rvtr/unlaunch-installer_dev.git
synced 2026-01-26 13:43:08 -05:00
385 lines
11 KiB
C
385 lines
11 KiB
C
#include "main.h"
|
|
#include "menu.h"
|
|
#include "message.h"
|
|
#include "nand/nandio.h"
|
|
#include "storage.h"
|
|
#include "version.h"
|
|
#include "unlaunch.h"
|
|
#include <errno.h>
|
|
#include <dirent.h>
|
|
#include <time.h>
|
|
|
|
bool programEnd = false;
|
|
bool sdnandMode = true;
|
|
bool retailLauncherTmdPresentAndToBePatched = true;
|
|
bool retailConsole = true;
|
|
bool unlaunchInstallerFound = false;
|
|
bool unlaunchFound = false;
|
|
bool unlaunchPatches = false;
|
|
bool devkpFound = false;
|
|
bool launcherDSiFound = false;
|
|
bool arm7Exiting = false;
|
|
bool charging = false;
|
|
u8 batteryLevel = 0;
|
|
u8 region = 0xFF;
|
|
|
|
PrintConsole topScreen;
|
|
PrintConsole bottomScreen;
|
|
|
|
enum {
|
|
MAIN_MENU_MODE,
|
|
MAIN_MENU_INSTALL,
|
|
MAIN_MENU_SAFE_UNLAUNCH_UNINSTALL,
|
|
MAIN_MENU_SAFE_UNLAUNCH_INSTALL,
|
|
MAIN_MENU_TITLES,
|
|
MAIN_MENU_BACKUP,
|
|
MAIN_MENU_TEST,
|
|
MAIN_MENU_FIX,
|
|
MAIN_MENU_DATA_MANAGEMENT,
|
|
MAIN_MENU_LANGUAGE_PATCHER,
|
|
MAIN_MENU_EXIT
|
|
};
|
|
|
|
static void _setupScreens()
|
|
{
|
|
REG_DISPCNT = MODE_FB0;
|
|
VRAM_A_CR = VRAM_ENABLE;
|
|
|
|
videoSetMode(MODE_0_2D);
|
|
videoSetModeSub(MODE_0_2D);
|
|
|
|
vramSetBankA(VRAM_A_MAIN_BG);
|
|
vramSetBankC(VRAM_C_SUB_BG);
|
|
|
|
consoleInit(&topScreen, 3, BgType_Text4bpp, BgSize_T_256x256, 31, 0, true, true);
|
|
consoleInit(&bottomScreen, 3, BgType_Text4bpp, BgSize_T_256x256, 31, 0, false, true);
|
|
|
|
clearScreen(&bottomScreen);
|
|
|
|
VRAM_A[100] = 0xFFFF;
|
|
}
|
|
|
|
static int _mainMenu(int cursor)
|
|
{
|
|
//top screen
|
|
clearScreen(&topScreen);
|
|
|
|
iprintf("\t\tNAND Title Manager\n");
|
|
iprintf("\t\t\tmodified from\n");
|
|
iprintf("\tTitle Manager for HiyaCFW\n");
|
|
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\t \x1B[46mhttps://dsi.cfw.guide\x1B[47m\n");
|
|
iprintf("\n\n \x1B[46mgithub.com/Epicpkmn11/NTM/wiki\x1B[47m\n");
|
|
iprintf("\x1b[22;0HJeff - 2018-2019");
|
|
iprintf("\x1b[23;0HPk11 - 2022-2023");
|
|
|
|
//menu
|
|
Menu* m = newMenu();
|
|
setMenuHeader(m, "MAIN MENU");
|
|
|
|
char modeStr[32], datamanStr[32], launcherStr[32];
|
|
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, "Install", NULL, 0);
|
|
addMenuItem(m, "Safe unlaunch uninstall", NULL, 0);
|
|
addMenuItem(m, "Safe unlaunch install", NULL, 0);
|
|
addMenuItem(m, "Titles", NULL, 0);
|
|
addMenuItem(m, "Restore", NULL, 0);
|
|
addMenuItem(m, "Test", 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);
|
|
|
|
m->cursor = cursor;
|
|
|
|
//bottom screen
|
|
printMenu(m);
|
|
|
|
while (!programEnd)
|
|
{
|
|
swiWaitForVBlank();
|
|
scanKeys();
|
|
|
|
if (moveCursor(m))
|
|
printMenu(m);
|
|
|
|
if (keysDown() & KEY_A)
|
|
break;
|
|
}
|
|
|
|
int result = m->cursor;
|
|
freeMenu(m);
|
|
|
|
return result;
|
|
}
|
|
|
|
void fifoHandlerPower(u32 value32, void* userdata)
|
|
{
|
|
if (value32 == 0x54495845) // 'EXIT'
|
|
{
|
|
programEnd = true;
|
|
arm7Exiting = true;
|
|
}
|
|
}
|
|
|
|
void fifoHandlerBattery(u32 value32, void* userdata)
|
|
{
|
|
batteryLevel = value32 & 0xF;
|
|
charging = (value32 & BIT(7)) != 0;
|
|
}
|
|
|
|
bool checkIfUnlaunchHasPatches(const char* path)
|
|
{
|
|
//check if launcher patches are enabled
|
|
const static u32 tidValues[][2] = {
|
|
// {location, value}
|
|
{0xE439, 0x382E3176}, // 1.8
|
|
{0xB07C, 0x17484E41}, // 1.9
|
|
{0xB099, 0x17484E41}, // 2.0 (Normal)
|
|
{0xB079, 0x484E1841}, // 2.0 (Patched)
|
|
};
|
|
|
|
bool patched = false;
|
|
|
|
FILE *tmd = fopen(path, "rb");
|
|
if (tmd)
|
|
{
|
|
for (int i = 0; i < sizeof(tidValues) / sizeof(tidValues[0]); i++)
|
|
{
|
|
if (fseek(tmd, tidValues[i][0], SEEK_SET) == 0)
|
|
{
|
|
u32 tidVal;
|
|
fread(&tidVal, sizeof(u32), 1, tmd);
|
|
if (tidVal == tidValues[i][1])
|
|
{
|
|
patched = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fclose(tmd);
|
|
return patched;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
srand(time(0));
|
|
keysSetRepeat(25, 5);
|
|
_setupScreens();
|
|
|
|
fifoSetValue32Handler(FIFO_USER_01, fifoHandlerPower, NULL);
|
|
fifoSetValue32Handler(FIFO_USER_03, fifoHandlerBattery, NULL);
|
|
|
|
//DSi check
|
|
if (!isDSiMode())
|
|
{
|
|
messageBox("\x1B[31mError:\x1B[33m This app is only for DSi.");
|
|
return 0;
|
|
}
|
|
|
|
//setup sd card access
|
|
if (!fatInitDefault())
|
|
{
|
|
messageBox("fatInitDefault()...\x1B[31mFailed\n\x1B[47m");
|
|
return 0;
|
|
}
|
|
|
|
//setup nand access
|
|
if (!fatMountSimple("nand", &io_dsi_nand))
|
|
{
|
|
messageBox("nand init \x1B[31mfailed\n\x1B[47m");
|
|
return 0;
|
|
}
|
|
|
|
unlaunchInstallerFound = (access("sd:/unlaunch.dsi", F_OK) == 0);
|
|
|
|
//check for unlaunch and region
|
|
char retailLauncherTmdPath[64];
|
|
const char* hnaaTmdPath = "nand:/title/00030017/484e4141/content/title.tmd";
|
|
{
|
|
FILE* file = fopen("nand:/sys/HWINFO_S.dat", "rb");
|
|
if (file)
|
|
{
|
|
fseek(file, 0xA0, SEEK_SET);
|
|
u32 launcherTid;
|
|
fread(&launcherTid, sizeof(u32), 1, file);
|
|
fclose(file);
|
|
|
|
region = launcherTid & 0xFF;
|
|
|
|
sprintf(retailLauncherTmdPath, "nand:/title/00030017/%08lx/content/title.tmd", launcherTid);
|
|
unsigned long long tmdSize = getFileSizePath(retailLauncherTmdPath);
|
|
if (tmdSize > 520)
|
|
{
|
|
unlaunchFound = true;
|
|
unlaunchPatches = checkIfUnlaunchHasPatches(retailLauncherTmdPath);
|
|
}
|
|
else if(tmdSize != 520)
|
|
{
|
|
//if size isn't 520 then the tmd either is not present (size 0), or is already invalid, thus no need to patch
|
|
retailLauncherTmdPresentAndToBePatched = false;
|
|
}
|
|
// HWINFO_S may not always exist (PRE_IMPORT). Fill in defaults if that happens.
|
|
}
|
|
|
|
// I own and know of many people with retail and dev prototypes
|
|
// These can normally be identified by having the region set to ALL (0x41)
|
|
retailConsole = (region != 0x41 && region != 0xFF);
|
|
|
|
if (!unlaunchFound)
|
|
{
|
|
unsigned long long tmdSize = getFileSizePath(hnaaTmdPath);
|
|
if (tmdSize > 520)
|
|
{
|
|
unlaunchFound = true;
|
|
unlaunchPatches = checkIfUnlaunchHasPatches(hnaaTmdPath);
|
|
}
|
|
}
|
|
|
|
if (!unlaunchFound)
|
|
{
|
|
messageBox("Unlaunch not found. TMD files\nwill be required and there\nis a greater risk something\ncould go wrong.\n\nSee \x1B[46mhttps://dsi.cfw.guide/\x1B[47m to\ninstall.");
|
|
}
|
|
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");
|
|
}
|
|
}
|
|
|
|
//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("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");
|
|
//main menu
|
|
int cursor = 0;
|
|
|
|
while (!programEnd)
|
|
{
|
|
cursor = _mainMenu(cursor);
|
|
|
|
switch (cursor)
|
|
{
|
|
case MAIN_MENU_MODE:
|
|
sdnandMode = !sdnandMode;
|
|
devkpFound = (access(sdnandMode ? "sd:/sys/dev.kp" : "nand:/sys/dev.kp", F_OK) == 0);
|
|
break;
|
|
|
|
case MAIN_MENU_INSTALL:
|
|
installMenu();
|
|
break;
|
|
|
|
case MAIN_MENU_SAFE_UNLAUNCH_UNINSTALL:
|
|
if(!unlaunchFound)
|
|
{
|
|
messageBox("\x1B[31mError:\x1B[33m Unlaunch is not installed\n");
|
|
} else if(nandio_unlock_writing()) {
|
|
if(uninstallUnlaunch(retailConsole, retailLauncherTmdPath))
|
|
{
|
|
messageBox("Uninstall successful!\n");
|
|
} else {
|
|
messageBox("\x1B[31mError:\x1B[33m Uninstall failed\n");
|
|
}
|
|
nandio_lock_writing();
|
|
}
|
|
break;
|
|
|
|
case MAIN_MENU_SAFE_UNLAUNCH_INSTALL:
|
|
if (unlaunchInstallerFound && (choiceBox("Install unlaunch?") == YES)
|
|
&& (retailLauncherTmdPresentAndToBePatched || (choiceBox("There doesn't seem to be a launcher.tmd\nfile matcing the hwinfo file\nKeep installing?") == YES))
|
|
&& nandio_unlock_writing())
|
|
{
|
|
if(installUnlaunch(retailConsole, retailLauncherTmdPresentAndToBePatched ? retailLauncherTmdPath : NULL))
|
|
{
|
|
messageBox("Install successful!\n");
|
|
} else {
|
|
messageBox("\x1B[31mError:\x1B[33m Install failed\n");
|
|
}
|
|
nandio_lock_writing();
|
|
}
|
|
break;
|
|
|
|
case MAIN_MENU_TITLES:
|
|
titleMenu();
|
|
break;
|
|
|
|
case MAIN_MENU_BACKUP:
|
|
backupMenu();
|
|
break;
|
|
|
|
case MAIN_MENU_TEST:
|
|
testMenu();
|
|
break;
|
|
|
|
case MAIN_MENU_FIX:
|
|
if (nandio_unlock_writing())
|
|
{
|
|
nandio_force_fat_fix();
|
|
nandio_lock_writing();
|
|
messageBox("Mismatch in FAT copies will be\nfixed on close.\n");
|
|
}
|
|
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:
|
|
programEnd = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
clearScreen(&bottomScreen);
|
|
printf("Unmounting NAND...\n");
|
|
fatUnmount("nand:");
|
|
printf("Merging stages...\n");
|
|
nandio_shutdown();
|
|
|
|
fifoSendValue32(FIFO_USER_02, 0x54495845); // 'EXIT'
|
|
|
|
while (arm7Exiting)
|
|
swiWaitForVBlank();
|
|
|
|
return 0;
|
|
}
|
|
|
|
void clearScreen(PrintConsole* screen)
|
|
{
|
|
consoleSelect(screen);
|
|
consoleClear();
|
|
} |