From 94cb35df6f94bc052f64577d3922ba91edda6fc7 Mon Sep 17 00:00:00 2001 From: Edoardo Lolletti Date: Fri, 26 Apr 2024 19:03:23 +0200 Subject: [PATCH] Supports patching unlaunch with custom backgrounds --- arm9/src/bgMenu.cpp | 75 ++++++++++++++ arm9/src/bgMenu.h | 14 +++ arm9/src/main.c | 26 ++++- arm9/src/menu.c | 4 +- arm9/src/menu.h | 2 +- arm9/src/tonccpy.h | 43 ++++++++ arm9/src/tonccpy.itcm.c | 136 +++++++++++++++++++++++++ arm9/src/unlaunch.cpp | 80 +++++++++++++-- arm9/src/unlaunch.h | 2 +- nitrofiles/backgrounds/black.gif | Bin 0 -> 351 bytes nitrofiles/backgrounds/desert.gif | Bin 0 -> 14363 bytes nitrofiles/backgrounds/desert_gray.gif | Bin 0 -> 14875 bytes 12 files changed, 370 insertions(+), 12 deletions(-) create mode 100644 arm9/src/bgMenu.cpp create mode 100644 arm9/src/bgMenu.h create mode 100644 arm9/src/tonccpy.h create mode 100644 arm9/src/tonccpy.itcm.c create mode 100644 nitrofiles/backgrounds/black.gif create mode 100644 nitrofiles/backgrounds/desert.gif create mode 100644 nitrofiles/backgrounds/desert_gray.gif diff --git a/arm9/src/bgMenu.cpp b/arm9/src/bgMenu.cpp new file mode 100644 index 0000000..44114ce --- /dev/null +++ b/arm9/src/bgMenu.cpp @@ -0,0 +1,75 @@ +#include "bgMenu.h" +#include "main.h" +#include "menu.h" + +#include +#include +#include +#include + +static const auto& getBackgroundList() +{ + static auto bgs = []{ + std::vector> bgs; + static const std::string bgstr{"nitro:/backgrounds/"}; + auto* pdir = opendir("nitro:/backgrounds"); + if(!pdir) return bgs; + dirent* pent; + while((pent = readdir(pdir))) { + if(pent->d_type == DT_DIR) + continue; + std::string name{pent->d_name}; + if(!name.ends_with(".gif") && !name.ends_with(".GIF")) + continue; + bgs.emplace_back(name.substr(0, name.size() - 4), bgstr + name); + } + closedir(pdir); + return bgs; + }(); + return bgs; +} + +const char* backgroundMenu() +{ + //top screen + clearScreen(&topScreen); + + //menu + Menu* m = newMenu(); + setMenuHeader(m, "BACKGROUNDS"); + + const auto& bgs = getBackgroundList(); + + for(const auto& [bgName, bgPath] : bgs) + { + addMenuItem(m, bgName.data(), nullptr, 0); + } + addMenuItem(m, "Default", nullptr, 0); + addMenuItem(m, "Cancel", nullptr, 0); + + m->cursor = 0; + + //bottom screen + printMenu(m); + + while (!programEnd) + { + swiWaitForVBlank(); + scanKeys(); + + if (moveCursor(m)) + printMenu(m); + + if (keysDown() & KEY_A) + break; + } + + const char* result = nullptr; + if(static_cast(m->cursor) < bgs.size()) + result = bgs[m->cursor].second.data(); + else if(static_cast(m->cursor) == bgs.size()) + result = "default"; + freeMenu(m); + + return result; +} \ No newline at end of file diff --git a/arm9/src/bgMenu.h b/arm9/src/bgMenu.h new file mode 100644 index 0000000..1ad40d9 --- /dev/null +++ b/arm9/src/bgMenu.h @@ -0,0 +1,14 @@ +#ifndef BGMENU_H +#define BGMENU_H + +#ifdef __cplusplus +extern "C" { +#endif + +const char* backgroundMenu(); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/arm9/src/main.c b/arm9/src/main.c index 65db340..b43ba5b 100644 --- a/arm9/src/main.c +++ b/arm9/src/main.c @@ -1,3 +1,4 @@ +#include "bgMenu.h" #include "main.h" #include "menu.h" #include "message.h" @@ -17,6 +18,7 @@ static UNLAUNCH_VERSION foundUnlaunchInstallerVersion = INVALID; static bool disableAllPatches = false; static bool enableSoundAndSplash = false; static const char* splashSoundBinaryPatchPath = NULL; +static const char* customBgPath = NULL; bool charging = false; u8 batteryLevel = 0; @@ -25,6 +27,7 @@ PrintConsole bottomScreen; enum { MAIN_MENU_SAFE_UNLAUNCH_UNINSTALL, + MAIN_MENU_CUSTOM_BG, MAIN_MENU_TID_PATCHES, MAIN_MENU_SOUND_SPLASH_PATCHES, MAIN_MENU_SAFE_UNLAUNCH_INSTALL, @@ -69,8 +72,9 @@ static int mainMenu(int cursor) Menu* m = newMenu(); setMenuHeader(m, "MAIN MENU"); - char uninstallStr[32], installStr[32], soundPatchesStr[64], tidPatchesStr[32]; + char uninstallStr[32], installStr[32], soundPatchesStr[64], tidPatchesStr[32], customBgStr[32]; sprintf(uninstallStr, "\x1B[%02omUninstall unlaunch", unlaunchFound ? 047 : 037); + sprintf(customBgStr, "\x1B[%02omCustom background", (foundUnlaunchInstallerVersion != INVALID) ? 047 : 037); sprintf(tidPatchesStr, "\x1B[%02omDisable all patches: %s", (foundUnlaunchInstallerVersion == v1_9 || foundUnlaunchInstallerVersion == v2_0) ? 047 : 037, disableAllPatches ? "On" : "Off"); @@ -79,6 +83,7 @@ static int mainMenu(int cursor) enableSoundAndSplash ? "On" : "Off"); sprintf(installStr, "\x1B[%02omInstall unlaunch", (foundUnlaunchInstallerVersion != INVALID && !unlaunchFound) ? 047 : 037); addMenuItem(m, uninstallStr, NULL, 0); + addMenuItem(m, customBgStr, NULL, true); addMenuItem(m, tidPatchesStr, NULL, 0); addMenuItem(m, soundPatchesStr, NULL, 0); addMenuItem(m, installStr, NULL, 0); @@ -257,6 +262,22 @@ int main(int argc, char **argv) } break; + case MAIN_MENU_CUSTOM_BG: + if(foundUnlaunchInstallerVersion != INVALID) { + const char* customBg = backgroundMenu(); + if(!customBg) + break; + if(strcmp(customBg, "default") == 0) + { + customBgPath = NULL; + } + else + { + customBgPath = customBg; + } + } + break; + case MAIN_MENU_TID_PATCHES: if(foundUnlaunchInstallerVersion == v1_9 || foundUnlaunchInstallerVersion == v2_0) { disableAllPatches = !disableAllPatches; @@ -279,7 +300,8 @@ int main(int argc, char **argv) if(installUnlaunch(retailConsole, retailLauncherTmdPresentAndToBePatched ? retailLauncherTmdPath : NULL, disableAllPatches, - enableSoundAndSplash ? splashSoundBinaryPatchPath : NULL)) + enableSoundAndSplash ? splashSoundBinaryPatchPath : NULL, + customBgPath)) { messageBox("Install successful!\n"); unlaunchFound = true; diff --git a/arm9/src/menu.c b/arm9/src/menu.c index 026fc3e..9a2d422 100644 --- a/arm9/src/menu.c +++ b/arm9/src/menu.c @@ -77,7 +77,7 @@ void sortMenuItems(Menu* m) qsort(m->items, m->itemCount, sizeof(Item), alphabeticalCompare); } -void setMenuHeader(Menu* m, char* str) +void setMenuHeader(Menu* m, const char* str) { if (!m) return; @@ -87,7 +87,7 @@ void setMenuHeader(Menu* m, char* str) return; } - char* strPtr = str; + const char* strPtr = str; if (strlen(strPtr) > 30) strPtr = str + (strlen(strPtr) - 30); diff --git a/arm9/src/menu.h b/arm9/src/menu.h index 2942394..b6cb591 100644 --- a/arm9/src/menu.h +++ b/arm9/src/menu.h @@ -30,7 +30,7 @@ void freeMenu(Menu* m); void addMenuItem(Menu* m, char const* label, char const* value, bool directory); void sortMenuItems(Menu* m); -void setMenuHeader(Menu* m, char* str); +void setMenuHeader(Menu* m, const char* str); void resetMenu(Menu* m); void clearMenu(Menu* m); diff --git a/arm9/src/tonccpy.h b/arm9/src/tonccpy.h new file mode 100644 index 0000000..dd4267d --- /dev/null +++ b/arm9/src/tonccpy.h @@ -0,0 +1,43 @@ +//# Stuff you may not have yet. + +#ifndef TONCCPY_H +#define TONCCPY_H + + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef unsigned int uint; +#define BIT_MASK(len) ( (1<<(len))-1 ) +static inline u32 quad8(u16 x) { x |= x<<8; return x | x<<16; } + + +//# Declarations and inlines. + +void tonccpy(void *dst, const void *src, uint size); + +void __toncset(void *dst, u32 fill, uint size); +static inline void toncset(void *dst, u8 src, uint size); +static inline void toncset16(void *dst, u16 src, uint size); +static inline void toncset32(void *dst, u32 src, uint size); + + +//! VRAM-safe memset, byte version. Size in bytes. +static inline void toncset(void *dst, u8 src, uint size) +{ __toncset(dst, quad8(src), size); } + +//! VRAM-safe memset, halfword version. Size in hwords. +static inline void toncset16(void *dst, u16 src, uint size) +{ __toncset(dst, src|src<<16, size*2); } + +//! VRAM-safe memset, word version. Size in words. +static inline void toncset32(void *dst, u32 src, uint size) +{ __toncset(dst, src, size*4); } + +#ifdef __cplusplus +} +#endif +#endif diff --git a/arm9/src/tonccpy.itcm.c b/arm9/src/tonccpy.itcm.c new file mode 100644 index 0000000..a51437e --- /dev/null +++ b/arm9/src/tonccpy.itcm.c @@ -0,0 +1,136 @@ +#include "tonccpy.h" +//# tonccpy.c + +//! VRAM-safe cpy. +/*! This version mimics memcpy in functionality, with + the benefit of working for VRAM as well. It is also + slightly faster than the original memcpy, but faster + implementations can be made. + \param dst Destination pointer. + \param src Source pointer. + \param size Fill-length in bytes. + \note The pointers and size need not be word-aligned. +*/ +void tonccpy(void *dst, const void *src, uint size) +{ + if(size==0 || dst==0 || src==0) + return; + + uint count; + u16 *dst16; // hword destination + u8 *src8; // byte source + + // Ideal case: copy by 4x words. Leaves tail for later. + if( ((u32)src|(u32)dst)%4==0 && size>=4) + { + u32 *src32= (u32*)src, *dst32= (u32*)dst; + + count= size/4; + uint tmp= count&3; + count /= 4; + + // Duff's Device, good friend! + switch(tmp) { + do { *dst32++ = *src32++; + case 3: *dst32++ = *src32++; + case 2: *dst32++ = *src32++; + case 1: *dst32++ = *src32++; + case 0: ; } while(count--); + } + + // Check for tail + size &= 3; + if(size == 0) + return; + + src8= (u8*)src32; + dst16= (u16*)dst32; + } + else // Unaligned. + { + uint dstOfs= (u32)dst&1; + src8= (u8*)src; + dst16= (u16*)(dst-dstOfs); + + // Head: 1 byte. + if(dstOfs != 0) + { + *dst16= (*dst16 & 0xFF) | *src8++<<8; + dst16++; + if(--size==0) + return; + } + } + + // Unaligned main: copy by 2x byte. + count= size/2; + while(count--) + { + *dst16++ = src8[0] | src8[1]<<8; + src8 += 2; + } + + // Tail: 1 byte. + if(size&1) + *dst16= (*dst16 &~ 0xFF) | *src8; +} +//# toncset.c + +//! VRAM-safe memset, internal routine. +/*! This version mimics memset in functionality, with + the benefit of working for VRAM as well. It is also + slightly faster than the original memset. + \param dst Destination pointer. + \param fill Word to fill with. + \param size Fill-length in bytes. + \note The \a dst pointer and \a size need not be + word-aligned. In the case of unaligned fills, \a fill + will be masked off to match the situation. +*/ +void __toncset(void *dst, u32 fill, uint size) +{ + if(size==0 || dst==0) + return; + + uint left= (u32)dst&3; + u32 *dst32= (u32*)(dst-left); + u32 count, mask; + + // Unaligned head. + if(left != 0) + { + // Adjust for very small stint. + if(left+size<4) + { + mask= BIT_MASK(size*8)<<(left*8); + *dst32= (*dst32 &~ mask) | (fill & mask); + return; + } + + mask= BIT_MASK(left*8); + *dst32= (*dst32 & mask) | (fill&~mask); + dst32++; + size -= 4-left; + } + + // Main stint. + count= size/4; + uint tmp= count&3; + count /= 4; + + switch(tmp) { + do { *dst32++ = fill; + case 3: *dst32++ = fill; + case 2: *dst32++ = fill; + case 1: *dst32++ = fill; + case 0: ; } while(count--); + } + + // Tail + size &= 3; + if(size) + { + mask= BIT_MASK(size*8); + *dst32= (*dst32 &~ mask) | (fill & mask); + } +} diff --git a/arm9/src/unlaunch.cpp b/arm9/src/unlaunch.cpp index 8d99d7f..e90cfa8 100644 --- a/arm9/src/unlaunch.cpp +++ b/arm9/src/unlaunch.cpp @@ -1,15 +1,16 @@ #include "message.h" #include "sha1digest.h" #include "storage.h" +#include "tonccpy.h" #include "unlaunch.h" #include -#include #include #include #include #include static char unlaunchInstallerBuffer[0x30000]; +static char ogUnlaunchInstallerBuffer[0x30000]; static const char* hnaaTmdPath = "nand:/title/00030017/484e4141/content/title.tmd"; static const char* hnaaBackupTmdPath = "nand:/title/00030017/484e4141/content/title.tmd.bak"; @@ -32,6 +33,12 @@ constexpr std::array knownUnlaunchHashes{ "15f4a36251d1408d71114019b2825fe8f5b4c8cc"_sha1, // v2.0 }; +constexpr std::array gifOffsets{ + std::make_pair(0x48d4, 0x8540), /* 1.8 */ + std::make_pair(0x48c8, 0x8534), /* 1.9 */ + std::make_pair(0x48f0, 0x855c), /* 2.0 */ +}; + constexpr std::array blockAllPatchesOffset{ 0xae74, /* 1.9 */ 0xae91, /* 2.0 */ @@ -366,12 +373,12 @@ static bool readUnlaunchInstaller(const char* path) } int toRead = unlaunchInstallerSize; - char* buff = unlaunchInstallerBuffer; + auto* buff = unlaunchInstallerBuffer; // Pad the installer with 520 bytes, those being the size of a valid tmd buff += 520; size_t n = 0; - while (toRead != 0 && (n = fread(buff, sizeof(char), toRead, unlaunchInstaller)) > 0) + while (toRead != 0 && (n = fread(buff, sizeof(uint8_t), toRead, unlaunchInstaller)) > 0) { toRead -= n; buff += n; @@ -402,8 +409,64 @@ static bool verifyUnlaunchInstaller(void) return true; } -static bool patchUnlaunchInstaller(bool disableAllPatches, const char* splashSoundBinaryPatchPath) +static bool patchCustomBackground(const char* customBackgroundPath) { + if(!customBackgroundPath) + { + return true; + } + auto bgGif = fopen(customBackgroundPath, "rb"); + if(!bgGif) + { + messageBox("\x1B[31mError:\x1B[33m Failed to open custom bg gif.\n"); + return false; + } + auto size = getFileSize(bgGif); + if(size < 7 || size > 0x3C70) + { + messageBox("\x1B[31mError:\x1B[33m Invalid gif file.\n"); + fclose(bgGif); + return false; + } + u16 gifWidth; + u16 gifHeight; + if((fseek(bgGif, 6, SEEK_SET) != 0) || (fread(&gifWidth, 1, sizeof(u16), bgGif) != sizeof(u16)) || (fread(&gifHeight, 1, sizeof(u16), bgGif) != sizeof(u16))) + { + messageBox("\x1B[31mError:\x1B[33m Failed to parse gif file.\n"); + fclose(bgGif); + return false; + } + if (gifWidth != 256 || gifHeight != 192) { + messageBox("\x1B[31mError:\x1B[33m Gif file has invalid dimensions.\n"); + fclose(bgGif); + return false; + } + const u32 gifSignatureStart = 0x38464947; + const u32 gifSignatureEnd = 0x3B000044; + + auto [gifOffsetStart, gifOffsetEnd] = gifOffsets[installerVersion]; + + auto* gifStart = reinterpret_cast((unlaunchInstallerBuffer + 520) + gifOffsetStart); + auto* gifEnd = reinterpret_cast((unlaunchInstallerBuffer + 520) + gifOffsetEnd); + + if(*gifStart != gifSignatureStart || *gifEnd != gifSignatureEnd) + { + messageBox("\x1B[31mError:\x1B[33m Gif offsets not matching.\n"); + fclose(bgGif); + return false; + } + + fseek(bgGif, 0, SEEK_SET); + + //read the whole file, could be less than 0x3C70, but unlaunch should then just ignore the leftover data + fread(gifStart, 1, 0x3C70, bgGif); + + return true; +} + +static bool patchUnlaunchInstaller(bool disableAllPatches, const char* splashSoundBinaryPatchPath, const char* customBackgroundPath) +{ + tonccpy(unlaunchInstallerBuffer, ogUnlaunchInstallerBuffer, sizeof(unlaunchInstallerBuffer)); if(disableAllPatches) { if(installerVersion == v1_8) @@ -450,6 +513,10 @@ static bool patchUnlaunchInstaller(bool disableAllPatches, const char* splashSou } fclose(patch); } + if(!patchCustomBackground(customBackgroundPath)) + { + return false; + } return true; } @@ -457,14 +524,15 @@ UNLAUNCH_VERSION loadUnlaunchInstaller(const char* path) { if(readUnlaunchInstaller(path) && verifyUnlaunchInstaller()) { + tonccpy(ogUnlaunchInstallerBuffer, unlaunchInstallerBuffer, sizeof(unlaunchInstallerBuffer)); return installerVersion; } return INVALID; } -bool installUnlaunch(bool retailConsole, const char* retailLauncherTmdPath, bool disableAllPatches, const char* splashSoundBinaryPatchPath) +bool installUnlaunch(bool retailConsole, const char* retailLauncherTmdPath, bool disableAllPatches, const char* splashSoundBinaryPatchPath, const char* customBackgroundPath) { - if (installerVersion == INVALID || !patchUnlaunchInstaller(disableAllPatches, splashSoundBinaryPatchPath)) + if (installerVersion == INVALID || !patchUnlaunchInstaller(disableAllPatches, splashSoundBinaryPatchPath, customBackgroundPath)) return false; // Treat protos differently diff --git a/arm9/src/unlaunch.h b/arm9/src/unlaunch.h index 3910874..30e8541 100644 --- a/arm9/src/unlaunch.h +++ b/arm9/src/unlaunch.h @@ -14,7 +14,7 @@ typedef enum UNLAUNCH_VERSION { } UNLAUNCH_VERSION; bool uninstallUnlaunch(bool notProto, bool hasHNAABackup, const char* retailLauncherTmdPath); -bool installUnlaunch(bool retailConsole, const char* retailLauncherTmdPath, bool disableAllPatches, const char* splashSoundBinaryPatchPath); +bool installUnlaunch(bool retailConsole, const char* retailLauncherTmdPath, bool disableAllPatches, const char* splashSoundBinaryPatchPath, const char* customBackgroundPath); bool isLauncherTmdPatched(const char* path); diff --git a/nitrofiles/backgrounds/black.gif b/nitrofiles/backgrounds/black.gif new file mode 100644 index 0000000000000000000000000000000000000000..4c0930380174d65478d1cde07265b76edccdb254 GIT binary patch literal 351 zcmV-l0igazNk%w1VE_TZ0Du7i00030|NkNW5kqoiVRU6=Aa`kWXdp*PO;7+V00000 z00F=N00RDmkEzS;52Kv4+KaQ^y!#J^;z*X}iKgnxw(bkZ@=VwEjpzE#_x=wI3Wvm^ z@rX<+m&~T~35`mp)T;H0&1$#YuJ;QLi^t@$`HW7h*X*|Y4Ufy`^t%0y&+GU6zW)yx zC^$%1Xn2U2sJO`3==ca3DLF}5X?cm6skzD7>G=s7DmqG9YI=&As=CVB>iP;BD?3YD zYkP~EtGmnF>-!5FEIdqHY+LZGDZMt-a0N?fnfNE!Lp2r;6>i4-eZyofQQ x#wv{*J9_*GGNj0nBukn+i87_il`LDjdh zuj+%TnyQ|zmXVX@_d^!R=210BmVnS9@d{#0NQmQZP zl;k`V_+KcA=@@wV=&0Bj*d=HQMCeFGSm@-L$rYK2)tCvsaEJ+U3Q2!q(c>W0vd=agXV9AoJk@eCCOgTX~s{JA!gHP);ZHe427nKqs&j$Uz1KSZ4ai@MynJOk5$ zAu*lqf^Nb2&$+q(@x7kxRbI}6J}hZLLH?0t&;W(VnDmg?y!fcJkl2!mK!K?suF+tL zIqt$=3y&MBxLOiyUYE7;FcsVHt~D6DTSuF0!}K0p7DFRJRO zt!V5mEnP2xOqCWcmgcUMXHHaSOjMWj)wWeN4~*8MI~n$bbAmYfE$Iz)pR^ zOiRmBTiH=l-f~-gcke)7KlH4xd1tui&v4!Ac-8$(JM;wlAOG+F&;N@JP`)4lQ2_q{ z%z*#Re>VXD!vN=C5?<$+-XPE?URw{C7F5{vWFom`JdO1~>AX7P(?k+jo9%@)YUYw5NpjmDR#=5eHr z6-LgN>Qrd)=^cVGDFpf=NfjO|bZdF$$_>YxFZJ+kkjGebhNIKk-3hDJtW`}1dMrcL z2U2gNWmCfyVhu)h_GJg+ESJi38!%LJ#fJ_2Kh77Kut_CG9`WOz$It0j8F5XnF|97w z4mWS^HaB0kwIZ%2owQd?Iq)r9bxnnRbh>3TH@f=`LouvKjA##IGi)ijll3 ziT&z%B4-Zywt%bQ5Mr5<@U3pm#?YG&PpdAXY!BmGJ;8RmU7O7rsWV1nM$Gpstz#mX z$C<@yh@5|Myj8TV=ZPc)rQE^Fc*z-Cr?fl$7eh}8eJ>J8Nsbp9- z76SG%)Cwl~$~n{-$YGR)^Bi`yD=0zbRXTj|@!5waKdZRc5?Y?QH%jJYZ#RDYHeH_e zxn17g>OH*V+zB$}{3^{vn%uf%;8gcnU5`zeWt`d;qs=BIQCINjus0g_IBR^Ucz``p znE!Mkqc`OA2b}ca?t5#O^0FY_Oa*c$TLHUHei5i<*ZwF`SC zYnhh#+*Q7qL5yEH90Esl1F_u6hQsBBUi^(gF^A;V4B-oilAa0_nC6T}=OeB�GU| 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 BF$Vwu literal 0 HcmV?d00001