diff --git a/Makefile b/Makefile index 9d44a2f..fd7e2d6 100644 --- a/Makefile +++ b/Makefile @@ -53,6 +53,7 @@ $(TARGET).dsi : $(NITRO_FILES) arm7/$(TARGET).elf arm9/$(TARGET).elf -g "$(GAME_CODE)" "00" "$(GAME_LABEL)" \ -b $(GAME_ICON) "$(GAME_TITLE);$(GAME_SUBTITLE1)" \ $(_ADDFILES) + cp $(TARGET).dsi ntrboot.nds #--------------------------------------------------------------------------------- arm7/$(TARGET).elf: @@ -66,4 +67,4 @@ arm9/$(TARGET).elf: clean: $(MAKE) -C arm9 clean $(MAKE) -C arm7 clean - rm -f $(TARGET).dsi $(TARGET).arm7 $(TARGET).arm9 + rm -f $(TARGET).dsi $(TARGET).arm7 $(TARGET).arm9 ntrboot.nds diff --git a/arm9/Makefile b/arm9/Makefile index 7110017..d464ce4 100644 --- a/arm9/Makefile +++ b/arm9/Makefile @@ -31,7 +31,7 @@ CFLAGS := -g -Wall -O2\ $(ARCH) CFLAGS += $(INCLUDE) -DARM9 -CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++23 +CXXFLAGS := $(CFLAGS) -fno-rtti -fexceptions -std=gnu++23 -Wno-psabi ASFLAGS := -g $(ARCH) -march=armv5te -mtune=arm946e-s diff --git a/arm9/include/version.h b/arm9/include/version.h index 8222156..3458667 100644 --- a/arm9/include/version.h +++ b/arm9/include/version.h @@ -1,6 +1,6 @@ #ifndef VERSION_H #define VERSION_H -#define VERSION "v0.1" +#define VERSION "v1.0" #endif // VERSION_H diff --git a/arm9/src/consoleInfo.h b/arm9/src/consoleInfo.h new file mode 100644 index 0000000..20eb3d4 --- /dev/null +++ b/arm9/src/consoleInfo.h @@ -0,0 +1,27 @@ +#ifndef CONSOLE_INFO_H +#define CONSOLE_INFO_H + +#include +#include +#include + +#include "sha1digest.h" +#include "nocashFooter.h" + +struct consoleInfo { + bool isRetail{true}; + bool tmdPatched{false}; + bool tmdInvalid{false}; + bool tmdFound{true}; + bool tmdGood{false}; + bool UnlaunchHNAAtmdFound{false}; + bool needsNocashFooterToBeWritten{false}; + uint32_t launcherVersion{0}; + std::string launcherTmdPath; + std::string launcherAppPath; + std::array recoveryTmdData; + Sha1Digest recoveryTmdDataSha; + NocashFooter nocashFooter; +}; + +#endif diff --git a/arm9/src/main.c b/arm9/src/main.c deleted file mode 100644 index 27ee73f..0000000 --- a/arm9/src/main.c +++ /dev/null @@ -1,561 +0,0 @@ -#include "bgMenu.h" -#include "main.h" -#include "menu.h" -#include "message.h" -#include "nand/nandio.h" -#include "storage.h" -#include "version.h" -#include "unlaunch.h" -#include "nitrofs.h" -#include "deviceList.h" -#include "nocashFooter.h" - -volatile bool programEnd = false; -static volatile bool arm7Exiting = false; -static bool unlaunchFound = false; -static bool hnaaUnlaunchFound = false; -static bool retailLauncherTmdPresentAndToBePatched = true; -static bool retailConsole = true; -static UNLAUNCH_VERSION foundUnlaunchInstallerVersion = INVALID; -static bool disableAllPatches = false; -static bool enableSoundAndSplash = false; -static const char* splashSoundBinaryPatchPath = NULL; -static const char* customBgPath = NULL; -volatile bool charging = false; -volatile u8 batteryLevel = 0; -static bool advancedOptionsUnlocked = false; -static bool needsNocashFooterToBeWritten = false; -static bool isLauncherVersionSupported = true; -static NocashFooter computedNocashFooter; - -PrintConsole topScreen; -PrintConsole bottomScreen; - -enum { - MAIN_MENU_SAFE_UNLAUNCH_UNINSTALL, - MAIN_MENU_CUSTOM_BG, - MAIN_MENU_SOUND_SPLASH_PATCHES, - MAIN_MENU_SAFE_UNLAUNCH_INSTALL, - MAIN_MENU_EXIT, - MAIN_MENU_SAFE_UNLAUNCH_UNINSTALL_NO_BACKUP, - MAIN_MENU_WRITE_NOCASH_FOOTER_ONLY, - MAIN_MENU_TID_PATCHES, -}; - -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\"Safe\" unlaunch installer\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("\x1b[23;0Hedo9300 - 2024"); - - //menu - Menu* m = newMenu(); - setMenuHeader(m, "MAIN MENU"); - - char soundPatchesStr[64], tidPatchesStr[32], installUnlaunchStr[32]; - sprintf(tidPatchesStr, "Disable all patches: %s", - disableAllPatches ? "On" : "Off"); - sprintf(soundPatchesStr, "Enable sound and splash: %s", - enableSoundAndSplash ? "On" : "Off"); - if(foundUnlaunchInstallerVersion != INVALID) - { - sprintf(installUnlaunchStr, "Install unlaunch (%s)", getUnlaunchVersionString(foundUnlaunchInstallerVersion)); - } - else - { - strcpy(installUnlaunchStr, "Install unlaunch"); - } - addMenuItem(m, "Uninstall unlaunch", NULL, unlaunchFound && isLauncherVersionSupported, false); - addMenuItem(m, "Custom background", NULL, foundUnlaunchInstallerVersion != INVALID && isLauncherVersionSupported, true); - addMenuItem(m, soundPatchesStr, NULL, foundUnlaunchInstallerVersion == v2_0 && !disableAllPatches && splashSoundBinaryPatchPath != NULL && isLauncherVersionSupported, false); - addMenuItem(m, installUnlaunchStr, NULL, foundUnlaunchInstallerVersion != INVALID && !unlaunchFound && isLauncherVersionSupported, false); - addMenuItem(m, "Exit", NULL, true, false); - if(!isLauncherVersionSupported) - { - addMenuItem(m, "Uninstall unlaunch no backup", NULL, unlaunchFound, false); - } - else if(advancedOptionsUnlocked) - { - addMenuItem(m, "Uninstall unlaunch no backup", NULL, unlaunchFound, false); - addMenuItem(m, "Write nocash footer", NULL, needsNocashFooterToBeWritten, false); - addMenuItem(m, tidPatchesStr, NULL, (foundUnlaunchInstallerVersion == v1_9 || foundUnlaunchInstallerVersion == v2_0) && isLauncherVersionSupported, false); - } - - m->cursor = cursor; - - //bottom screen - printMenu(m); - - int konamiCode = 0; - bool konamiCodeCooldown = false; - - while (!programEnd) - { - swiWaitForVBlank(); - scanKeys(); - - if (moveCursor(m)) - printMenu(m); - - if (keysDown() & KEY_A) - break; - - if(advancedOptionsUnlocked) - continue; - - int held = keysHeld(); - - if ((held & (KEY_L | KEY_R | KEY_Y)) == (KEY_L | KEY_R | KEY_Y)) - { - if(held == (KEY_L | KEY_R | KEY_Y) && !konamiCodeCooldown) - { - konamiCodeCooldown = true; - ++konamiCode; - } - } - else - { - konamiCodeCooldown = false; - } - if (konamiCode == 5) - { - advancedOptionsUnlocked = true; - // Enabled by default when unsupported - if(isLauncherVersionSupported) - { - addMenuItem(m, "Uninstall unlaunch no backup", NULL, unlaunchFound, false); - } - addMenuItem(m, "Write nocash footer", NULL, needsNocashFooterToBeWritten, false); - addMenuItem(m, tidPatchesStr, NULL, (foundUnlaunchInstallerVersion == v1_9 || foundUnlaunchInstallerVersion == v2_0) && isLauncherVersionSupported, false); - } - } - - int result = m->cursor; - freeMenu(m); - - return result; -} - -static void fifoHandlerPower(u32 value32, void* userdata) -{ - if (value32 == 0x54495845) // 'EXIT' - { - programEnd = true; - arm7Exiting = true; - } -} - -static void fifoHandlerBattery(u32 value32, void* userdata) -{ - batteryLevel = value32 & 0xF; - charging = (value32 & BIT(7)) != 0; -} - -int main(int argc, char **argv) -{ - 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 exclusively for DSi."); - return 0; - } - - //setup sd card access - if (!fatInitDefault()) - { - messageBox("fatInitDefault()...\x1B[31mFailed\n\x1B[47m"); - } - - u32 clusterSize = getClusterSizeForPartition("sd:/"); - if(clusterSize > 32768) - { - messageBox("Sd card cluster size is too large"); - return 0; - } - - //setup nand access - if (!fatMountSimple("nand", &io_dsi_nand)) - { - messageBox("nand init \x1B[31mfailed\n\x1B[47m"); - return 0; - } - - NocashFooter footer; - - nandio_read_nocash_footer(&footer); - nandio_construct_nocash_footer(&computedNocashFooter); - - if(!(needsNocashFooterToBeWritten = !isFooterValid(&footer))) - { - if(memcmp(&footer, &computedNocashFooter, sizeof(footer)) != 0) - { - messageBox("\x1B[31mError:\x1B[33m This console has a\n" - "nocash footer embedded in its\n" - "nand that doesn't match the one\n" - "generated.\n" - "The footer already present will\n" - "be overwritten."); - needsNocashFooterToBeWritten = true; - } - } - - while (batteryLevel < 7 && !charging) - { - if (choiceBox("\x1B[47mBattery is too low!\nPlease plug in the console.\n\nContinue?") == NO) - return 0; - } - - DeviceList* deviceList = getDeviceList(); - - const char* installerPath = (argc > 0) ? argv[0] : (deviceList ? deviceList->appname : "sd:/ntrboot.nds"); - - if (!nitroFSInit(installerPath)) - { - messageBox("nitroFSInit()...\x1B[31mFailed\n\x1B[47m"); - } - - if (fileExists("sd:/unlaunch.dsi")) - { - foundUnlaunchInstallerVersion = loadUnlaunchInstaller("sd:/unlaunch.dsi"); - if (foundUnlaunchInstallerVersion == INVALID) - { - messageBox("\x1B[41mWARNING:\x1B[47m Failed to load unlaunch.dsi\n" - "from the root of the sd card.\n" - "Attempting to use the bundled one."); - } - } - - if(foundUnlaunchInstallerVersion == INVALID) - { - foundUnlaunchInstallerVersion = loadUnlaunchInstaller("nitro:/unlaunch.dsi"); - if (foundUnlaunchInstallerVersion == INVALID) - { - messageBox("\x1B[41mWARNING:\x1B[47m Failed to load bundled unlaunch\n" - "installer.\n" - "Installing unlaunch won't be possible."); - } - } - if (fileExists("sd:/unlaunch-patch.bin")) { - splashSoundBinaryPatchPath = "sd:/unlaunch-patch.bin"; - } - else if(fileExists("nitro:/unlaunch-patch.bin")) - { - splashSoundBinaryPatchPath = "nitro:/unlaunch-patch.bin"; - } - - //check for unlaunch and region - u8 region = 0xff; - char retailLauncherTmdPath[64]; - char retailLauncherPath[64]; - const char* hnaaTmdPath = "nand:/title/00030017/484e4141/content/title.tmd"; - { - FILE* file = fopen("nand:/sys/HWINFO_S.dat", "rb"); - bool mainTmdIsPatched = false; - 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); - FILE* tmd = fopen(retailLauncherTmdPath, "rb"); - unsigned long long tmdSize = getFileSize(tmd); - if(!tmd || tmdSize < 520) - { - //if size isn't 520 then the tmd either is not present, or is already invalid, thus no need to patch - retailLauncherTmdPresentAndToBePatched = false; - } - else - { - if (tmdSize > 520) - { - unlaunchFound = true; - } - else - { - mainTmdIsPatched = isLauncherTmdPatched(retailLauncherTmdPath); - } - fseek(tmd, 0x1DC, SEEK_SET); - unsigned short launcherVersion; - fread(&launcherVersion, sizeof(launcherVersion), 1, tmd); - // Launcher v4, build v1024 (shipped with firmware 1.4.2 (1.4.3 for china and korea) - // will fail to launch if another tmd withouth appropriate application, or an invalid - // tmd (in our case the one installed from unlaunch) is found in the HNAA launcher folder - // there's really no workaround to that, so that specific version is blacklisted and only uninstalling - // an "officially" installed unlaunch without leaving any backup behind will be allowed - if(launcherVersion == 4) - { - isLauncherVersionSupported = false; - messageBox("\x1B[41mWARNING:\x1B[47m This system version\n" - "doesn't support this install\n" - "method, only uninstalling\n" - "unaunch without backups will\n" - "be possible"); - } - else if (launcherVersion > 7) - { - char messageBoxError[128]; - sprintf(messageBoxError, "\x1B[41mWARNING:\x1B[47m This system version (%d)\n" - "is unknown\n" - "nothing will be done", (int)launcherVersion); - messageBox("\x1B[41mWARNING:\x1B[47m This system version\n" - "is unknown\n" - "nothing will be done"); - goto abort; - } - sprintf(retailLauncherPath, "nand:/title/00030017/%08lx/content/0000000%d.app", launcherTid, (int)launcherVersion); - } - if(tmd) - { - fclose(tmd); - } - // 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); - - unsigned long long tmdSize = getFileSizePath(hnaaTmdPath); - if (tmdSize > 520) - { - unlaunchFound = unlaunchFound || (mainTmdIsPatched || !retailConsole); - hnaaUnlaunchFound = true; - } - } - - messageBox("\x1B[41mWARNING:\x1B[47m This tool can write to\n" - "your internal NAND!\n\n" - "This always has a risk, albeit\n" - "low, of \x1B[41mbricking\x1B[47m your system\n" - "and should be done with caution!\n\n" - "If you have not yet done so,\n" - "you should make a NAND backup."); - //main menu - int cursor = 0; - - while (!programEnd) - { - cursor = mainMenu(cursor); - if(programEnd) - break; - - switch (cursor) - { - case MAIN_MENU_SAFE_UNLAUNCH_UNINSTALL: - case MAIN_MENU_SAFE_UNLAUNCH_UNINSTALL_NO_BACKUP: - if(!unlaunchFound) - { - break; - } - bool unsafeUninstall = advancedOptionsUnlocked && cursor == MAIN_MENU_SAFE_UNLAUNCH_UNINSTALL_NO_BACKUP; - if(!isLauncherVersionSupported && !unsafeUninstall) - { - break; - } - if(!nandio_unlock_writing()) - { - break; - } - printf("Uninstalling"); - if(needsNocashFooterToBeWritten) - { - printf("Writing nocash footer\n"); - if(!nandio_write_nocash_footer(&computedNocashFooter)) - { - nandio_lock_writing(); - messageBox("Failed to write nocash footer"); - break; - } - needsNocashFooterToBeWritten = false; - } - if(uninstallUnlaunch(retailConsole, hnaaUnlaunchFound, retailLauncherTmdPath, retailLauncherPath, unsafeUninstall)) - { - messageBox("Uninstall successful!\n"); - unlaunchFound = false; - } - else - { - messageBox("\x1B[31mError:\x1B[33m Uninstall failed\n"); - } - nandio_lock_writing(); - printf("Synchronizing FAT tables...\n"); - nandio_synchronize_fats(); - break; - - case MAIN_MENU_CUSTOM_BG: - if(!isLauncherVersionSupported) - { - break; - } - if(foundUnlaunchInstallerVersion == INVALID) - { - break; - } - const char* customBg = backgroundMenu(); - if(!customBg) - { - break; - } - if(strcmp(customBg, "default") == 0) - { - customBgPath = NULL; - } - else - { - customBgPath = customBg; - } - break; - - case MAIN_MENU_TID_PATCHES: - if(!isLauncherVersionSupported) - { - break; - } - if(advancedOptionsUnlocked && (foundUnlaunchInstallerVersion == v1_9 || foundUnlaunchInstallerVersion == v2_0)) { - disableAllPatches = !disableAllPatches; - } - break; - - case MAIN_MENU_SOUND_SPLASH_PATCHES: - if(!isLauncherVersionSupported) - { - break; - } - if(foundUnlaunchInstallerVersion == v2_0 && !disableAllPatches && splashSoundBinaryPatchPath != NULL) { - enableSoundAndSplash = !enableSoundAndSplash; - } - break; - - case MAIN_MENU_SAFE_UNLAUNCH_INSTALL: - if(!isLauncherVersionSupported) - { - break; - } - if(unlaunchFound || foundUnlaunchInstallerVersion == INVALID) - { - break; - } - if(choiceBox("Install unlaunch?") == NO) - { - break; - } - if(!retailLauncherTmdPresentAndToBePatched - && (choiceBox("There doesn't seem to be a launcher.tmd\n" - "file matcing the hwinfo file\n" - "Keep installing?") == NO)) - { - break; - } - if(!nandio_unlock_writing()) - { - break; - } - printf("Installing\n"); - if(needsNocashFooterToBeWritten) - { - printf("Writing nocash footer\n"); - if(!nandio_write_nocash_footer(&computedNocashFooter)) - { - nandio_lock_writing(); - messageBox("Failed to write nocash footer"); - break; - } - needsNocashFooterToBeWritten = false; - } - if(installUnlaunch(retailConsole, - retailLauncherTmdPresentAndToBePatched ? retailLauncherTmdPath : NULL, - retailLauncherTmdPresentAndToBePatched ? retailLauncherPath : NULL, - disableAllPatches, - enableSoundAndSplash ? splashSoundBinaryPatchPath : NULL, - customBgPath)) - { - messageBox("Install successful!\n"); - unlaunchFound = true; - } - else - { - messageBox("\x1B[31mError:\x1B[33m Install failed\n"); - } - nandio_lock_writing(); - printf("Synchronizing FAT tables...\n"); - nandio_synchronize_fats(); - break; - - case MAIN_MENU_WRITE_NOCASH_FOOTER_ONLY: - if(!needsNocashFooterToBeWritten) - { - break; - } - if(!nandio_write_nocash_footer(&computedNocashFooter)) - { - messageBox("Failed to write nocash footer"); - break; - } - needsNocashFooterToBeWritten = false; - break; - - case MAIN_MENU_EXIT: - programEnd = true; - break; - } - } - - abort: - - 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(); -} \ No newline at end of file diff --git a/arm9/src/main.cpp b/arm9/src/main.cpp new file mode 100644 index 0000000..2fefba9 --- /dev/null +++ b/arm9/src/main.cpp @@ -0,0 +1,705 @@ +#include +#include +#include +#include +#include + +#include "bgMenu.h" +#include "consoleInfo.h" +#include "main.h" +#include "menu.h" +#include "message.h" +#include "nand/nandio.h" +#include "storage.h" +#include "version.h" +#include "unlaunch.h" +#include "nitrofs.h" +#include "deviceList.h" +#include "nocashFooter.h" + +using namespace std::string_view_literals; + +volatile bool programEnd = false; +static volatile bool arm7Exiting = false; +static bool retailLauncherTmdPresentAndToBePatched = true; +static UNLAUNCH_VERSION foundUnlaunchInstallerVersion = INVALID; +static bool disableAllPatches = false; +static bool enableSoundAndSplash = false; +static const char* splashSoundBinaryPatchPath = NULL; +static const char* customBgPath = NULL; +volatile bool charging = false; +volatile u8 batteryLevel = 0; +static bool advancedOptionsUnlocked = false; +static bool isLauncherVersionSupported = true; + +PrintConsole topScreen; +PrintConsole bottomScreen; + +enum { + MAIN_MENU_SAFE_UNLAUNCH_UNINSTALL, + MAIN_MENU_CUSTOM_BG, + MAIN_MENU_SOUND_SPLASH_PATCHES, + MAIN_MENU_SAFE_UNLAUNCH_INSTALL, + MAIN_MENU_EXIT, + MAIN_MENU_SAFE_UNLAUNCH_UNINSTALL_NO_BACKUP, + MAIN_MENU_WRITE_NOCASH_FOOTER_ONLY, + MAIN_MENU_TID_PATCHES, +}; + +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(const consoleInfo& info, int cursor) +{ + const auto tidPatchesSupported = (foundUnlaunchInstallerVersion == v1_9 || foundUnlaunchInstallerVersion == v2_0) && isLauncherVersionSupported; + //top screen + clearScreen(&topScreen); + + iprintf("\t\"Safe\" unlaunch installer\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("\x1b[23;0Hedo9300 - 2025"); + + //menu + Menu* m = newMenu(); + setMenuHeader(m, "MAIN MENU"); + + auto [restore_string, restore_string_no_backup] = [&]{ + if(info.tmdInvalid) { + return std::make_pair("Restore launcher tmd", "Restore launcher tmd no backup"); + } + return std::make_pair("Uninstall unlaunch", "Uninstall unlaunch no backup"); + }(); + + char soundPatchesStr[64], tidPatchesStr[32], installUnlaunchStr[32]; + sprintf(tidPatchesStr, "Disable all patches: %s", + disableAllPatches ? "On" : "Off"); + sprintf(soundPatchesStr, "Enable sound and splash: %s", + enableSoundAndSplash ? "On" : "Off"); + if(foundUnlaunchInstallerVersion != INVALID) + { + sprintf(installUnlaunchStr, "Install unlaunch (%s)", getUnlaunchVersionString(foundUnlaunchInstallerVersion)); + } + else + { + strcpy(installUnlaunchStr, "Install unlaunch"); + } + addMenuItem(m, restore_string, NULL, (info.tmdInvalid || info.tmdPatched) && isLauncherVersionSupported, false); + addMenuItem(m, "Custom background", NULL, foundUnlaunchInstallerVersion != INVALID && isLauncherVersionSupported, true); + addMenuItem(m, soundPatchesStr, NULL, foundUnlaunchInstallerVersion == v2_0 && !disableAllPatches && splashSoundBinaryPatchPath != NULL && isLauncherVersionSupported, false); + addMenuItem(m, installUnlaunchStr, NULL, foundUnlaunchInstallerVersion != INVALID && !(info.tmdInvalid || info.tmdPatched) && isLauncherVersionSupported, false); + addMenuItem(m, "Exit", NULL, true, false); + if(!isLauncherVersionSupported) + { + addMenuItem(m, restore_string_no_backup, NULL, (info.tmdInvalid || info.tmdPatched), false); + } + else if(advancedOptionsUnlocked) + { + addMenuItem(m, restore_string_no_backup, NULL, (info.tmdInvalid || info.tmdPatched), false); + addMenuItem(m, "Write nocash footer", NULL, info.needsNocashFooterToBeWritten, false); + addMenuItem(m, tidPatchesStr, NULL, tidPatchesSupported, false); + } + + m->cursor = cursor; + + //bottom screen + printMenu(m); + + int konamiCode = 0; + bool konamiCodeCooldown = false; + + while (!programEnd) + { + swiWaitForVBlank(); + scanKeys(); + + if (moveCursor(m)) + printMenu(m); + + if (keysDown() & KEY_A) + break; + + if(advancedOptionsUnlocked) + continue; + + int held = keysHeld(); + + if ((held & (KEY_L | KEY_R | KEY_Y)) == (KEY_L | KEY_R | KEY_Y)) + { + if(held == (KEY_L | KEY_R | KEY_Y) && !konamiCodeCooldown) + { + konamiCodeCooldown = true; + ++konamiCode; + } + } + else + { + konamiCodeCooldown = false; + } + if (konamiCode == 5) + { + advancedOptionsUnlocked = true; + // Enabled by default when unsupported + if(isLauncherVersionSupported) + { + addMenuItem(m, "Uninstall unlaunch no backup", NULL, (info.tmdInvalid || info.tmdPatched), false); + } + addMenuItem(m, "Write nocash footer", NULL, info.needsNocashFooterToBeWritten, false); + addMenuItem(m, tidPatchesStr, NULL, tidPatchesSupported, false); + } + } + + int result = m->cursor; + freeMenu(m); + + return result; +} + +void setup() { + keysSetRepeat(25, 5); + setupScreens(); + + fifoSetValue32Handler(FIFO_USER_01, [](u32 value32, void*) { + if (value32 != 0x54495845) // 'EXIT' + return; + programEnd = true; + arm7Exiting = true; + }, NULL); + fifoSetValue32Handler(FIFO_USER_03, [](u32 value32, void*) { + batteryLevel = value32 & 0xF; + charging = (value32 & BIT(7)) != 0; + }, NULL); + + //DSi check + if (!isDSiMode()) + { + messageBox("\x1B[31mError:\x1B[33m This app is exclusively for DSi."); + exit(0); + } + + //setup sd card access + if (!fatInitDefault()) + { + messageBox("fatInitDefault()...\x1B[31mFailed\n\x1B[47m"); + } + + u32 clusterSize = getClusterSizeForPartition("sd:/"); + if(clusterSize > 32768) + { + messageBox("Sd card cluster size is too large"); + exit(0); + } + + //setup nand access + if (!fatMountSimple("nand", &io_dsi_nand)) + { + messageBox("nand init \x1B[31mfailed\n\x1B[47m"); + exit(0); + } +} + +void checkNocashFooter(consoleInfo& info) { + NocashFooter footer; + + nandio_read_nocash_footer(&footer); + nandio_construct_nocash_footer(&info.nocashFooter); + + info.needsNocashFooterToBeWritten = !isFooterValid(&footer); + + if(!info.needsNocashFooterToBeWritten) + { + if(memcmp(&footer, &info.nocashFooter, sizeof(footer)) != 0) + { + messageBox("\x1B[31mError:\x1B[33m This console has a\n" + "nocash footer embedded in its\n" + "nand that doesn't match the one\n" + "generated.\n" + "The footer already present will\n" + "be overwritten."); + info.needsNocashFooterToBeWritten = true; + } + } +} + +bool writeNocashFooter(consoleInfo& info) { + if(!info.needsNocashFooterToBeWritten) + return true; + + if(!nandio_unlock_writing()) + return false; + + printf("Writing nocash footer\n"); + auto res = nandio_write_nocash_footer(&info.nocashFooter); + nandio_lock_writing(); + if(!res) + { + messageBox("Failed to write nocash footer"); + return false; + } + info.needsNocashFooterToBeWritten = false; + return true; +} + +void waitForBatteryChargedEnough() { + + while (batteryLevel < 7 && !charging) + { + if (choiceBox("\x1B[47mBattery is too low!\nPlease plug in the console.\n\nContinue?") == NO) + exit(0); + } +} + +const char* getInstallerPath(int argc, char **argv) { + if(argc > 0) + return argv[0]; + DeviceList* deviceList = getDeviceList(); + + if(deviceList) return deviceList->appname; + + return "sd:/ntrboot.nds"; +} + +void loadUnlaunchInstaller() { + if (fileExists("sd:/unlaunch.dsi")) + { + foundUnlaunchInstallerVersion = loadUnlaunchInstaller("sd:/unlaunch.dsi"); + if(foundUnlaunchInstallerVersion != INVALID) + return; + + messageBox("\x1B[41mWARNING:\x1B[47m Failed to load unlaunch.dsi\n" + "from the root of the sd card.\n" + "Attempting to use the bundled one."); + } + + foundUnlaunchInstallerVersion = loadUnlaunchInstaller("nitro:/unlaunch.dsi"); + + if(foundUnlaunchInstallerVersion != INVALID) + return; + + messageBox("\x1B[41mWARNING:\x1B[47m Failed to load bundled unlaunch\n" + "installer.\n" + "Installing unlaunch won't be possible."); +} + +void loadUnlaunchInstallerPatch() { + if (fileExists("sd:/unlaunch-patch.bin")) { + splashSoundBinaryPatchPath = "sd:/unlaunch-patch.bin"; + } + else if(fileExists("nitro:/unlaunch-patch.bin")) + { + splashSoundBinaryPatchPath = "nitro:/unlaunch-patch.bin"; + } +} + +void parseLauncherInfo(std::string_view launcher_tid_str, consoleInfo& info) { + auto launcher_content_path = std::format("nand:/title/00030017/{}/content", launcher_tid_str); + + auto [tmd_found, expected_launcher_build, retailLauncherPath] = [&] { + std::shared_ptr pdir{opendir(launcher_content_path.c_str()), closedir}; + if (!pdir) + throw std::runtime_error(std::format("Could not open launcher title directory ({})", launcher_content_path)); + dirent* pent; + std::optional> foundApp; + bool tmdFound; + while((pent = readdir(pdir.get())) != nullptr) { + if(foundApp && tmdFound) { + break; + } + if(pent->d_type == DT_DIR) + continue; + std::string_view filename{pent->d_name}; + if(filename == "title.tmd") { + tmdFound = true; + continue; + } + + if(filename.size() != 12 || !filename.ends_with(".app") || !filename.starts_with("0000000")) + continue; + + auto launcher_app_version = static_cast(static_cast(filename[7]) - static_cast('0')); + if(launcher_app_version > 7) + throw std::runtime_error(std::format("Found an unsupported launcher version: {}", launcher_app_version)); + + foundApp = std::make_pair(static_cast(256 * launcher_app_version), std::string{filename}); + } + if(!foundApp) + throw std::runtime_error("Launcher app not found"); + const auto& [launcher_build, launcher_app_name] = *foundApp; + return std::make_tuple(tmdFound, launcher_build, std::format("{}/{}", launcher_content_path, launcher_app_name)); + }(); + + if((info.tmdFound = tmd_found)) { + const auto recoveryTmdPath = std::format("nitro:/{}/tmd.{}", launcher_tid_str, static_cast(expected_launcher_build)); + info.launcherTmdPath = std::format("{}/title.tmd", launcher_content_path); + info.recoveryTmdDataSha = [&] -> Sha1Digest { + auto file = fopen(std::format("{}.sha1", recoveryTmdPath).data(), "rb"); + if(!file) + throw std::runtime_error("Good tmd sha1 not found"); + char sha1StrBuff[41]{}; + auto read = fread(sha1StrBuff, sizeof(sha1StrBuff) - 1, 1, file); + fclose(file); + if(read != 1) + throw std::runtime_error("Failed to parse good tmd's sha1 file"); + return {sha1StrBuff}; + }(); + + auto patchedTmdSha1 = [&] -> Sha1Digest { + auto file = fopen(std::format("{}.patch.sha1", recoveryTmdPath).data(), "rb"); + if(!file) + throw std::runtime_error("Patched tmd sha1 not found"); + char sha1StrBuff[41]{}; + auto read = fread(sha1StrBuff, sizeof(sha1StrBuff) - 1, 1, file); + fclose(file); + if(read != 1) + throw std::runtime_error("Failed to parse patched tmd's sha1 file"); + return {sha1StrBuff}; + }(); + + info.recoveryTmdData = [&] { + auto* sourceTmd = fopen(recoveryTmdPath.data(), "rb"); + + std::array ret; + auto read = fread(ret.data(), ret.size(), 1, sourceTmd); + fclose(sourceTmd); + if(read != 1) + { + throw std::runtime_error("Failed to read good tmd's buffer"); + } + + Sha1Digest digest; + swiSHA1Calc(digest.data(), ret.data(), ret.size()); + if(digest != info.recoveryTmdDataSha) + { + throw std::runtime_error("Good tmd's sha mismatching"); + } + return ret; + }(); + + std::shared_ptr tmd{fopen(info.launcherTmdPath.data(), "rb"), fclose}; + if(!tmd) { + info.tmdFound = false; + } else if(auto tmdSize = getFileSize(tmd.get()); tmdSize < 520) { + //if size isn't at least 520 then the tmd is already invalid + info.tmdInvalid = true; + } else { + info.launcherAppPath = retailLauncherPath; + if(tmdSize > 520) { + info.tmdInvalid = true; + } + else + { + Sha1Digest digest; + calculateFileSha1(tmd.get(), &digest); + if(digest == info.recoveryTmdDataSha){ + info.tmdGood = true; + } else if(digest == patchedTmdSha1) { + info.tmdPatched = true; + } else { + info.tmdInvalid = true; + } + } + if(!info.tmdInvalid) { + fseek(tmd.get(), 0x1DC, SEEK_SET); + uint16_t launcherVersion; + fread(&launcherVersion, sizeof(launcherVersion), 1, tmd.get()); + if(static_cast(launcherVersion) * 256 != expected_launcher_build) { + throw std::runtime_error("Launcher version found doesn't match with the one in the tmd"); + } + info.launcherVersion = launcherVersion; + } + } + if(info.tmdInvalid || !info.tmdFound) { + // if the tmd is invalid, don't read the launcher version from it and assume it's the one + // matching the app file + info.launcherVersion = expected_launcher_build / 256; + } + } +} + +void retrieveInstalledLauncherInfo(consoleInfo& info) { + static constexpr auto hnaaTmdPath = "nand:/title/00030017/484e4141/content/title.tmd"sv; + const auto [launcher_tid_str, region] = [] -> std::pair { + uint32_t launcherTid; + { + auto* file = fopen("nand:/sys/HWINFO_S.dat", "rb"); + if(!file) + return std::make_pair("", static_cast(0xFF)); + fseek(file, 0xA0, SEEK_SET); + fread(&launcherTid, sizeof(uint32_t), 1, file); + fclose(file); + } + return std::make_pair(std::format("{:08x}", launcherTid), static_cast(launcherTid & 0xFF)); + }(); + + // 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) + info.isRetail = (region != 0x41 && region != 0xFF); + + //check for unlaunch and region + if (info.isRetail && launcher_tid_str.size() != 0) { + parseLauncherInfo(launcher_tid_str, info); + } else { + // HWINFO_S may not always exist (PRE_IMPORT). Fill in defaults if that happens. + (void)0; + } + + if (auto tmdSize = getFileSizePath(hnaaTmdPath.data()); tmdSize > 520) { + info.UnlaunchHNAAtmdFound = true; + } +} + +void uninstall(consoleInfo& info, bool noBackup) { + if(!(info.tmdInvalid || info.tmdPatched)) + { + return; + } + bool unsafeUninstall = advancedOptionsUnlocked && noBackup; + if(!isLauncherVersionSupported && !unsafeUninstall) + { + return; + } + printf("Uninstalling"); + if(!writeNocashFooter(info)) + { + return; + } + if(!nandio_unlock_writing()) + { + return; + } + if(uninstallUnlaunch(info, unsafeUninstall)) + { + messageBox("Uninstall successful!\n"); + info.tmdInvalid = false; + info.tmdPatched = false; + info.tmdGood = true; + info.UnlaunchHNAAtmdFound = !unsafeUninstall; + } + else + { + messageBox("\x1B[31mError:\x1B[33m Uninstall failed\n"); + } + nandio_lock_writing(); + printf("Synchronizing FAT tables...\n"); + nandio_synchronize_fats(); +} + +void install(consoleInfo& info) { + if(!isLauncherVersionSupported) + { + return; + } + if(info.tmdInvalid || info.tmdPatched || !info.tmdGood || foundUnlaunchInstallerVersion == INVALID) + { + return; + } + if(choiceBox("Install unlaunch?") == NO) + { + return; + } + if(!retailLauncherTmdPresentAndToBePatched + && (choiceBox("There doesn't seem to be a launcher.tmd\n" + "file matcing the hwinfo file\n" + "Keep installing?") == NO)) + { + return; + } + printf("Installing\n"); + if(!writeNocashFooter(info)) + { + return; + } + if(!nandio_unlock_writing()) + { + return; + } + if(installUnlaunch(info, disableAllPatches, + enableSoundAndSplash ? splashSoundBinaryPatchPath : NULL, + customBgPath)) + { + messageBox("Install successful!\n"); + info.tmdGood = false; + info.tmdPatched = true; + info.UnlaunchHNAAtmdFound = true; + } + else + { + messageBox("\x1B[31mError:\x1B[33m Install failed\n"); + } + nandio_lock_writing(); + printf("Synchronizing FAT tables...\n"); + nandio_synchronize_fats(); +} + +void customBg() { + if(!isLauncherVersionSupported) + { + return; + } + if(foundUnlaunchInstallerVersion == INVALID) + { + return; + } + const char* customBg = backgroundMenu(); + if(!customBg) + { + return; + } + if(strcmp(customBg, "default") == 0) + { + customBgPath = NULL; + } + else + { + customBgPath = customBg; + } +} + +void doMainMenu(consoleInfo& info) { + int cursor = 0; + while(!programEnd) + { + cursor = mainMenu(info, cursor); + if(programEnd) + break; + + switch (cursor) + { + case MAIN_MENU_SAFE_UNLAUNCH_UNINSTALL: + case MAIN_MENU_SAFE_UNLAUNCH_UNINSTALL_NO_BACKUP: + { + uninstall(info, cursor == MAIN_MENU_SAFE_UNLAUNCH_UNINSTALL_NO_BACKUP); + } + break; + + case MAIN_MENU_CUSTOM_BG: + { + customBg(); + } + break; + + case MAIN_MENU_TID_PATCHES: + if(!isLauncherVersionSupported) + { + break; + } + if(advancedOptionsUnlocked && (foundUnlaunchInstallerVersion == v1_9 || foundUnlaunchInstallerVersion == v2_0)) { + disableAllPatches = !disableAllPatches; + } + break; + + case MAIN_MENU_SOUND_SPLASH_PATCHES: + if(!isLauncherVersionSupported) + { + break; + } + if(foundUnlaunchInstallerVersion == v2_0 && !disableAllPatches && splashSoundBinaryPatchPath != NULL) { + enableSoundAndSplash = !enableSoundAndSplash; + } + break; + + case MAIN_MENU_SAFE_UNLAUNCH_INSTALL: + { + install(info); + } + break; + + case MAIN_MENU_WRITE_NOCASH_FOOTER_ONLY: + (void)writeNocashFooter(info); + break; + + case MAIN_MENU_EXIT: + programEnd = true; + return; + } + } +} + +int main(int argc, char **argv) +{ + setup(); + + if (!nitroFSInit(getInstallerPath(argc, argv))) + { + messageBox("nitroFSInit()...\x1B[31mFailed\n\x1B[47m"); + } + + loadUnlaunchInstaller(); + loadUnlaunchInstallerPatch(); + + consoleInfo info; + + try { + retrieveInstalledLauncherInfo(info); + + checkNocashFooter(info); + + // Launcher v4, build v1024 (shipped with firmware 1.4.2 (1.4.3 for china and korea) + // will fail to launch if another tmd withouth appropriate application, or an invalid + // tmd (in our case the one installed from unlaunch) is found in the HNAA launcher folder + // there's really no workaround to that, so that specific version is blacklisted and only uninstalling + // an "officially" installed unlaunch without leaving any backup behind will be allowed + if(info.launcherVersion == 4) { + isLauncherVersionSupported = false; + messageBox("\x1B[41mWARNING:\x1B[47m This system version\n" + "doesn't support this install\n" + "method, only uninstalling\n" + "unaunch without backups will\n" + "be possible"); + } + + messageBox("\x1B[41mWARNING:\x1B[47m This tool can write to\n" + "your internal NAND!\n\n" + "This always has a risk, albeit\n" + "low, of \x1B[41mbricking\x1B[47m your system\n" + "and should be done with caution!\n\n" + "If you have not yet done so,\n" + "you should make a NAND backup."); + + waitForBatteryChargedEnough(); + + doMainMenu(info); + } catch (const std::exception& e) { + messageBox(e.what()); + } + + 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(); +} diff --git a/arm9/src/unlaunch.cpp b/arm9/src/unlaunch.cpp index fb6126b..45e81c4 100644 --- a/arm9/src/unlaunch.cpp +++ b/arm9/src/unlaunch.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include static char unlaunchInstallerBuffer[0x30000]; static char ogUnlaunchInstallerBuffer[0x30000]; @@ -51,23 +53,9 @@ bool isValidUnlaunchInstallerSize(size_t size) return size == 163320 /*1.8*/ || size == 196088 /*1.9, 2.0*/; } -bool isLauncherTmdPatched(const char* path) -{ - FILE* launcherTmd = fopen(path, "rb"); - if(!launcherTmd) - { - return false; - } - fseek(launcherTmd, 0x190, SEEK_SET); - char c; - fread(&c, 1, 1, launcherTmd); - fclose(launcherTmd); - return c == 0x47; -} - static bool removeHnaaLauncher() { - auto* errString = [] -> const char* { + auto* errString = [] -> const char* { if(!toggleFileReadOnly(hnaaTmdPath, false)) { return "\x1B[31mError:\x1B[33m Failed to mark unlaunch's title.tmd as writable\nLeaving as is\n"; @@ -94,92 +82,85 @@ static bool removeHnaaLauncher() return true; } -static bool restoreMainTmd(const char* path, bool hasHNAABackup, bool removeHNAABackup) +static bool restoreMainTmd(const consoleInfo& info, bool removeHNAABackup) { - FILE* launcherTmd = fopen(path, "r+b"); - if(!launcherTmd) + std::shared_ptr launcherTmdSptr{fopen(info.launcherTmdPath.data(), "r+b"), fclose}; + if(!launcherTmdSptr) { messageBox("\x1B[31mError:\x1B[33m Failed to open default launcher's title.tmd\n"); return false; } - // Set back the title.tmd's title id from GNXX to HNXX - fseek(launcherTmd, 0x190, SEEK_SET); - char c; - fread(&c, 1, 1, launcherTmd); - //if byte is not what we expect, the install method was different - if(c == 0x47) - { - fseek(launcherTmd, -1, SEEK_CUR); - c = 0x48; - fwrite(&c, 1, 1, launcherTmd); - fclose(launcherTmd); - if(removeHNAABackup && hasHNAABackup) - { - removeHnaaLauncher(); - } - } - else if(c != 0x47) - { - if (getFileSize(launcherTmd) > 520) { - // Remove unlaunch if it already exists on the main launcher tmd. - // If we don't do this and unlaunch is on the tmd, it will take over and prevent loading HNAA + FILE* launcherTmd = launcherTmdSptr.get(); - // This is also a good idea to make sure the tmd is 520b. - // You will have a much higher brick risk if something goes wrong with a tmd over 520b. - // See: http://docs.randommeaninglesscharacters.com/unlaunch.html - if(!hasHNAABackup && !removeHNAABackup) - { - auto choiceString = [&]{ - if(installerVersion != INVALID) - return "Unlaunch was installed with the\n" - "legacy method.\n" - "Before uninstalling it, a\n" - "failsafe installation will be\n" - "created.\n" - "Proceed?"; - return "Unlaunch was installed with the\n" - "legacy method\n" - "But a failsafe installation\n" - "cannot be created since no valid\n" - "unlaunch installer was provided.\n" - "Proceed anyways?"; - }(); - if(choiceBox(choiceString) == NO) - { - fclose(launcherTmd); - return false; - } - if(installerVersion != INVALID) - { - if(!writeUnlaunchToHNAAFolder()) - { - if(choiceBox("Failsafe installation couldn't\n" - "be copmleted.\n" - "Proceed anyways?") == NO) - { - fclose(launcherTmd); - return false; - } - } - } - } - if(removeHNAABackup && hasHNAABackup) - { - removeHnaaLauncher(); - } - if (ftruncate(fileno(launcherTmd), 520) != 0) { - messageBox("\x1B[31mError:\x1B[33m Failed to remove unlaunch\n"); - fclose(launcherTmd); - return false; - } - fclose(launcherTmd); - return true; - } - messageBox("\x1B[31mError:\x1B[33m Unlaunch was installed with an\nunknown method\naborting\n"); - fclose(launcherTmd); - return false; - } - return true; + // If the tmd is patched, assume the HNAA backup is already set in place. + if(info.tmdPatched) { + fseek(launcherTmd, 0x190, SEEK_SET); + // Set back the title.tmd's title id from GNXX to HNXX + char c = 0x48; + fwrite(&c, 1, 1, launcherTmd); + fflush(launcherTmd); + } else if(!info.tmdGood || info.tmdInvalid) { + // The tmd isn't good, it either has the wrong size, or the hash didn't match + // and it wasn't patched with the new method + // Install the hnaa backup if not found and then truncate the tmd to 520b + // before restoring it + if(!info.UnlaunchHNAAtmdFound && !removeHNAABackup) + { + auto choiceString = [&]{ + if(installerVersion != INVALID) + return "Unlaunch was installed with the\n" + "legacy method.\n" + "Before uninstalling it, a\n" + "failsafe installation will be\n" + "created.\n" + "Proceed?"; + return "Unlaunch was installed with the\n" + "legacy method\n" + "But a failsafe installation\n" + "cannot be created since no valid\n" + "unlaunch installer was provided.\n" + "Proceed anyways?"; + }(); + if(choiceBox(choiceString) == NO) + { + return false; + } + if(installerVersion != INVALID) + { + if(!writeUnlaunchToHNAAFolder()) + { + if(choiceBox("Failsafe installation couldn't\n" + "be copmleted.\n" + "Proceed anyways?") == NO) + { + return false; + } + } + } + } + if (ftruncate(fileno(launcherTmd), 520) != 0) { + messageBox("\x1B[31mError:\x1B[33m Failed to remove unlaunch\n"); + return false; + } + } + + Sha1Digest digest; + calculateFileSha1(launcherTmd, &digest); + + // the tmd still doesn't match, write a known good one + if(digest != info.recoveryTmdDataSha) { + fseek(launcherTmd, 0, SEEK_SET); + auto written = fwrite(info.recoveryTmdData.data(), info.recoveryTmdData.size(), 1, launcherTmd); + if(written != 1) { + messageBox("\x1B[31mError:\x1B[33m Failed to remove unlaunch\n"); + return false; + } + } + if(removeHNAABackup && info.UnlaunchHNAAtmdFound) + { + return removeHnaaLauncher(); + } + return true; } static bool patchMainTmd(const char* path) @@ -225,15 +206,21 @@ static bool restoreProtoTmd(const char* path) return true; } -bool uninstallUnlaunch(bool retailConsole, bool hasHNAABackup, const char* retailLauncherTmdPath, const char* retailLauncherPath, bool removeHNAABackup) +bool uninstallUnlaunch(const consoleInfo& info, bool removeHNAABackup) { // TODO: handle retailLauncherTmdPresentAndToBePatched = false on retail consoles - if (retailConsole) { - if (!toggleFileReadOnly(retailLauncherTmdPath, false) || !toggleFileReadOnly(retailLauncherPath, false)) + if (info.isRetail) { + if(!toggleFileReadOnly(info.launcherTmdPath.data(), false)) + { + messageBox(std::format("\x1B[31mError:\x1B[33m Failed to make {} writable\n", info.launcherTmdPath).data()); + return false; + } + if(!toggleFileReadOnly(info.launcherAppPath.data(), false)) { + messageBox(std::format("\x1B[31mError:\x1B[33m Failed to make {} writable\n", info.launcherAppPath).data()); return false; - } - if (!restoreMainTmd(retailLauncherTmdPath, hasHNAABackup, removeHNAABackup)) + } + if (!restoreMainTmd(info, removeHNAABackup)) { return false; } @@ -312,7 +299,7 @@ static bool writeUnlaunchToHNAAFolder() return true; } -static bool installUnlaunchRetailConsole(const char* retailLauncherTmdPath, const char* retailLauncherPath) +static bool installUnlaunchRetailConsole(const consoleInfo& info) { if(!writeUnlaunchToHNAAFolder()) return false; @@ -320,20 +307,20 @@ static bool installUnlaunchRetailConsole(const char* retailLauncherTmdPath, cons //Finally patch the default launcher tmd to be invalid //If there isn't a title.tmd matching the language region in the hwinfo // nothing else has to be done, could be a language patch, or a dev system, the user will know what they have done - if (retailLauncherTmdPath) - { - // Set tmd as writable in case unlaunch was already installed through the old method - if(!toggleFileReadOnly(retailLauncherTmdPath, false) || !patchMainTmd(retailLauncherTmdPath)) - { - removeHnaaLauncher(); - return false; - } - if (!toggleFileReadOnly(retailLauncherTmdPath, true) || !toggleFileReadOnly(retailLauncherPath, true)) - { - messageBox("\x1B[31mError:\x1B[33m Failed to mark default launcher's title.tmd\nas read only, install might be unstable\n"); - } - } - return true; + if (!info.tmdFound) + return true; + + // Set tmd as writable in case unlaunch was already installed through the old method + if(!toggleFileReadOnly(info.launcherTmdPath.data(), false) || !patchMainTmd(info.launcherTmdPath.data())) + { + removeHnaaLauncher(); + return false; + } + if (!toggleFileReadOnly(info.launcherTmdPath.data(), true) || !toggleFileReadOnly(info.launcherAppPath.data(), true)) + { + messageBox("\x1B[31mError:\x1B[33m Failed to mark default launcher's title.tmd\nas read only, install might be unstable\n"); + } + return true; } static bool installUnlaunchProtoConsole(void) @@ -381,9 +368,9 @@ static bool installUnlaunchProtoConsole(void) return true; } -static bool readUnlaunchInstaller(const char* path) +static bool readUnlaunchInstaller(std::string_view path) { - FILE* unlaunchInstaller = fopen(path, "rb"); + FILE* unlaunchInstaller = fopen(path.data(), "rb"); if (!unlaunchInstaller) { messageBox("\x1B[31mError:\x1B[33m Failed to open unlaunch installer\n"); @@ -545,7 +532,7 @@ static bool patchUnlaunchInstaller(bool disableAllPatches, const char* splashSou return true; } -UNLAUNCH_VERSION loadUnlaunchInstaller(const char* path) +UNLAUNCH_VERSION loadUnlaunchInstaller(std::string_view path) { if(readUnlaunchInstaller(path) && verifyUnlaunchInstaller()) { @@ -569,16 +556,16 @@ const char* getUnlaunchVersionString(UNLAUNCH_VERSION version) return unlaunchVersionStrings[version]; } -bool installUnlaunch(bool retailConsole, const char* retailLauncherTmdPath, const char* retailLauncherPath, bool disableAllPatches, const char* splashSoundBinaryPatchPath, const char* customBackgroundPath) +bool installUnlaunch(const consoleInfo& info, bool disableAllPatches, const char* splashSoundBinaryPatchPath, const char* customBackgroundPath) { if (installerVersion == INVALID || !patchUnlaunchInstaller(disableAllPatches, splashSoundBinaryPatchPath, customBackgroundPath)) return false; // Treat protos differently - if (!retailConsole) + if (!info.isRetail) { return installUnlaunchProtoConsole(); } // Do things normally for production units - return installUnlaunchRetailConsole(retailLauncherTmdPath, retailLauncherPath); -} \ No newline at end of file + return installUnlaunchRetailConsole(info); +} diff --git a/arm9/src/unlaunch.h b/arm9/src/unlaunch.h index 72108a9..b179d2b 100644 --- a/arm9/src/unlaunch.h +++ b/arm9/src/unlaunch.h @@ -1,10 +1,8 @@ #ifndef UNLAUNCH_H #define UNLAUNCH_H -#include +#include -#ifdef __cplusplus -extern "C" { -#endif +#include "consoleInfo.h" typedef enum UNLAUNCH_VERSION { v1_8, @@ -15,15 +13,9 @@ typedef enum UNLAUNCH_VERSION { const char* getUnlaunchVersionString(UNLAUNCH_VERSION); -bool uninstallUnlaunch(bool notProto, bool hasHNAABackup, const char* retailLauncherTmdPath, const char* retailLauncherPath, bool removeHNAABackup); -bool installUnlaunch(bool retailConsole, const char* retailLauncherTmdPath, const char* retailLauncherPath, bool disableAllPatches, const char* splashSoundBinaryPatchPath, const char* customBackgroundPath); +bool uninstallUnlaunch(const consoleInfo& info, bool removeHNAABackup); +bool installUnlaunch(const consoleInfo& info, bool disableAllPatches, const char* splashSoundBinaryPatchPath, const char* customBackgroundPath); -bool isLauncherTmdPatched(const char* path); +UNLAUNCH_VERSION loadUnlaunchInstaller(std::string_view path); -UNLAUNCH_VERSION loadUnlaunchInstaller(const char* path); - -#ifdef __cplusplus -} #endif - -#endif \ No newline at end of file diff --git a/nitrofiles/484e4143/tmd.1024 b/nitrofiles/484e4143/tmd.1024 new file mode 100644 index 0000000..088abb8 Binary files /dev/null and b/nitrofiles/484e4143/tmd.1024 differ diff --git a/nitrofiles/484e4143/tmd.1024.patch.sha1 b/nitrofiles/484e4143/tmd.1024.patch.sha1 new file mode 100644 index 0000000..3d3304c --- /dev/null +++ b/nitrofiles/484e4143/tmd.1024.patch.sha1 @@ -0,0 +1 @@ +d20ef5520ef3df8bc418f46075cc5e6865ed4b6e \ No newline at end of file diff --git a/nitrofiles/484e4143/tmd.1024.sha1 b/nitrofiles/484e4143/tmd.1024.sha1 new file mode 100644 index 0000000..18515e3 --- /dev/null +++ b/nitrofiles/484e4143/tmd.1024.sha1 @@ -0,0 +1 @@ +88076c8d9e8330e43e32bba7c24fb2970d16241e \ No newline at end of file diff --git a/nitrofiles/484e4143/tmd.1280 b/nitrofiles/484e4143/tmd.1280 new file mode 100644 index 0000000..fc66618 Binary files /dev/null and b/nitrofiles/484e4143/tmd.1280 differ diff --git a/nitrofiles/484e4143/tmd.1280.patch.sha1 b/nitrofiles/484e4143/tmd.1280.patch.sha1 new file mode 100644 index 0000000..bf0fec1 --- /dev/null +++ b/nitrofiles/484e4143/tmd.1280.patch.sha1 @@ -0,0 +1 @@ +7fc30f65d75ca08ff6c356527a8cc4f62669a69e \ No newline at end of file diff --git a/nitrofiles/484e4143/tmd.1280.sha1 b/nitrofiles/484e4143/tmd.1280.sha1 new file mode 100644 index 0000000..de81d6c --- /dev/null +++ b/nitrofiles/484e4143/tmd.1280.sha1 @@ -0,0 +1 @@ +58e0db23ee9b0cae9d7e83fd39b1781a7eebf3bb \ No newline at end of file diff --git a/nitrofiles/484e4143/tmd.1536 b/nitrofiles/484e4143/tmd.1536 new file mode 100644 index 0000000..4ea4f42 Binary files /dev/null and b/nitrofiles/484e4143/tmd.1536 differ diff --git a/nitrofiles/484e4143/tmd.1536.patch.sha1 b/nitrofiles/484e4143/tmd.1536.patch.sha1 new file mode 100644 index 0000000..6f365d9 --- /dev/null +++ b/nitrofiles/484e4143/tmd.1536.patch.sha1 @@ -0,0 +1 @@ +dab8a54b21f6c76062b0ad2a2e195a09c27960fd \ No newline at end of file diff --git a/nitrofiles/484e4143/tmd.1536.sha1 b/nitrofiles/484e4143/tmd.1536.sha1 new file mode 100644 index 0000000..77a70c0 --- /dev/null +++ b/nitrofiles/484e4143/tmd.1536.sha1 @@ -0,0 +1 @@ +7c57ec724652b98923b2111150062657119644c5 \ No newline at end of file diff --git a/nitrofiles/484e4143/tmd.1792 b/nitrofiles/484e4143/tmd.1792 new file mode 100644 index 0000000..bc7ee8b Binary files /dev/null and b/nitrofiles/484e4143/tmd.1792 differ diff --git a/nitrofiles/484e4143/tmd.1792.patch.sha1 b/nitrofiles/484e4143/tmd.1792.patch.sha1 new file mode 100644 index 0000000..fcdc038 --- /dev/null +++ b/nitrofiles/484e4143/tmd.1792.patch.sha1 @@ -0,0 +1 @@ +0358cb04f28d038cf6337a9d05ae58b3ad86af59 \ No newline at end of file diff --git a/nitrofiles/484e4143/tmd.1792.sha1 b/nitrofiles/484e4143/tmd.1792.sha1 new file mode 100644 index 0000000..59c7533 --- /dev/null +++ b/nitrofiles/484e4143/tmd.1792.sha1 @@ -0,0 +1 @@ +e0a43818affb9c2849230abba12bc59fae48aa69 \ No newline at end of file diff --git a/nitrofiles/484e4143/tmd.512 b/nitrofiles/484e4143/tmd.512 new file mode 100644 index 0000000..026d076 Binary files /dev/null and b/nitrofiles/484e4143/tmd.512 differ diff --git a/nitrofiles/484e4143/tmd.512.patch.sha1 b/nitrofiles/484e4143/tmd.512.patch.sha1 new file mode 100644 index 0000000..93e1e49 --- /dev/null +++ b/nitrofiles/484e4143/tmd.512.patch.sha1 @@ -0,0 +1 @@ +4e350d55f0b134748ddaf1ff1eef99de4c7dfa85 \ No newline at end of file diff --git a/nitrofiles/484e4143/tmd.512.sha1 b/nitrofiles/484e4143/tmd.512.sha1 new file mode 100644 index 0000000..a0bb6cb --- /dev/null +++ b/nitrofiles/484e4143/tmd.512.sha1 @@ -0,0 +1 @@ +76727f47fa55a06d0b684745c5e6cdd5f596c4e5 \ No newline at end of file diff --git a/nitrofiles/484e4143/tmd.768 b/nitrofiles/484e4143/tmd.768 new file mode 100644 index 0000000..fdcfb50 Binary files /dev/null and b/nitrofiles/484e4143/tmd.768 differ diff --git a/nitrofiles/484e4143/tmd.768.patch.sha1 b/nitrofiles/484e4143/tmd.768.patch.sha1 new file mode 100644 index 0000000..92ee74c --- /dev/null +++ b/nitrofiles/484e4143/tmd.768.patch.sha1 @@ -0,0 +1 @@ +b1d18a727dae139451a6e2ca4b89dd22253d4639 \ No newline at end of file diff --git a/nitrofiles/484e4143/tmd.768.sha1 b/nitrofiles/484e4143/tmd.768.sha1 new file mode 100644 index 0000000..4873b75 --- /dev/null +++ b/nitrofiles/484e4143/tmd.768.sha1 @@ -0,0 +1 @@ +ebd7cff8b0d3ccca8579872b29dc20cc3a0827d1 \ No newline at end of file diff --git a/nitrofiles/484e4145/tmd.1024 b/nitrofiles/484e4145/tmd.1024 new file mode 100644 index 0000000..fd82d3e Binary files /dev/null and b/nitrofiles/484e4145/tmd.1024 differ diff --git a/nitrofiles/484e4145/tmd.1024.patch.sha1 b/nitrofiles/484e4145/tmd.1024.patch.sha1 new file mode 100644 index 0000000..23c5871 --- /dev/null +++ b/nitrofiles/484e4145/tmd.1024.patch.sha1 @@ -0,0 +1 @@ +a91f95d68dccd359987ef7e32ec2221148153da6 \ No newline at end of file diff --git a/nitrofiles/484e4145/tmd.1024.sha1 b/nitrofiles/484e4145/tmd.1024.sha1 new file mode 100644 index 0000000..9afea24 --- /dev/null +++ b/nitrofiles/484e4145/tmd.1024.sha1 @@ -0,0 +1 @@ +7795346d34093c0d73db587f6c5fd8510b947ec7 \ No newline at end of file diff --git a/nitrofiles/484e4145/tmd.1280 b/nitrofiles/484e4145/tmd.1280 new file mode 100644 index 0000000..736276e Binary files /dev/null and b/nitrofiles/484e4145/tmd.1280 differ diff --git a/nitrofiles/484e4145/tmd.1280.patch.sha1 b/nitrofiles/484e4145/tmd.1280.patch.sha1 new file mode 100644 index 0000000..cc3e19b --- /dev/null +++ b/nitrofiles/484e4145/tmd.1280.patch.sha1 @@ -0,0 +1 @@ +4c482027655615abe80ed32a26f064fd97caf80c \ No newline at end of file diff --git a/nitrofiles/484e4145/tmd.1280.sha1 b/nitrofiles/484e4145/tmd.1280.sha1 new file mode 100644 index 0000000..b669eb7 --- /dev/null +++ b/nitrofiles/484e4145/tmd.1280.sha1 @@ -0,0 +1 @@ +978f1a3b26a4f983a7e305d1a89c73d0890e6683 \ No newline at end of file diff --git a/nitrofiles/484e4145/tmd.1536 b/nitrofiles/484e4145/tmd.1536 new file mode 100644 index 0000000..c432d9b Binary files /dev/null and b/nitrofiles/484e4145/tmd.1536 differ diff --git a/nitrofiles/484e4145/tmd.1536.patch.sha1 b/nitrofiles/484e4145/tmd.1536.patch.sha1 new file mode 100644 index 0000000..5ef4684 --- /dev/null +++ b/nitrofiles/484e4145/tmd.1536.patch.sha1 @@ -0,0 +1 @@ +c758f170bc58b6a2bc60cd521456b76a0304fe2c \ No newline at end of file diff --git a/nitrofiles/484e4145/tmd.1536.sha1 b/nitrofiles/484e4145/tmd.1536.sha1 new file mode 100644 index 0000000..daaadb5 --- /dev/null +++ b/nitrofiles/484e4145/tmd.1536.sha1 @@ -0,0 +1 @@ +ca573c0014319ce6a5e3ead6197d07c84783f21d \ No newline at end of file diff --git a/nitrofiles/484e4145/tmd.1792 b/nitrofiles/484e4145/tmd.1792 new file mode 100644 index 0000000..ad280f9 Binary files /dev/null and b/nitrofiles/484e4145/tmd.1792 differ diff --git a/nitrofiles/484e4145/tmd.1792.patch.sha1 b/nitrofiles/484e4145/tmd.1792.patch.sha1 new file mode 100644 index 0000000..1912cac --- /dev/null +++ b/nitrofiles/484e4145/tmd.1792.patch.sha1 @@ -0,0 +1 @@ +4702ac21227a9a1e2d46b6c336e8dc99b1ec25bf \ No newline at end of file diff --git a/nitrofiles/484e4145/tmd.1792.sha1 b/nitrofiles/484e4145/tmd.1792.sha1 new file mode 100644 index 0000000..83984d1 --- /dev/null +++ b/nitrofiles/484e4145/tmd.1792.sha1 @@ -0,0 +1 @@ +a297f64a9d574a9c7abe71998553c3a602f124d9 \ No newline at end of file diff --git a/nitrofiles/484e4145/tmd.256 b/nitrofiles/484e4145/tmd.256 new file mode 100644 index 0000000..4b970c1 Binary files /dev/null and b/nitrofiles/484e4145/tmd.256 differ diff --git a/nitrofiles/484e4145/tmd.256.patch.sha1 b/nitrofiles/484e4145/tmd.256.patch.sha1 new file mode 100644 index 0000000..583d23d --- /dev/null +++ b/nitrofiles/484e4145/tmd.256.patch.sha1 @@ -0,0 +1 @@ +0bb15b299d5dbe236f6194b5e9091eebe05264c7 \ No newline at end of file diff --git a/nitrofiles/484e4145/tmd.256.sha1 b/nitrofiles/484e4145/tmd.256.sha1 new file mode 100644 index 0000000..fdcb435 --- /dev/null +++ b/nitrofiles/484e4145/tmd.256.sha1 @@ -0,0 +1 @@ +4c68c41515868deb79f1a79a8e45c4248a4ed2c2 \ No newline at end of file diff --git a/nitrofiles/484e4145/tmd.512 b/nitrofiles/484e4145/tmd.512 new file mode 100644 index 0000000..6ef29cb Binary files /dev/null and b/nitrofiles/484e4145/tmd.512 differ diff --git a/nitrofiles/484e4145/tmd.512.patch.sha1 b/nitrofiles/484e4145/tmd.512.patch.sha1 new file mode 100644 index 0000000..0915014 --- /dev/null +++ b/nitrofiles/484e4145/tmd.512.patch.sha1 @@ -0,0 +1 @@ +7cf1ab87b14a325626f730579277e66ad51f7134 \ No newline at end of file diff --git a/nitrofiles/484e4145/tmd.512.sha1 b/nitrofiles/484e4145/tmd.512.sha1 new file mode 100644 index 0000000..e62f7b9 --- /dev/null +++ b/nitrofiles/484e4145/tmd.512.sha1 @@ -0,0 +1 @@ +6c52561a047c8036f31f9d468570d50d36f7d988 \ No newline at end of file diff --git a/nitrofiles/484e4145/tmd.768 b/nitrofiles/484e4145/tmd.768 new file mode 100644 index 0000000..9409f47 Binary files /dev/null and b/nitrofiles/484e4145/tmd.768 differ diff --git a/nitrofiles/484e4145/tmd.768.patch.sha1 b/nitrofiles/484e4145/tmd.768.patch.sha1 new file mode 100644 index 0000000..0533d6f --- /dev/null +++ b/nitrofiles/484e4145/tmd.768.patch.sha1 @@ -0,0 +1 @@ +393fdcc1a46baf35fc5324928865736fa9bb1816 \ No newline at end of file diff --git a/nitrofiles/484e4145/tmd.768.sha1 b/nitrofiles/484e4145/tmd.768.sha1 new file mode 100644 index 0000000..021f237 --- /dev/null +++ b/nitrofiles/484e4145/tmd.768.sha1 @@ -0,0 +1 @@ +5a27d8d7437380252cf35786231f8adcc4cf3ff6 \ No newline at end of file diff --git a/nitrofiles/484e414a/tmd.0 b/nitrofiles/484e414a/tmd.0 new file mode 100644 index 0000000..c83b302 Binary files /dev/null and b/nitrofiles/484e414a/tmd.0 differ diff --git a/nitrofiles/484e414a/tmd.0.patch.sha1 b/nitrofiles/484e414a/tmd.0.patch.sha1 new file mode 100644 index 0000000..5a54df9 --- /dev/null +++ b/nitrofiles/484e414a/tmd.0.patch.sha1 @@ -0,0 +1 @@ +f98c9648e668b8c30d1e85926626bf971cfbf749 \ No newline at end of file diff --git a/nitrofiles/484e414a/tmd.0.sha1 b/nitrofiles/484e414a/tmd.0.sha1 new file mode 100644 index 0000000..cc9be54 --- /dev/null +++ b/nitrofiles/484e414a/tmd.0.sha1 @@ -0,0 +1 @@ +e99b6e6e9e8e46d2a0ad820a2c8e187829b3001a \ No newline at end of file diff --git a/nitrofiles/484e414a/tmd.1024 b/nitrofiles/484e414a/tmd.1024 new file mode 100644 index 0000000..7df516a Binary files /dev/null and b/nitrofiles/484e414a/tmd.1024 differ diff --git a/nitrofiles/484e414a/tmd.1024.patch.sha1 b/nitrofiles/484e414a/tmd.1024.patch.sha1 new file mode 100644 index 0000000..ce16cbe --- /dev/null +++ b/nitrofiles/484e414a/tmd.1024.patch.sha1 @@ -0,0 +1 @@ +ea8006223ad563928c0174c5792e9d823ab6bd3a \ No newline at end of file diff --git a/nitrofiles/484e414a/tmd.1024.sha1 b/nitrofiles/484e414a/tmd.1024.sha1 new file mode 100644 index 0000000..1118e92 --- /dev/null +++ b/nitrofiles/484e414a/tmd.1024.sha1 @@ -0,0 +1 @@ +dbbebf6f8c5697e1eb1727a6a20c7a077670c30c \ No newline at end of file diff --git a/nitrofiles/484e414a/tmd.1280 b/nitrofiles/484e414a/tmd.1280 new file mode 100644 index 0000000..21a55c3 Binary files /dev/null and b/nitrofiles/484e414a/tmd.1280 differ diff --git a/nitrofiles/484e414a/tmd.1280.patch.sha1 b/nitrofiles/484e414a/tmd.1280.patch.sha1 new file mode 100644 index 0000000..d73efd8 --- /dev/null +++ b/nitrofiles/484e414a/tmd.1280.patch.sha1 @@ -0,0 +1 @@ +9a51af752391184023f9bf2bfe33e9a17af7f977 \ No newline at end of file diff --git a/nitrofiles/484e414a/tmd.1280.sha1 b/nitrofiles/484e414a/tmd.1280.sha1 new file mode 100644 index 0000000..42e8d1b --- /dev/null +++ b/nitrofiles/484e414a/tmd.1280.sha1 @@ -0,0 +1 @@ +470a6087932b7a435f879ad2ff695c4e097eae22 \ No newline at end of file diff --git a/nitrofiles/484e414a/tmd.1536 b/nitrofiles/484e414a/tmd.1536 new file mode 100644 index 0000000..b4b01c1 Binary files /dev/null and b/nitrofiles/484e414a/tmd.1536 differ diff --git a/nitrofiles/484e414a/tmd.1536.patch.sha1 b/nitrofiles/484e414a/tmd.1536.patch.sha1 new file mode 100644 index 0000000..d1016ca --- /dev/null +++ b/nitrofiles/484e414a/tmd.1536.patch.sha1 @@ -0,0 +1 @@ +fa9d59ec03d9f8b31065bf7327d3d8ba15b61e97 \ No newline at end of file diff --git a/nitrofiles/484e414a/tmd.1536.sha1 b/nitrofiles/484e414a/tmd.1536.sha1 new file mode 100644 index 0000000..23e9527 --- /dev/null +++ b/nitrofiles/484e414a/tmd.1536.sha1 @@ -0,0 +1 @@ +54264f425a499bc1ea13a6dd20e2f8c3e2c271ee \ No newline at end of file diff --git a/nitrofiles/484e414a/tmd.1792 b/nitrofiles/484e414a/tmd.1792 new file mode 100644 index 0000000..7c8f104 Binary files /dev/null and b/nitrofiles/484e414a/tmd.1792 differ diff --git a/nitrofiles/484e414a/tmd.1792.patch.sha1 b/nitrofiles/484e414a/tmd.1792.patch.sha1 new file mode 100644 index 0000000..b1c5503 --- /dev/null +++ b/nitrofiles/484e414a/tmd.1792.patch.sha1 @@ -0,0 +1 @@ +ad741b0ef09b4a5f1f35f5737c8abd7b2edb9239 \ No newline at end of file diff --git a/nitrofiles/484e414a/tmd.1792.sha1 b/nitrofiles/484e414a/tmd.1792.sha1 new file mode 100644 index 0000000..b37aeaf --- /dev/null +++ b/nitrofiles/484e414a/tmd.1792.sha1 @@ -0,0 +1 @@ +c731a5a43941ff12d6814e0fc8b4f41b0481aa21 \ No newline at end of file diff --git a/nitrofiles/484e414a/tmd.256 b/nitrofiles/484e414a/tmd.256 new file mode 100644 index 0000000..e3f6fe8 Binary files /dev/null and b/nitrofiles/484e414a/tmd.256 differ diff --git a/nitrofiles/484e414a/tmd.256.patch.sha1 b/nitrofiles/484e414a/tmd.256.patch.sha1 new file mode 100644 index 0000000..9a901b3 --- /dev/null +++ b/nitrofiles/484e414a/tmd.256.patch.sha1 @@ -0,0 +1 @@ +3b321c1e135fcbde14b9e2016c5d4b6abd19bdea \ No newline at end of file diff --git a/nitrofiles/484e414a/tmd.256.sha1 b/nitrofiles/484e414a/tmd.256.sha1 new file mode 100644 index 0000000..0c4b829 --- /dev/null +++ b/nitrofiles/484e414a/tmd.256.sha1 @@ -0,0 +1 @@ +84796177e89ec2687929becfb9a83481ae93f077 \ No newline at end of file diff --git a/nitrofiles/484e414a/tmd.512 b/nitrofiles/484e414a/tmd.512 new file mode 100644 index 0000000..822b24c Binary files /dev/null and b/nitrofiles/484e414a/tmd.512 differ diff --git a/nitrofiles/484e414a/tmd.512.patch.sha1 b/nitrofiles/484e414a/tmd.512.patch.sha1 new file mode 100644 index 0000000..c8f10e3 --- /dev/null +++ b/nitrofiles/484e414a/tmd.512.patch.sha1 @@ -0,0 +1 @@ +efc5c2e832373f76a0fa3e02aa9ba57c31b7b450 \ No newline at end of file diff --git a/nitrofiles/484e414a/tmd.512.sha1 b/nitrofiles/484e414a/tmd.512.sha1 new file mode 100644 index 0000000..c778286 --- /dev/null +++ b/nitrofiles/484e414a/tmd.512.sha1 @@ -0,0 +1 @@ +6a20da037dd7fcb454bdf5b3f3553f4fa37a24ce \ No newline at end of file diff --git a/nitrofiles/484e414a/tmd.768 b/nitrofiles/484e414a/tmd.768 new file mode 100644 index 0000000..39f6c5e Binary files /dev/null and b/nitrofiles/484e414a/tmd.768 differ diff --git a/nitrofiles/484e414a/tmd.768.patch.sha1 b/nitrofiles/484e414a/tmd.768.patch.sha1 new file mode 100644 index 0000000..e561c55 --- /dev/null +++ b/nitrofiles/484e414a/tmd.768.patch.sha1 @@ -0,0 +1 @@ +95898a6eeed084bc20c2d39ce6467c1351eaf4a5 \ No newline at end of file diff --git a/nitrofiles/484e414a/tmd.768.sha1 b/nitrofiles/484e414a/tmd.768.sha1 new file mode 100644 index 0000000..6fffc88 --- /dev/null +++ b/nitrofiles/484e414a/tmd.768.sha1 @@ -0,0 +1 @@ +ce3df01d150ef8a543b9916a7ff811f41d947813 \ No newline at end of file diff --git a/nitrofiles/484e414b/tmd.1024 b/nitrofiles/484e414b/tmd.1024 new file mode 100644 index 0000000..550cbb1 Binary files /dev/null and b/nitrofiles/484e414b/tmd.1024 differ diff --git a/nitrofiles/484e414b/tmd.1024.patch.sha1 b/nitrofiles/484e414b/tmd.1024.patch.sha1 new file mode 100644 index 0000000..d07b5b6 --- /dev/null +++ b/nitrofiles/484e414b/tmd.1024.patch.sha1 @@ -0,0 +1 @@ +9ab4d682b3b1c152da66272c1be952e2b8b76824 \ No newline at end of file diff --git a/nitrofiles/484e414b/tmd.1024.sha1 b/nitrofiles/484e414b/tmd.1024.sha1 new file mode 100644 index 0000000..6006a2a --- /dev/null +++ b/nitrofiles/484e414b/tmd.1024.sha1 @@ -0,0 +1 @@ +ddb3908d8dfd29eba996caeaed79e9356c8a6d27 \ No newline at end of file diff --git a/nitrofiles/484e414b/tmd.1280 b/nitrofiles/484e414b/tmd.1280 new file mode 100644 index 0000000..dde14d3 Binary files /dev/null and b/nitrofiles/484e414b/tmd.1280 differ diff --git a/nitrofiles/484e414b/tmd.1280.patch.sha1 b/nitrofiles/484e414b/tmd.1280.patch.sha1 new file mode 100644 index 0000000..545cb5f --- /dev/null +++ b/nitrofiles/484e414b/tmd.1280.patch.sha1 @@ -0,0 +1 @@ +049a12c7ab4d714409554e51ba4ba420f790ada4 \ No newline at end of file diff --git a/nitrofiles/484e414b/tmd.1280.sha1 b/nitrofiles/484e414b/tmd.1280.sha1 new file mode 100644 index 0000000..82ccd85 --- /dev/null +++ b/nitrofiles/484e414b/tmd.1280.sha1 @@ -0,0 +1 @@ +52dc147e431a7f219096165e1d1521b1a6dba705 \ No newline at end of file diff --git a/nitrofiles/484e414b/tmd.1536 b/nitrofiles/484e414b/tmd.1536 new file mode 100644 index 0000000..0eb6bae Binary files /dev/null and b/nitrofiles/484e414b/tmd.1536 differ diff --git a/nitrofiles/484e414b/tmd.1536.patch.sha1 b/nitrofiles/484e414b/tmd.1536.patch.sha1 new file mode 100644 index 0000000..d9922dd --- /dev/null +++ b/nitrofiles/484e414b/tmd.1536.patch.sha1 @@ -0,0 +1 @@ +9dc4d3093880a1ed965d0768f69099c160ad5c48 \ No newline at end of file diff --git a/nitrofiles/484e414b/tmd.1536.sha1 b/nitrofiles/484e414b/tmd.1536.sha1 new file mode 100644 index 0000000..c5c72f3 --- /dev/null +++ b/nitrofiles/484e414b/tmd.1536.sha1 @@ -0,0 +1 @@ +d3449c4cbfb0904246ad2091a30c11b40c48ef16 \ No newline at end of file diff --git a/nitrofiles/484e414b/tmd.1792 b/nitrofiles/484e414b/tmd.1792 new file mode 100644 index 0000000..7f0d5de Binary files /dev/null and b/nitrofiles/484e414b/tmd.1792 differ diff --git a/nitrofiles/484e414b/tmd.1792.patch.sha1 b/nitrofiles/484e414b/tmd.1792.patch.sha1 new file mode 100644 index 0000000..4891ccd --- /dev/null +++ b/nitrofiles/484e414b/tmd.1792.patch.sha1 @@ -0,0 +1 @@ +68e1f16adc4a25bc8b63a741004be6b8bd098517 \ No newline at end of file diff --git a/nitrofiles/484e414b/tmd.1792.sha1 b/nitrofiles/484e414b/tmd.1792.sha1 new file mode 100644 index 0000000..6552d7d --- /dev/null +++ b/nitrofiles/484e414b/tmd.1792.sha1 @@ -0,0 +1 @@ +c4e583b568e6f52ffa9cb6a4d3f810660ba5532f \ No newline at end of file diff --git a/nitrofiles/484e414b/tmd.512 b/nitrofiles/484e414b/tmd.512 new file mode 100644 index 0000000..b154f99 Binary files /dev/null and b/nitrofiles/484e414b/tmd.512 differ diff --git a/nitrofiles/484e414b/tmd.512.patch.sha1 b/nitrofiles/484e414b/tmd.512.patch.sha1 new file mode 100644 index 0000000..09a6c64 --- /dev/null +++ b/nitrofiles/484e414b/tmd.512.patch.sha1 @@ -0,0 +1 @@ +e483dcfd3fa330dc95fe349c0fa95f32ccb6f6ec \ No newline at end of file diff --git a/nitrofiles/484e414b/tmd.512.sha1 b/nitrofiles/484e414b/tmd.512.sha1 new file mode 100644 index 0000000..0b677a8 --- /dev/null +++ b/nitrofiles/484e414b/tmd.512.sha1 @@ -0,0 +1 @@ +8b94dea2b03055a5729e61a247ee70df0d9ebbff \ No newline at end of file diff --git a/nitrofiles/484e414b/tmd.768 b/nitrofiles/484e414b/tmd.768 new file mode 100644 index 0000000..e2f22cc Binary files /dev/null and b/nitrofiles/484e414b/tmd.768 differ diff --git a/nitrofiles/484e414b/tmd.768.patch.sha1 b/nitrofiles/484e414b/tmd.768.patch.sha1 new file mode 100644 index 0000000..4035995 --- /dev/null +++ b/nitrofiles/484e414b/tmd.768.patch.sha1 @@ -0,0 +1 @@ +86ca8b148a65462b51e59b6d0f47a3fd6da1a597 \ No newline at end of file diff --git a/nitrofiles/484e414b/tmd.768.sha1 b/nitrofiles/484e414b/tmd.768.sha1 new file mode 100644 index 0000000..b628fbe --- /dev/null +++ b/nitrofiles/484e414b/tmd.768.sha1 @@ -0,0 +1 @@ +8bda71fb406de03486825c27c653d8968c039fe3 \ No newline at end of file diff --git a/nitrofiles/484e4150/tmd.1024 b/nitrofiles/484e4150/tmd.1024 new file mode 100644 index 0000000..3f6cd9c Binary files /dev/null and b/nitrofiles/484e4150/tmd.1024 differ diff --git a/nitrofiles/484e4150/tmd.1024.patch.sha1 b/nitrofiles/484e4150/tmd.1024.patch.sha1 new file mode 100644 index 0000000..2053caf --- /dev/null +++ b/nitrofiles/484e4150/tmd.1024.patch.sha1 @@ -0,0 +1 @@ +f60acf3acadb565d08719a79efaba5231f077a62 \ No newline at end of file diff --git a/nitrofiles/484e4150/tmd.1024.sha1 b/nitrofiles/484e4150/tmd.1024.sha1 new file mode 100644 index 0000000..1f74f29 --- /dev/null +++ b/nitrofiles/484e4150/tmd.1024.sha1 @@ -0,0 +1 @@ +1141459540fd9df26208609a41db5eb19fce2093 \ No newline at end of file diff --git a/nitrofiles/484e4150/tmd.1280 b/nitrofiles/484e4150/tmd.1280 new file mode 100644 index 0000000..3ef63d1 Binary files /dev/null and b/nitrofiles/484e4150/tmd.1280 differ diff --git a/nitrofiles/484e4150/tmd.1280.patch.sha1 b/nitrofiles/484e4150/tmd.1280.patch.sha1 new file mode 100644 index 0000000..a14cbfd --- /dev/null +++ b/nitrofiles/484e4150/tmd.1280.patch.sha1 @@ -0,0 +1 @@ +60374b640ce21b3cae134b6ee29d16eabbaaad6d \ No newline at end of file diff --git a/nitrofiles/484e4150/tmd.1280.sha1 b/nitrofiles/484e4150/tmd.1280.sha1 new file mode 100644 index 0000000..09bb34f --- /dev/null +++ b/nitrofiles/484e4150/tmd.1280.sha1 @@ -0,0 +1 @@ +51e5befb51db74fb9fd0da19906dd5b03aaea92d \ No newline at end of file diff --git a/nitrofiles/484e4150/tmd.1536 b/nitrofiles/484e4150/tmd.1536 new file mode 100644 index 0000000..c607b5b Binary files /dev/null and b/nitrofiles/484e4150/tmd.1536 differ diff --git a/nitrofiles/484e4150/tmd.1536.patch.sha1 b/nitrofiles/484e4150/tmd.1536.patch.sha1 new file mode 100644 index 0000000..6b03aa8 --- /dev/null +++ b/nitrofiles/484e4150/tmd.1536.patch.sha1 @@ -0,0 +1 @@ +8fb6cd27d752b90628993a4745f147738af474ed \ No newline at end of file diff --git a/nitrofiles/484e4150/tmd.1536.sha1 b/nitrofiles/484e4150/tmd.1536.sha1 new file mode 100644 index 0000000..26ddd2d --- /dev/null +++ b/nitrofiles/484e4150/tmd.1536.sha1 @@ -0,0 +1 @@ +b14f07b0325f6e08c63b52bddfba7d35285e89d7 \ No newline at end of file diff --git a/nitrofiles/484e4150/tmd.1792 b/nitrofiles/484e4150/tmd.1792 new file mode 100644 index 0000000..313c033 Binary files /dev/null and b/nitrofiles/484e4150/tmd.1792 differ diff --git a/nitrofiles/484e4150/tmd.1792.patch.sha1 b/nitrofiles/484e4150/tmd.1792.patch.sha1 new file mode 100644 index 0000000..08c8c37 --- /dev/null +++ b/nitrofiles/484e4150/tmd.1792.patch.sha1 @@ -0,0 +1 @@ +ad8c172b60d313a8e42a93b82a66ba9fad02e48f \ No newline at end of file diff --git a/nitrofiles/484e4150/tmd.1792.sha1 b/nitrofiles/484e4150/tmd.1792.sha1 new file mode 100644 index 0000000..8c4668a --- /dev/null +++ b/nitrofiles/484e4150/tmd.1792.sha1 @@ -0,0 +1 @@ +59a52e25fd9ef37fe9f0b67d1be0cea376438641 \ No newline at end of file diff --git a/nitrofiles/484e4150/tmd.256 b/nitrofiles/484e4150/tmd.256 new file mode 100644 index 0000000..1ab16fe Binary files /dev/null and b/nitrofiles/484e4150/tmd.256 differ diff --git a/nitrofiles/484e4150/tmd.256.patch.sha1 b/nitrofiles/484e4150/tmd.256.patch.sha1 new file mode 100644 index 0000000..f7e163b --- /dev/null +++ b/nitrofiles/484e4150/tmd.256.patch.sha1 @@ -0,0 +1 @@ +7bac9563d8ad82cb1a17f108e4f838de217b9b79 \ No newline at end of file diff --git a/nitrofiles/484e4150/tmd.256.sha1 b/nitrofiles/484e4150/tmd.256.sha1 new file mode 100644 index 0000000..c91d38e --- /dev/null +++ b/nitrofiles/484e4150/tmd.256.sha1 @@ -0,0 +1 @@ +aa9d8a660235102398d7791d4220689ccee5db17 \ No newline at end of file diff --git a/nitrofiles/484e4150/tmd.512 b/nitrofiles/484e4150/tmd.512 new file mode 100644 index 0000000..152b271 Binary files /dev/null and b/nitrofiles/484e4150/tmd.512 differ diff --git a/nitrofiles/484e4150/tmd.512.patch.sha1 b/nitrofiles/484e4150/tmd.512.patch.sha1 new file mode 100644 index 0000000..1677797 --- /dev/null +++ b/nitrofiles/484e4150/tmd.512.patch.sha1 @@ -0,0 +1 @@ +953a49d6cb973b705ed244de44cd6514fdaf3097 \ No newline at end of file diff --git a/nitrofiles/484e4150/tmd.512.sha1 b/nitrofiles/484e4150/tmd.512.sha1 new file mode 100644 index 0000000..2d2e3be --- /dev/null +++ b/nitrofiles/484e4150/tmd.512.sha1 @@ -0,0 +1 @@ +0d5cebe83d237f94bc4b4f3c5d89e0f4f1f0910c \ No newline at end of file diff --git a/nitrofiles/484e4150/tmd.768 b/nitrofiles/484e4150/tmd.768 new file mode 100644 index 0000000..1d5ebfe Binary files /dev/null and b/nitrofiles/484e4150/tmd.768 differ diff --git a/nitrofiles/484e4150/tmd.768.patch.sha1 b/nitrofiles/484e4150/tmd.768.patch.sha1 new file mode 100644 index 0000000..ffb7c7a --- /dev/null +++ b/nitrofiles/484e4150/tmd.768.patch.sha1 @@ -0,0 +1 @@ +715b5135b96b92dc11bb7f15f4c9d24a1c69f83d \ No newline at end of file diff --git a/nitrofiles/484e4150/tmd.768.sha1 b/nitrofiles/484e4150/tmd.768.sha1 new file mode 100644 index 0000000..223e628 --- /dev/null +++ b/nitrofiles/484e4150/tmd.768.sha1 @@ -0,0 +1 @@ +85b0c85d356f9244b348a319ceaa747235b49205 \ No newline at end of file diff --git a/nitrofiles/484e4155/tmd.1024 b/nitrofiles/484e4155/tmd.1024 new file mode 100644 index 0000000..7896a59 Binary files /dev/null and b/nitrofiles/484e4155/tmd.1024 differ diff --git a/nitrofiles/484e4155/tmd.1024.patch.sha1 b/nitrofiles/484e4155/tmd.1024.patch.sha1 new file mode 100644 index 0000000..4683d22 --- /dev/null +++ b/nitrofiles/484e4155/tmd.1024.patch.sha1 @@ -0,0 +1 @@ +58e72dd4db37392add6c90e57d45738596e1e4e1 \ No newline at end of file diff --git a/nitrofiles/484e4155/tmd.1024.sha1 b/nitrofiles/484e4155/tmd.1024.sha1 new file mode 100644 index 0000000..5f6f5d6 --- /dev/null +++ b/nitrofiles/484e4155/tmd.1024.sha1 @@ -0,0 +1 @@ +317c8fb18be531edc349657b082bb2f019eb00f0 \ No newline at end of file diff --git a/nitrofiles/484e4155/tmd.1280 b/nitrofiles/484e4155/tmd.1280 new file mode 100644 index 0000000..411aea9 Binary files /dev/null and b/nitrofiles/484e4155/tmd.1280 differ diff --git a/nitrofiles/484e4155/tmd.1280.patch.sha1 b/nitrofiles/484e4155/tmd.1280.patch.sha1 new file mode 100644 index 0000000..5f2888d --- /dev/null +++ b/nitrofiles/484e4155/tmd.1280.patch.sha1 @@ -0,0 +1 @@ +849d5e690d99989ec9e17dfced89e68a2ceb0950 \ No newline at end of file diff --git a/nitrofiles/484e4155/tmd.1280.sha1 b/nitrofiles/484e4155/tmd.1280.sha1 new file mode 100644 index 0000000..e901936 --- /dev/null +++ b/nitrofiles/484e4155/tmd.1280.sha1 @@ -0,0 +1 @@ +9463fdc0fb1bb75fa54e70844fcfb07b2552f928 \ No newline at end of file diff --git a/nitrofiles/484e4155/tmd.1536 b/nitrofiles/484e4155/tmd.1536 new file mode 100644 index 0000000..4a3dc3c Binary files /dev/null and b/nitrofiles/484e4155/tmd.1536 differ diff --git a/nitrofiles/484e4155/tmd.1536.patch.sha1 b/nitrofiles/484e4155/tmd.1536.patch.sha1 new file mode 100644 index 0000000..2a5bdeb --- /dev/null +++ b/nitrofiles/484e4155/tmd.1536.patch.sha1 @@ -0,0 +1 @@ +326d93f7d98ccaa501b7cfe2df7643ab0240e65e \ No newline at end of file diff --git a/nitrofiles/484e4155/tmd.1536.sha1 b/nitrofiles/484e4155/tmd.1536.sha1 new file mode 100644 index 0000000..94e28a5 --- /dev/null +++ b/nitrofiles/484e4155/tmd.1536.sha1 @@ -0,0 +1 @@ +2f2d4d2b0d322ae3ca9fe5aebc901af34cb31af2 \ No newline at end of file diff --git a/nitrofiles/484e4155/tmd.1792 b/nitrofiles/484e4155/tmd.1792 new file mode 100644 index 0000000..2e4c387 Binary files /dev/null and b/nitrofiles/484e4155/tmd.1792 differ diff --git a/nitrofiles/484e4155/tmd.1792.patch.sha1 b/nitrofiles/484e4155/tmd.1792.patch.sha1 new file mode 100644 index 0000000..f9f564e --- /dev/null +++ b/nitrofiles/484e4155/tmd.1792.patch.sha1 @@ -0,0 +1 @@ +7ca86964bb72c8f1cbeb80abff372b2bd9aed62e \ No newline at end of file diff --git a/nitrofiles/484e4155/tmd.1792.sha1 b/nitrofiles/484e4155/tmd.1792.sha1 new file mode 100644 index 0000000..0b65390 --- /dev/null +++ b/nitrofiles/484e4155/tmd.1792.sha1 @@ -0,0 +1 @@ +2847ac650cca6f884124fe8803c830945f114da1 \ No newline at end of file diff --git a/nitrofiles/484e4155/tmd.256 b/nitrofiles/484e4155/tmd.256 new file mode 100644 index 0000000..fec6a00 Binary files /dev/null and b/nitrofiles/484e4155/tmd.256 differ diff --git a/nitrofiles/484e4155/tmd.256.patch.sha1 b/nitrofiles/484e4155/tmd.256.patch.sha1 new file mode 100644 index 0000000..57dd3c5 --- /dev/null +++ b/nitrofiles/484e4155/tmd.256.patch.sha1 @@ -0,0 +1 @@ +df8002ff01bb3d07a6972141024d43228b8703d1 \ No newline at end of file diff --git a/nitrofiles/484e4155/tmd.256.sha1 b/nitrofiles/484e4155/tmd.256.sha1 new file mode 100644 index 0000000..aa3965f --- /dev/null +++ b/nitrofiles/484e4155/tmd.256.sha1 @@ -0,0 +1 @@ +de7020064cfe5e6aec10455b86bd8e1d432ec9a9 \ No newline at end of file diff --git a/nitrofiles/484e4155/tmd.512 b/nitrofiles/484e4155/tmd.512 new file mode 100644 index 0000000..7aa494d Binary files /dev/null and b/nitrofiles/484e4155/tmd.512 differ diff --git a/nitrofiles/484e4155/tmd.512.patch.sha1 b/nitrofiles/484e4155/tmd.512.patch.sha1 new file mode 100644 index 0000000..3d4e4f4 --- /dev/null +++ b/nitrofiles/484e4155/tmd.512.patch.sha1 @@ -0,0 +1 @@ +e3661ab33099fed402bcaf35cc17c24f54680e2c \ No newline at end of file diff --git a/nitrofiles/484e4155/tmd.512.sha1 b/nitrofiles/484e4155/tmd.512.sha1 new file mode 100644 index 0000000..fa3cc89 --- /dev/null +++ b/nitrofiles/484e4155/tmd.512.sha1 @@ -0,0 +1 @@ +7348e2b773e2aedc3e509e3b9df1cf2bbd33faa8 \ No newline at end of file diff --git a/nitrofiles/484e4155/tmd.768 b/nitrofiles/484e4155/tmd.768 new file mode 100644 index 0000000..d88d4ce Binary files /dev/null and b/nitrofiles/484e4155/tmd.768 differ diff --git a/nitrofiles/484e4155/tmd.768.patch.sha1 b/nitrofiles/484e4155/tmd.768.patch.sha1 new file mode 100644 index 0000000..fc97737 --- /dev/null +++ b/nitrofiles/484e4155/tmd.768.patch.sha1 @@ -0,0 +1 @@ +8cb3e55d23f77024ba231fb293b3df3328d8b6d4 \ No newline at end of file diff --git a/nitrofiles/484e4155/tmd.768.sha1 b/nitrofiles/484e4155/tmd.768.sha1 new file mode 100644 index 0000000..e697d32 --- /dev/null +++ b/nitrofiles/484e4155/tmd.768.sha1 @@ -0,0 +1 @@ +59fd7fad402f379d9b966e06fe8691a28e94091f \ No newline at end of file