From d652f5a2eb6141458b639deddc47db3a2129fbcb Mon Sep 17 00:00:00 2001 From: rw-r-r-0644 Date: Wed, 2 Dec 2020 15:57:13 +0100 Subject: [PATCH] Reorganize menu layout --- source/ApplicationState.cpp | 585 ++++++++++++++---------------------- source/ApplicationState.h | 42 ++- source/InstallerService.cpp | 28 ++ source/InstallerService.h | 2 + source/Menu.h | 99 ++++++ 5 files changed, 376 insertions(+), 380 deletions(-) create mode 100644 source/Menu.h diff --git a/source/ApplicationState.cpp b/source/ApplicationState.cpp index 664205a..fdefaea 100644 --- a/source/ApplicationState.cpp +++ b/source/ApplicationState.cpp @@ -1,414 +1,265 @@ #include "ApplicationState.h" #include "WiiUScreen.h" #include "ScreenUtils.h" +#include "StringTools.h" #include "../build/safe_payload.h" #include #include extern "C" void OSShutdown(); -void ApplicationState::render() { - WiiUScreen::clearScreen(); - WiiUScreen::drawLine("Aroma Installer"); - WiiUScreen::drawLine("=================="); - WiiUScreen::drawLine(""); +void ApplicationState::changeState(eGameState newState) { + this->state = newState; + menu.clear(); if (this->state == STATE_ERROR) { - WiiUScreen::drawLine("The installation failed:"); - WiiUScreen::drawLine(); - WiiUScreen::drawLinef("Error: %s", ErrorMessage().c_str()); - WiiUScreen::drawLinef("Description: %s", ErrorDescription().c_str()); - WiiUScreen::drawLine(); - WiiUScreen::drawLine(); - WiiUScreen::drawLine("Press A to return to the Wii U Menu."); + menu.addText("The installation failed:"); + menu.addText(); + menu.addText("Error: " + ErrorMessage()); + menu.addText("Description: " + ErrorDescription()); + menu.addText(); + menu.addText(); + menu.addOption("Press A to return to the Wii U Menu.", STATE_EXIT_SYSMENU); } else if (this->state == STATE_WELCOME_SCREEN) { - WiiUScreen::drawLine("Welcome to the Aroma Installer!"); - WiiUScreen::drawLine("Do you want to check if an installation is possible?"); - WiiUScreen::drawLine(""); - if (this->selectedOption == 0) { - WiiUScreen::drawLine("> Check Exit"); - } else if (this->selectedOption == 1) { - WiiUScreen::drawLine(" Check > Exit"); - } + menu.addText("Welcome to the Aroma Installer!"); + menu.addText("Do you want to check if an installation is possible?"); + menu.addText(); + menu.addOption("Check", STATE_GET_APP_INFORMATION); + menu.addOption("Exit", STATE_EXIT_SYSMENU); } else if (this->state == STATE_GET_APP_INFORMATION) { - WiiUScreen::drawLine("Getting app information"); + menu.addText("Getting app information"); } else if (this->state == STATE_CHECK_PATCH_POSSIBLE) { - WiiUScreen::drawLine("Check if console can be patched."); + menu.addText("Check if console can be patched."); + } else if (this->state == STATE_CHECK_COLDBOOT_STATUS) { + menu.addText("Check if coldboot can be enabled."); } else if (this->state == STATE_CHECK_REMOVAL_POSSIBLE) { - WiiUScreen::drawLine("Check if Aroma can be removed."); - } else if (this->state == STATE_INSTALL_MENU) { - WiiUScreen::drawLinef("Compatible title:"); - WiiUScreen::drawLinef("%s", appInfo->appName); - WiiUScreen::drawLine(); - - if (this->fstAlreadyPatched) { - WiiUScreen::drawLine("[ X ] title.fst is already patched!"); - } else if (this->fstPatchPossible) { - WiiUScreen::drawLine("[ X ] title.fst can be patched!"); - } else { - WiiUScreen::drawLine("[ ] title.fst can NOT be patched!"); - } - if (this->cosAlreadyPatched) { - WiiUScreen::drawLine("[ X ] cos.xml is already patched!"); - } else if (this->cosPatchPossible) { - WiiUScreen::drawLine("[ X ] cos.xml can be patched!"); - } else { - WiiUScreen::drawLine("[ ] cos.xml can NOT be patched!"); - } - if (this->rpxAlreadyPatched) { - WiiUScreen::drawLine("[ X ] safe.rpx is already patched!"); - } else { - WiiUScreen::drawLine("[ X ] safe.rpx can to be patched!"); - } - - WiiUScreen::drawLine(); - WiiUScreen::drawLinef("System is booting into: "); - if (this->coldbootTitle == nullptr) { - WiiUScreen::drawLinef("%ll016X (Unknown title)", this->coldbootTitleId); - } else { - WiiUScreen::drawLinef("%ll016X (%s)", this->coldbootTitle->tid, this->coldbootTitle->name); - } - - WiiUScreen::drawLine(); - - if (!this->fstPatchPossible || !this->cosPatchPossible) { - WiiUScreen::drawLine("A safe installation of Aroma can not be provided."); - WiiUScreen::drawLine(); - WiiUScreen::drawLine("Press A to return to the Wii U Menu"); - } else { - std::string options = ""; - WiiUScreen::drawLine("Do you want to install Aroma?"); - WiiUScreen::drawLine(""); - - if (this->removalPossible) { - if (this->selectedOption == 0) { - WiiUScreen::drawLine("> Exit Install Remove"); - } else if (this->selectedOption == 1) { - WiiUScreen::drawLine(" Exit > Install Remove"); - } else if (this->selectedOption == 2) { - WiiUScreen::drawLine(" Exit Install > Remove"); - } + menu.addText("Check if Aroma can be removed."); + } else if (this->state == STATE_APP_INCOMPATIBLE) { + menu.addText("Sorry, Aroma cannot be safely installed to:"); + menu.addText(std::string(appInfo->appName)); + menu.addText(); + menu.addText("Additional informations:"); + auto showCheckResult = [&] (const std::string &name, bool canPatch, bool patched) { + if (patched) { + menu.addText("[ X ] " + name + "is already patched!"); + } else if (canPatch) { + menu.addText("[ X ] " + name + "can be patched!"); } else { - if (this->selectedOption == 0) { - WiiUScreen::drawLine("> Exit Install"); - } else if (this->selectedOption == 1) { - WiiUScreen::drawLine(" Exit > Install"); - } + menu.addText("[ ] " + name + "can NOT be patched!"); } + }; + showCheckResult("title.fst", this->fstPatchPossible, this->fstAlreadyPatched); + showCheckResult("cos.xml", this->cosPatchPossible, this->cosAlreadyPatched); + showCheckResult("safe.rpx", true, this->rpxAlreadyPatched); + menu.addText(); + menu.addOption("Exit", STATE_EXIT_SYSMENU); + } else if (this->state == STATE_MAIN_MENU) { + menu.addText("Aroma " + std::string(alreadyInstalled ? "is" : "can be") + " installed to:"); + menu.addText(std::string(appInfo->appName)); + menu.addText(); + menu.addOption("Install", STATE_INSTALL_CONFIRM_DIALOG); + menu.addOption("Boot options", STATE_BOOT_MENU); + if (this->removalPossible) { + menu.addOption("Remove", STATE_REMOVE_CONFIRM_DIALOG); } - } else if (this->state == STATE_INSTALL_CHOOSE_COLDBOOT) { - WiiUScreen::drawLine("Select your installation type:"); - WiiUScreen::drawLine(); - WiiUScreen::drawLine("[Coldboot] Aroma will launch directly after booting the console."); - WiiUScreen::drawLine("[No Coldboot] Aroma will need to be launched manually."); - WiiUScreen::drawLine(""); - if (this->selectedOption == 0) { - WiiUScreen::drawLine("> Back Coldboot No Coldboot"); - } else if (this->selectedOption == 1) { - WiiUScreen::drawLine(" Back > Coldboot No Coldboot"); - } else if (this->selectedOption == 2) { - WiiUScreen::drawLine(" Back Coldboot > No Coldboot"); - } - } else if (this->state == STATE_INSTALL_NO_COLDBOOT_ALLOWED) { - WiiUScreen::drawLine("Note: To install Aroma as coldboot you need to run this installer"); - WiiUScreen::drawLine("from an already running Aroma instance (and not the browser)"); - WiiUScreen::drawLine("After the installation has finished, reboot the console, open the"); - WiiUScreen::drawLine("Health & Safety app and run the Aroma installer."); - WiiUScreen::drawLine(); - if (this->selectedOption == 0) { - WiiUScreen::drawLine("> Back Install without Coldboot"); - } else if (this->selectedOption == 1) { - WiiUScreen::drawLine(" Back > Install without Coldboot"); - } + menu.addOption("Exit", STATE_EXIT_SYSMENU); } else if (this->state == STATE_INSTALL_CONFIRM_DIALOG) { - WiiUScreen::drawLine("Are you REALLY sure you want to install Aroma?"); - WiiUScreen::drawLine("Installing could permanently damage your console"); - WiiUScreen::drawLine(); - WiiUScreen::drawLine("After the installation you can NOT longer use:"); - WiiUScreen::drawLinef("- %s", appInfo->appName); - WiiUScreen::drawLine(); - WiiUScreen::drawLine("Selected installation type:"); - if (this->installColdboot) { - WiiUScreen::drawLine("- Coldboot"); - } else { - WiiUScreen::drawLine("- No Coldboot"); - } - - WiiUScreen::drawLine(); - WiiUScreen::drawLine(); - if (this->selectedOption == 0) { - WiiUScreen::drawLine("> Back Install"); - } else if (this->selectedOption == 1) { - WiiUScreen::drawLine(" Back > Install"); - } + menu.addText("Are you REALLY sure you want to install Aroma?"); + menu.addText("Installing could permanently damage your console"); + menu.addText(); + menu.addText("After the installation you can NO longer use:"); + menu.addText("- " + std::string(appInfo->appName)); + menu.addText(); + menu.addOption("Back", STATE_MAIN_MENU); + menu.addOption("Install", STATE_INSTALL_STARTED); } else if (this->state == STATE_INSTALL_STARTED) { - WiiUScreen::drawLine("Installing..."); - } else if (this->state == STATE_INSTALL_BACKUP) { - WiiUScreen::drawLine("... backing up files"); + menu.addText("Installing..."); } else if (this->state == STATE_INSTALL_FST) { - WiiUScreen::drawLine("... patching title.fst"); + menu.addText("... patching title.fst"); } else if (this->state == STATE_INSTALL_COS) { - WiiUScreen::drawLine("... patching cos.xml"); - } else if (this->state == STATE_INSTALL_SYSTEM_XML) { - WiiUScreen::drawLine("... patching system.xml"); + menu.addText("... patching cos.xml"); } else if (this->state == STATE_INSTALL_RPX) { - WiiUScreen::drawLine("... install safe.rpx"); + menu.addText("... install safe.rpx"); } else if (this->state == STATE_INSTALL_SUCCESS) { - WiiUScreen::drawLine("Aroma was successfully installed"); - WiiUScreen::drawLine(); - WiiUScreen::drawLine("Press A to shutdown the console"); + menu.addText("Aroma was successfully installed"); + menu.addText(); + menu.addOption("Press A to shutdown the console", STATE_EXIT_SHUTDOWN); } else if (this->state == STATE_REMOVE_CONFIRM_DIALOG) { - WiiUScreen::drawLine("Are you REALLY sure you want to remove Aroma?"); - WiiUScreen::drawLine("If you have installed unsigned system"); - WiiUScreen::drawLine("applications or modified system files"); - WiiUScreen::drawLine("this could make your console unusable"); - WiiUScreen::drawLine(); - WiiUScreen::drawLine(); - if (this->selectedOption == 0) { - WiiUScreen::drawLine("> Back Remove"); - } else if (this->selectedOption == 1) { - WiiUScreen::drawLine(" Back > Remove"); - } + menu.addText("Are you REALLY sure you want to remove Aroma?"); + menu.addText("If you have modified some system apps such as the"); + menu.addText("system menu this could make your console unusable"); + menu.addText(); + menu.addOption("Back", STATE_MAIN_MENU); + menu.addOption("Remove", STATE_REMOVE_STARTED); } else if (this->state == STATE_REMOVE_STARTED) { - WiiUScreen::drawLine("Removing..."); + menu.addText("Removing..."); } else if (this->state == STATE_REMOVE_COLDBOOT) { - WiiUScreen::drawLine("... remove system.xml coldboot patches"); + menu.addText("... remove system.xml coldboot patches"); } else if (this->state == STATE_REMOVE_AROMA) { - WiiUScreen::drawLine("... remove Aroma application patches"); + menu.addText("... remove Aroma application patches"); } else if (this->state == STATE_REMOVE_SUCCESS) { - WiiUScreen::drawLine("Aroma was successfully removed"); - WiiUScreen::drawLine(); - WiiUScreen::drawLine("Press A to shutdown the console"); + menu.addText("Aroma was successfully removed"); + menu.addText(); + menu.addOption("Press A to shutdown the console", STATE_EXIT_SHUTDOWN); + } else if (this->state == STATE_BOOT_MENU) { + menu.addText("System is currently booting into: "); + std::string titleId = StringTools::strfmt("%ll016X", this->coldbootTitleId); + std::string titleName = this->coldbootTitle ? + std::string(this->coldbootTitle->name) : "Unknown title"; + menu.addText(titleId + " (" + titleName + ")"); + menu.addText(); + + if (this->systemXMLRestorePossible && this->systemXMLAlreadyPatched) { + menu.addOption("Switch back to System Menu", STATE_BOOT_SWITCH_SYSMENU); + } else if (this->systemXMLPatchAllowed) { + menu.addOption("Switch to Aroma", STATE_BOOT_SWITCH_AROMA); + } else if (this->systemXMLPatchPossible) { + menu.addText("To change the system boot title to Aroma, you need to"); + menu.addText("launch this installer from an already running Aroma"); + menu.addText("instance, in order to verify that the installation"); + menu.addText("is working properly."); + menu.addText(); + menu.addText("After installing Aroma, reboot the console, open the"); + menu.addText("Health & Safety app and relaunch the Aroma installer."); + menu.addText(); + } else { + menu.addText("Sorry, your system.xml file has not yet been tested"); + menu.addText("with this tool. Boot options cannot be modified."); + menu.addText(); + } + menu.addOption("Back", STATE_MAIN_MENU); + } else if (this->state == STATE_BOOT_SWITCH_AROMA) { + menu.addText("Changing system.xml to boot " + std::string(this->appInfo->appName) + " ..."); + } else if (this->state == STATE_BOOT_SWITCH_SYSMENU) { + menu.addText("Changing system.xml to boot System Menu ..."); + } else if (this->state == STATE_BOOT_SWITCH_SUCCESS) { + menu.addText("Boot title successfully updated!"); + menu.addText(); + menu.addOption("Press A to shutdown the console", STATE_EXIT_SHUTDOWN); } - printFooter(); - WiiUScreen::flipBuffers(); + + this->state = newState; +} + +void ApplicationState::render() { + menu.render(); } void ApplicationState::update(Input *input) { if (this->state == STATE_ERROR) { OSEnableHomeButtonMenu(true); - if (entrySelected(input)) { - SYSLaunchMenu(); - } - } else if (this->state == STATE_WELCOME_SCREEN) { - proccessMenuNavigation(input, 2); - if (entrySelected(input)) { - if (this->selectedOption == 0) { - this->state = STATE_GET_APP_INFORMATION; - } else { - SYSLaunchMenu(); - } - this->selectedOption = 0; - return; - } } else if (this->state == STATE_GET_APP_INFORMATION) { getAppInformation(); } else if (this->state == STATE_CHECK_PATCH_POSSIBLE) { checkPatchPossible(); + } else if (this->state == STATE_CHECK_COLDBOOT_STATUS) { + checkColdbootStatus(); } else if (this->state == STATE_CHECK_REMOVAL_POSSIBLE) { checkRemovalPossible(); - } else if (this->state == STATE_INSTALL_MENU) { - if (this->fstPatchPossible && this->cosPatchPossible) { - proccessMenuNavigation(input, 2 + (this->removalPossible ? 1 : 0)); - if (entrySelected(input)) { - if (this->selectedOption == 1) { - if (systemXMLPatchPossible) { - this->state = STATE_INSTALL_CHOOSE_COLDBOOT; - this->installColdboot = false; - } else { - this->state = STATE_INSTALL_CONFIRM_DIALOG; - } - } else if ((this->selectedOption == 2) && this->removalPossible) { - this->state = STATE_REMOVE_CONFIRM_DIALOG; - } else { - SYSLaunchMenu(); - } - this->selectedOption = 0; - return; - } + } else if (this->state == STATE_COMPATIBILITY_RESULTS) { + if (this->installPossible) { + changeState(STATE_MAIN_MENU); } else { - if (entrySelected(input)) { - SYSLaunchMenu(); - } - } - } else if (this->state == STATE_INSTALL_CHOOSE_COLDBOOT) { - - if (!InstallerService::isColdBootAllowed()) { - this->installColdboot = false; - this->state = STATE_INSTALL_NO_COLDBOOT_ALLOWED; - return; - } - - proccessMenuNavigation(input, 3); - if (entrySelected(input)) { - if (this->selectedOption == 0) { // Back - this->state = STATE_INSTALL_MENU; - } else { - if (selectedOption == 1) { // Install with coldboot - this->installColdboot = true; - } - this->state = STATE_INSTALL_CONFIRM_DIALOG; - } - this->selectedOption = 0; - return; - } - } else if (this->state == STATE_INSTALL_NO_COLDBOOT_ALLOWED) { - proccessMenuNavigation(input, 2); - if (entrySelected(input)) { - if (this->selectedOption == 0) { - this->state = STATE_INSTALL_MENU; - } else { - this->state = STATE_INSTALL_CONFIRM_DIALOG; - } - this->selectedOption = 0; - } - } else if (this->state == STATE_INSTALL_CONFIRM_DIALOG) { - proccessMenuNavigation(input, 2); - if (entrySelected(input)) { - if (this->selectedOption == 0) { - this->state = STATE_INSTALL_MENU; - } else { - this->state = STATE_INSTALL_STARTED; - OSEnableHomeButtonMenu(false); - } - this->selectedOption = 0; - return; + changeState(STATE_APP_INCOMPATIBLE); } } else if (this->state == STATE_INSTALL_STARTED) { - this->state = STATE_INSTALL_BACKUP; + OSEnableHomeButtonMenu(false); + changeState(STATE_INSTALL_BACKUP); } else if (this->state == STATE_INSTALL_BACKUP) { auto result = InstallerService::backupAppFiles(this->appInfo->path); if (result != InstallerService::SUCCESS) { - setError(ERROR_INSTALLER_ERROR); this->installerError = result; + setError(ERROR_INSTALLER_ERROR); } else { - this->state = STATE_INSTALL_FST; + changeState(STATE_INSTALL_FST); } } else if (this->state == STATE_INSTALL_FST) { - auto result = InstallerService::patchFST(this->appInfo->path, this->appInfo->fstHash); + auto result = (this->fstAlreadyPatched) ? InstallerService::SUCCESS : + InstallerService::patchFST(this->appInfo->path, this->appInfo->fstHash); if (result != InstallerService::SUCCESS) { - setError(ERROR_INSTALLER_ERROR); this->installerError = result; + setError(ERROR_INSTALLER_ERROR); } else { - this->state = STATE_INSTALL_COS; + changeState(STATE_INSTALL_COS); } } else if (this->state == STATE_INSTALL_COS) { - auto result = InstallerService::patchCOS(this->appInfo->path, this->appInfo->cosHash); + auto result = (this->cosAlreadyPatched) ? InstallerService::SUCCESS : + InstallerService::patchCOS(this->appInfo->path, this->appInfo->cosHash); if (result != InstallerService::SUCCESS) { - setError(ERROR_INSTALLER_ERROR); this->installerError = result; + setError(ERROR_INSTALLER_ERROR); } else { - this->state = STATE_INSTALL_RPX; + changeState(STATE_INSTALL_RPX); } } else if (this->state == STATE_INSTALL_RPX) { auto result = InstallerService::copyRPX(this->appInfo->path, root_rpx, root_rpx_size, RPX_HASH); if (result != InstallerService::SUCCESS) { - setError(ERROR_INSTALLER_ERROR); this->installerError = result; - } else { - if (this->installColdboot) { - this->state = STATE_INSTALL_SYSTEM_XML; - } else { - this->state = STATE_INSTALL_SUCCESS; - } - } - } else if (this->state == STATE_INSTALL_SYSTEM_XML) { - auto result = InstallerService::patchSystemXML("storage_slc_installer:/config", this->appInfo->titleId); - if (result != InstallerService::SUCCESS) { setError(ERROR_INSTALLER_ERROR); - this->installerError = result; } else { - auto fsaFd = IOSUHAX_FSA_Open(); - if (fsaFd >= 0) { - if (IOSUHAX_FSA_FlushVolume(fsaFd, "/vol/storage_mlc01") == 0) { - DEBUG_FUNCTION_LINE("Flushed mlc"); - } - if (IOSUHAX_FSA_FlushVolume(fsaFd, "/vol/system") == 0) { - DEBUG_FUNCTION_LINE("Flushed slc"); - } - IOSUHAX_FSA_Close(fsaFd); - } else { - DEBUG_FUNCTION_LINE("Failed to open fsa"); - } - this->state = STATE_INSTALL_SUCCESS; - } - } else if (this->state == STATE_INSTALL_SUCCESS) { - if (entrySelected(input)) { - OSShutdown(); - } - } else if (this->state == STATE_REMOVE_CONFIRM_DIALOG) { - proccessMenuNavigation(input, 2); - if (entrySelected(input)) { - if (this->selectedOption == 0) { - this->state = STATE_INSTALL_MENU; - } else { - this->state = STATE_REMOVE_STARTED; - OSEnableHomeButtonMenu(false); - } - this->selectedOption = 0; - return; + changeState(STATE_INSTALL_SUCCESS); } } else if (this->state == STATE_REMOVE_STARTED) { - this->state = STATE_REMOVE_COLDBOOT; - } else if (this->state == STATE_REMOVE_COLDBOOT) { - auto result = InstallerService::patchSystemXML("storage_slc_installer:/config", *this->systemMenuTitleId); - if (result != InstallerService::SUCCESS) { - setError(ERROR_INSTALLER_ERROR); - this->installerError = result; + OSEnableHomeButtonMenu(false); + if (this->systemXMLAlreadyPatched) { + changeState(STATE_REMOVE_COLDBOOT); } else { - auto fsaFd = IOSUHAX_FSA_Open(); - if (fsaFd >= 0) { - if (IOSUHAX_FSA_FlushVolume(fsaFd, "/vol/storage_mlc01") == 0) { - DEBUG_FUNCTION_LINE("Flushed mlc"); - } - if (IOSUHAX_FSA_FlushVolume(fsaFd, "/vol/system") == 0) { - DEBUG_FUNCTION_LINE("Flushed slc"); - } - IOSUHAX_FSA_Close(fsaFd); - } else { - DEBUG_FUNCTION_LINE("Failed to open fsa"); - } - this->state = STATE_REMOVE_AROMA; + changeState(STATE_REMOVE_AROMA); + } + } else if (this->state == STATE_REMOVE_COLDBOOT) { + auto result = InstallerService::setBootTitle(*this->systemMenuTitleId); + if (result != InstallerService::SUCCESS) { + this->installerError = result; + setError(ERROR_INSTALLER_ERROR); + } else { + changeState(STATE_REMOVE_AROMA); } } else if (this->state == STATE_REMOVE_AROMA) { auto result = InstallerService::restoreAppFiles(this->appInfo->path); if (result != InstallerService::SUCCESS) { - setError(ERROR_INSTALLER_ERROR); this->installerError = result; + setError(ERROR_INSTALLER_ERROR); } else { - this->state = STATE_REMOVE_SUCCESS; + changeState(STATE_REMOVE_SUCCESS); } - } else if (this->state == STATE_REMOVE_SUCCESS) { - if (entrySelected(input)) { - OSShutdown(); + } else if (this->state == STATE_BOOT_SWITCH_SYSMENU) { + OSEnableHomeButtonMenu(false); + auto result = InstallerService::setBootTitle(*this->systemMenuTitleId); + if (result != InstallerService::SUCCESS) { + this->installerError = result; + setError(ERROR_INSTALLER_ERROR); + } else { + changeState(STATE_BOOT_SWITCH_SUCCESS); } + } else if (this->state == STATE_BOOT_SWITCH_AROMA) { + OSEnableHomeButtonMenu(false); + auto result = InstallerService::setBootTitle(this->appInfo->titleId); + if (result != InstallerService::SUCCESS) { + this->installerError = result; + setError(ERROR_INSTALLER_ERROR); + } else { + changeState(STATE_BOOT_SWITCH_SUCCESS); + } + } else if (this->state == STATE_EXIT_SYSMENU) { + SYSLaunchMenu(); + } else if (this->state == STATE_EXIT_SHUTDOWN) { + OSShutdown(); } + + menu.update(input); } ApplicationState::ApplicationState() { - this->state = STATE_WELCOME_SCREEN; - this->selectedOption = 0; + menu.setOptionsCallback(std::bind(&ApplicationState::changeState, this, std::placeholders::_1)); + menu.setHeader("Aroma Installer"); + menu.setFooter("By Maschell"); + + changeState(STATE_WELCOME_SCREEN); DEBUG_FUNCTION_LINE("State has changed to \"STATE_WELCOME_SCREEN\""); } void ApplicationState::checkPatchPossible() { DEBUG_FUNCTION_LINE("Check patch possible"); - if (!this->appInfo) { - this->state = STATE_ERROR; - this->error = ERROR_NO_APP_INSTALLED; - DEBUG_FUNCTION_LINE("ERROR"); - return; - } - - this->coldbootTitleId = InstallerService::getColdbootTitleId("storage_slc_installer:/config"); - - this->coldbootTitle = nullptr; - for (int i = 0; GameList[i].tid != 0; i++) { - if (GameList[i].tid == this->coldbootTitleId) { - this->coldbootTitle = &GameList[i]; - break; - } - } DEBUG_FUNCTION_LINE("CHECK FST"); @@ -427,28 +278,61 @@ void ApplicationState::checkPatchPossible() { if (result != InstallerService::SUCCESS) { DEBUG_FUNCTION_LINE("ERROR: %s", InstallerService::ErrorMessage(result).c_str()); } + + this->installPossible = this->fstPatchPossible && this->cosPatchPossible; + this->alreadyInstalled = this->fstAlreadyPatched && this->rpxAlreadyPatched && this->cosAlreadyPatched; + + changeState(STATE_CHECK_COLDBOOT_STATUS); +} + +void ApplicationState::checkColdbootStatus() { + DEBUG_FUNCTION_LINE("Check coldboot status"); + + this->coldbootTitleId = InstallerService::getColdbootTitleId("storage_slc_installer:/config"); + this->coldbootTitle = nullptr; + for (int i = 0; GameList[i].tid != 0; i++) { + if (GameList[i].tid == this->coldbootTitleId) { + this->coldbootTitle = &GameList[i]; + break; + } + } + + InstallerService::eResults result; + + this->systemMenuTitleId = InstallerService::getSystemMenuTitleId(); + this->systemXMLPatchPossible = ((result = InstallerService::checkSystemXML("storage_slc_installer:/config", this->appInfo->titleId)) == InstallerService::SUCCESS); if (result != InstallerService::SUCCESS) { DEBUG_FUNCTION_LINE("ERROR: %s", InstallerService::ErrorMessage(result).c_str()); } - if (this->rpxAlreadyPatched) { - this->state = STATE_CHECK_REMOVAL_POSSIBLE; + if (this->systemMenuTitleId) { + this->systemXMLRestorePossible = ((result = InstallerService::checkSystemXML("storage_slc_installer:/config", *this->systemMenuTitleId)) == InstallerService::SUCCESS); + if (result != InstallerService::SUCCESS) { + DEBUG_FUNCTION_LINE("ERROR: %s", InstallerService::ErrorMessage(result).c_str()); + } } else { - this->state = STATE_INSTALL_MENU; + this->systemXMLRestorePossible = false; } + + this->systemXMLAlreadyPatched = (this->coldbootTitleId == this->appInfo->titleId); + + this->systemXMLPatchAllowed = this->systemXMLPatchPossible && this->alreadyInstalled && InstallerService::isColdBootAllowed(); + + changeState(STATE_CHECK_REMOVAL_POSSIBLE); } void ApplicationState::checkRemovalPossible() { - this->removalPossible = false; + DEBUG_FUNCTION_LINE("Check removal possible"); - this->systemMenuTitleId = InstallerService::getSystemMenuTitleId(); - if (this->systemMenuTitleId) { - this->removalPossible = InstallerService::checkSystemXML("storage_slc_installer:/config", *this->systemMenuTitleId) == InstallerService::SUCCESS; + this->removalPossible = this->alreadyInstalled; + if (this->removalPossible) { + this->removalPossible &= this->systemXMLRestorePossible || !this->systemXMLAlreadyPatched; + } + if (this->removalPossible) { this->removalPossible &= InstallerService::isBackupAvailable(this->appInfo->path); } - - this->state = STATE_INSTALL_MENU; + changeState(STATE_COMPATIBILITY_RESULTS); } void ApplicationState::getAppInformation() { @@ -456,11 +340,10 @@ void ApplicationState::getAppInformation() { this->appInfo = InstallerService::getInstalledAppInformation(); if (!this->appInfo) { DEBUG_FUNCTION_LINE("ERROR =("); - this->state = STATE_ERROR; - this->error = ERROR_NO_APP_INSTALLED; + setError(ERROR_NO_APP_INSTALLED); } else { DEBUG_FUNCTION_LINE("WORKED!"); - this->state = STATE_CHECK_PATCH_POSSIBLE; + changeState(STATE_CHECK_PATCH_POSSIBLE); } } @@ -491,33 +374,7 @@ std::string ApplicationState::ErrorDescription() { } void ApplicationState::setError(eErrorState err) { - this->state = STATE_ERROR; this->error = err; OSEnableHomeButtonMenu(true); -} - -void ApplicationState::handleError() { - -} - -void ApplicationState::printFooter() { - ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_TV, 0, 27, "By Maschell"); - ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_DRC, 0, 17, "By Maschell"); -} - -void ApplicationState::proccessMenuNavigation(Input *input, int maxOptionValue) { - if (input->data.buttons_d & Input::BUTTON_LEFT) { - this->selectedOption--; - } else if (input->data.buttons_d & Input::BUTTON_RIGHT) { - this->selectedOption++; - } - if (this->selectedOption < 0) { - this->selectedOption = maxOptionValue; - } else if (this->selectedOption >= maxOptionValue) { - this->selectedOption = 0; - } -} - -bool ApplicationState::entrySelected(Input *input) { - return input->data.buttons_d & Input::BUTTON_A; + changeState(STATE_ERROR); } diff --git a/source/ApplicationState.h b/source/ApplicationState.h index dfe26eb..e8328da 100644 --- a/source/ApplicationState.h +++ b/source/ApplicationState.h @@ -5,6 +5,7 @@ #include "common/common.h" #include "InstallerService.h" #include "Input.h" +#include "Menu.h" class ApplicationState { public: @@ -21,35 +22,45 @@ public: STATE_WELCOME_SCREEN, STATE_GET_APP_INFORMATION, STATE_CHECK_PATCH_POSSIBLE, + STATE_CHECK_COLDBOOT_STATUS, STATE_CHECK_REMOVAL_POSSIBLE, - STATE_INSTALL_MENU, - STATE_INSTALL_CHOOSE_COLDBOOT, - STATE_INSTALL_NO_COLDBOOT_ALLOWED, + STATE_COMPATIBILITY_RESULTS, + STATE_APP_INCOMPATIBLE, + STATE_MAIN_MENU, STATE_INSTALL_CONFIRM_DIALOG, STATE_INSTALL_STARTED, STATE_INSTALL_BACKUP, STATE_INSTALL_FST, STATE_INSTALL_COS, STATE_INSTALL_RPX, - STATE_INSTALL_SYSTEM_XML, STATE_INSTALL_SUCCESS, STATE_REMOVE_CONFIRM_DIALOG, STATE_REMOVE_STARTED, STATE_REMOVE_COLDBOOT, STATE_REMOVE_AROMA, - STATE_REMOVE_SUCCESS + STATE_REMOVE_SUCCESS, + STATE_BOOT_MENU, + STATE_BOOT_SWITCH_SYSMENU, + STATE_BOOT_SWITCH_AROMA, + STATE_BOOT_SWITCH_SUCCESS, + STATE_EXIT_SYSMENU, + STATE_EXIT_SHUTDOWN, }; ApplicationState(); void setError(eErrorState error); + void changeState(eGameState newState); + void render(); void update(Input *input); void checkPatchPossible(); + void checkColdbootStatus(); + void checkRemovalPossible(); void getAppInformation(); @@ -60,24 +71,23 @@ public: std::string ErrorDescription(); - void handleError(); - - int selectedOption; - - static void printFooter(); - - void proccessMenuNavigation(Input *input, int maxOptionValue); - - static bool entrySelected(Input *input); - bool installColdboot = false; InstallerService::eResults installerError = InstallerService::eResults::SUCCESS; private: + Menu menu; + bool fstPatchPossible = false; bool cosPatchPossible = false; - bool systemXMLPatchPossible = false; + bool removalPossible = false; + bool installPossible = false; + bool alreadyInstalled = false; + + bool systemXMLPatchPossible = false; + bool systemXMLPatchAllowed = false; + bool systemXMLAlreadyPatched = false; + bool systemXMLRestorePossible = false; eGameState state; eErrorState error = ERROR_NONE; diff --git a/source/InstallerService.cpp b/source/InstallerService.cpp index 425f3ab..b25d621 100644 --- a/source/InstallerService.cpp +++ b/source/InstallerService.cpp @@ -13,6 +13,7 @@ #include #include #include +#include InstallerService::eResults InstallerService::checkCOS(const std::string &path, char *hash) { std::string cosFilePath = path + "/code/cos.xml"; @@ -756,3 +757,30 @@ InstallerService::eResults InstallerService::checkFileHash(const std::string &fi } } +InstallerService::eResults InstallerService::setBootTitle(uint64_t titleId) { + InstallerService::eResults result; + + if ((result = checkSystemXML("storage_slc_installer:/config", titleId)) != SUCCESS) { + return result; + } + + if ((result = patchSystemXML("storage_slc_installer:/config", titleId)) != SUCCESS) { + return result; + } + + auto fsaFd = IOSUHAX_FSA_Open(); + if (fsaFd >= 0) { + if (IOSUHAX_FSA_FlushVolume(fsaFd, "/vol/storage_mlc01") == 0) { + DEBUG_FUNCTION_LINE("Flushed mlc"); + } + if (IOSUHAX_FSA_FlushVolume(fsaFd, "/vol/system") == 0) { + DEBUG_FUNCTION_LINE("Flushed slc"); + } + IOSUHAX_FSA_Close(fsaFd); + } else { + DEBUG_FUNCTION_LINE("Failed to open fsa"); + } + + return SUCCESS; +} + diff --git a/source/InstallerService.h b/source/InstallerService.h index 7a9f0dc..68a9f4c 100644 --- a/source/InstallerService.h +++ b/source/InstallerService.h @@ -81,6 +81,8 @@ public: static eResults checkRPXAlreadyValid(const std::string &path, const std::string &hash); + static eResults setBootTitle(uint64_t titleId); + private: static eResults patchFSTData(uint8_t *fstData, uint32_t size); diff --git a/source/Menu.h b/source/Menu.h new file mode 100644 index 0000000..ee05f89 --- /dev/null +++ b/source/Menu.h @@ -0,0 +1,99 @@ +#pragma once + +#include +#include +#include +#include +#include "Input.h" +#include "WiiUScreen.h" +#include "ScreenUtils.h" +#include "VPADInput.h" + +template +class Menu { +public: + Menu() { + clear(); + } + + void setOptionsCallback(std::function cb) { + callback = cb; + } + + void setHeader(const std::string &hdr) { + header = hdr; + } + + void setFooter(const std::string &ftr) { + footer = ftr; + } + + void clear() { + content.clear(); + options.clear(); + selected = 0; + } + + void addText(const std::string &text = "") { + content.emplace_back(false, text); + } + + void addOption(const std::string &text, T data) { + content.emplace_back(true, text); + options.push_back(data); + } + + void render() { + int selectedDist = selected; + WiiUScreen::clearScreen(); + printHeader(); + for (auto &row : content) { + std::string cursor = ""; + if (row.first) { + cursor += (selectedDist--) ? " " : "> "; + } + drawString(cursor + row.second); + } + printFooter(); + WiiUScreen::flipBuffers(); + } + + void update(const Input *input) { + if (input->data.buttons_d & Input::BUTTON_UP) { + selected = (selected ? selected : options.size()) - 1; + } else if (input->data.buttons_d & Input::BUTTON_DOWN) { + selected = (selected < (options.size() - 1)) ? (selected + 1) : 0; + } + + if (entrySelected(input)) { + auto selectedOption = std::next(options.begin(), selected); + callback(*selectedOption); + } + } + +private: + void drawString(const std::string &text = "") const { + WiiUScreen::drawLine(text.c_str()); + } + + void printHeader() const { + drawString(header); + drawString(std::string(header.size() + 3, '=')); + drawString(); + } + + void printFooter() const { + ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_TV, 0, 27, footer.c_str()); + ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_DRC, 0, 17, footer.c_str()); + } + + bool entrySelected(const Input *input) const { + return input->data.buttons_d & Input::BUTTON_A; + } + + std::function callback; + std::string header, footer; + std::list> content; + std::list options; + size_t selected = 0; +};