This commit is contained in:
Maschell 2020-10-16 19:48:13 +02:00
parent 1091833da2
commit 170a5a1860
12 changed files with 701 additions and 191 deletions

312
source/ApplicationState.cpp Normal file
View File

@ -0,0 +1,312 @@
#include "ApplicationState.h"
#include "WiiUScreen.h"
#include "ScreenUtils.h"
#include <sysapp/launch.h>
void ApplicationState::render() {
WiiUScreen::clearScreen();
WiiUScreen::drawLine("Aroma Installer");
WiiUScreen::drawLine("==================");
WiiUScreen::drawLine("");
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.");
} 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");
}
} else if (this->state == STATE_GET_APP_INFORMATION) {
WiiUScreen::drawLine("Getting app information");
} else if (this->state == STATE_CHECK_PATCH_POSSIBLE) {
WiiUScreen::drawLine("Check if console can be patched.");
} else if (this->state == STATE_CHECK_PATCH_POSSIBLE_DONE) {
WiiUScreen::drawLinef("Compatible title: %s", appInfo->appName);
WiiUScreen::drawLine();
if (this->fstPatchPossible) {
WiiUScreen::drawLine("[ X ] title.fst can be patched!");
} else {
WiiUScreen::drawLine("[ ] title.fst can NOT be patched!");
}
if (this->cosPatchPossible) {
WiiUScreen::drawLine("[ X ] cos.xml can be patched!");
} else {
WiiUScreen::drawLine("[ ] cos.xml can NOT be patched!");
}
if (this->systemXMLPatchPossible) {
WiiUScreen::drawLine("[ X ] system.xml can be patched!");
} else {
WiiUScreen::drawLine("[ ] system.xml can NOT be patched!");
}
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 {
WiiUScreen::drawLine("Do you want to install Aroma?");
WiiUScreen::drawLine("");
if (this->selectedOption == 0) {
WiiUScreen::drawLine("> Install Exit");
} else if (this->selectedOption == 1) {
WiiUScreen::drawLine(" Install > Exit");
}
}
} 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_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");
}
} else if (this->state == STATE_INSTALL_STARTED) {
WiiUScreen::drawLine("Installing...");
} else if (this->state == STATE_INSTALL_FST) {
WiiUScreen::drawLine("... 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");
} else if (this->state == STATE_INSTALL_RPX) {
WiiUScreen::drawLine("... install safe.rpx");
}
printFooter();
WiiUScreen::flipBuffers();
}
void ApplicationState::update(Input *input) {
if (this->state == STATE_ERROR) {
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_PATCH_POSSIBLE_DONE) {
if (this->fstPatchPossible && this->cosPatchPossible) {
proccessMenuNavigation(input, 2);
if (entrySelected(input)) {
if (this->selectedOption == 0) {
if (systemXMLPatchPossible) {
this->state = STATE_INSTALL_CHOOSE_COLDBOOT;
this->installColdboot = false;
} else {
this->state = STATE_INSTALL_CONFIRM_DIALOG;
}
} else {
SYSLaunchMenu();
}
this->selectedOption = 0;
return;
}
} else {
if (entrySelected(input)) {
SYSLaunchMenu();
}
}
} else if (this->state == STATE_INSTALL_CHOOSE_COLDBOOT) {
proccessMenuNavigation(input, 3);
if (entrySelected(input)) {
if (this->selectedOption == 0) { // Back
this->state = STATE_CHECK_PATCH_POSSIBLE_DONE;
} 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_CONFIRM_DIALOG) {
proccessMenuNavigation(input, 2);
if (entrySelected(input)) {
if (this->selectedOption == 0) {
this->state = STATE_CHECK_PATCH_POSSIBLE_DONE;
} else {
this->state = STATE_INSTALL_STARTED;
OSEnableHomeButtonMenu(false);
}
this->selectedOption = 0;
return;
}
} else if (this->state == STATE_INSTALL_STARTED) {
this->state = STATE_INSTALL_FST;
} else if (this->state == STATE_INSTALL_FST) {
auto result = InstallerService::patchFST(this->appInfo->path, this->appInfo->fstHash);
if (result != InstallerService::SUCCESS) {
this->error = ERROR_INSTALLER_ERROR;
this->installerError = result;
this->state = STATE_ERROR;
} else {
this->state = STATE_INSTALL_COS;
}
} else if (this->state == STATE_INSTALL_COS) {
auto result = InstallerService::patchCOS(this->appInfo->path, this->appInfo->cosHash);
if (result != InstallerService::SUCCESS) {
this->error = ERROR_INSTALLER_ERROR;
this->installerError = result;
this->state = STATE_ERROR;
} else {
this->state = STATE_INSTALL_RPX;
}
} else if (this->state == STATE_INSTALL_RPX) {
if (entrySelected(input)) {
this->state = STATE_WELCOME_SCREEN;
}
}
}
ApplicationState::ApplicationState() {
this->state = STATE_WELCOME_SCREEN;
this->selectedOption = 0;
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;
}
DEBUG_FUNCTION_LINE("CHECK FST");
InstallerService::eResults result;
this->fstPatchPossible = ((result = InstallerService::checkFST(this->appInfo->path, this->appInfo->fstHash)) == InstallerService::SUCCESS);
if (result != InstallerService::SUCCESS) {
DEBUG_FUNCTION_LINE("ERROR: %s", InstallerService::ErrorMessage(result).c_str());
}
this->cosPatchPossible = ((result = InstallerService::checkCOS(this->appInfo->path, this->appInfo->cosHash)) == InstallerService::SUCCESS);
if (result != InstallerService::SUCCESS) {
DEBUG_FUNCTION_LINE("ERROR: %s", InstallerService::ErrorMessage(result).c_str());
}
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());
}
this->state = STATE_CHECK_PATCH_POSSIBLE_DONE;
}
void ApplicationState::getAppInformation() {
DEBUG_FUNCTION_LINE("About to call getInstalledAppInformation");
this->appInfo = InstallerService::getInstalledAppInformation();
DEBUG_FUNCTION_LINE("back");
if (!this->appInfo) {
DEBUG_FUNCTION_LINE("ERROR =(");
this->state = STATE_ERROR;
this->error = ERROR_NO_APP_INSTALLED;
} else {
DEBUG_FUNCTION_LINE("WORKED!");
this->state = STATE_CHECK_PATCH_POSSIBLE;
}
}
std::string ApplicationState::ErrorMessage() {
if (this->error == ERROR_NONE) {
return "NONE";
} else if (this->error == ERROR_NO_APP_INSTALLED) {
return "ERROR_NO_APP_INSTALLED";
} else if (this->error == ERROR_IOSUHAX_FAILED) {
return "ERROR_IOSUHAX_FAILED";
} else if (this->error == ERROR_INSTALLER_ERROR) {
return InstallerService::ErrorMessage(this->installerError);
}
return "UNKNOWN_ERROR";
}
std::string ApplicationState::ErrorDescription() {
if (this->error == ERROR_NONE) {
return "-";
} else if (this->error == ERROR_NO_APP_INSTALLED) {
return "No compatible application is installed. A safe installation is not possible.";
} else if (this->error == ERROR_INSTALLER_ERROR) {
return InstallerService::ErrorDescription(this->installerError);
} else if (this->error == ERROR_IOSUHAX_FAILED) {
return "Failed to init IOSUHAX.";
}
return "UNKNOWN_ERROR";
}
void ApplicationState::setError(eErrorState error) {
this->state = STATE_ERROR;
this->error = error;
}
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;
}

72
source/ApplicationState.h Normal file
View File

@ -0,0 +1,72 @@
#pragma once
#include <string>
#include <optional>
#include "common/common.h"
#include "InstallerService.h"
#include "Input.h"
class ApplicationState {
public:
enum eErrorState {
ERROR_NONE,
ERROR_IOSUHAX_FAILED,
ERROR_NO_APP_INSTALLED,
ERROR_INSTALLER_ERROR
};
enum eGameState {
STATE_ERROR,
STATE_WELCOME_SCREEN,
STATE_GET_APP_INFORMATION,
STATE_CHECK_PATCH_POSSIBLE,
STATE_CHECK_PATCH_POSSIBLE_DONE,
STATE_INSTALL_CHOOSE_COLDBOOT,
STATE_INSTALL_CONFIRM_DIALOG,
STATE_INSTALL_STARTED,
STATE_INSTALL_FST,
STATE_INSTALL_SYSTEM_XML,
STATE_INSTALL_COS,
STATE_INSTALL_RPX
};
ApplicationState();
void setError(eErrorState error);
void render();
void update(Input *input);
void checkPatchPossible();
void getAppInformation();
std::optional<appInformation> appInfo;
std::string ErrorMessage();
std::string ErrorDescription();
void handleError();
int selectedOption;
static void printFooter();
void proccessMenuNavigation(Input *input, int maxOptionValue);
bool entrySelected(Input *input);
bool installColdboot = false;
InstallerService::eResults installerError = InstallerService::eResults::SUCCESS;
private:
bool fstPatchPossible = false;
bool cosPatchPossible = false;
bool systemXMLPatchPossible = false;
eGameState state;
eErrorState error = ERROR_NONE;
};

View File

@ -1,103 +0,0 @@
#include "GameState.h"
#include "WiiUScreen.h"
#include "Input.h"
void GameState::render() {
WiiUScreen::clearScreen();
if (this->state == STATE_ERROR) {
WiiUScreen::drawLinef("Error: %s", ErrorMessage().c_str());
} else if (this->state == STATE_GET_APP_INFORMATION) {
WiiUScreen::drawLine("Getting app information");
} else if (this->state == STATE_CHECK_PATCH_POSSIBLE) {
WiiUScreen::drawLine("Check if console can be patched.");
} else if (this->state == STATE_CHECK_PATCH_POSSIBLE_DONE) {
if (this->fstPatchPossibe) {
WiiUScreen::drawLine("- title.fst can be patched!");
} else {
WiiUScreen::drawLine("x title.fst can NOT be patched!");
}
if (this->cosPatchPossibe) {
WiiUScreen::drawLine("- cos.xml can be patched!");
} else {
WiiUScreen::drawLine("x cos.xml can NOT be patched!");
}
if (this->systemXMLPatchPossibe) {
WiiUScreen::drawLine("- system.xml can be patched!");
} else {
WiiUScreen::drawLine("x system.xml can NOT be patched!");
}
}
WiiUScreen::flipBuffers();
}
Input GameState::getCurrentInput(){
}
void GameState::update(Input input) {
if (this->state == STATE_ERROR) {
handleError();
} else if (this->state == STATE_GET_APP_INFORMATION) {
getAppInformation();
} else if (this->state == STATE_CHECK_PATCH_POSSIBLE) {
checkPatchPossible();
}
}
GameState::GameState() {
this->state = STATE_GET_APP_INFORMATION;
DEBUG_FUNCTION_LINE("State has changed to \"STATE_GET_APP_INFORMATION\"");
}
void GameState::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;
}
DEBUG_FUNCTION_LINE("CHECK FST");
InstallerService::eResults result;
this->fstPatchPossibe = ((result = InstallerService::checkFST(this->appInfo->path, this->appInfo->fstHash)) == InstallerService::SUCCESS);
if (result != InstallerService::SUCCESS) {
DEBUG_FUNCTION_LINE("ERROR: %s", InstallerService::ErrorMessage(result).c_str());
}
this->cosPatchPossibe = ((result = InstallerService::checkCOS(this->appInfo->path, this->appInfo->cosHash)) == InstallerService::SUCCESS);
if (result != InstallerService::SUCCESS) {
DEBUG_FUNCTION_LINE("ERROR: %s", InstallerService::ErrorMessage(result).c_str());
}
this->systemXMLPatchPossibe = ((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());
}
this->state = STATE_CHECK_PATCH_POSSIBLE_DONE;
}
void GameState::getAppInformation() {
DEBUG_FUNCTION_LINE("About to call getInstalledAppInformation");
this->appInfo = InstallerService::getInstalledAppInformation();
DEBUG_FUNCTION_LINE("back");
if (!this->appInfo) {
DEBUG_FUNCTION_LINE("ERROR =(");
this->state = STATE_ERROR;
this->error = ERROR_NO_APP_INSTALLED;
} else {
DEBUG_FUNCTION_LINE("WORKED!");
this->state = STATE_CHECK_PATCH_POSSIBLE;
}
}
std::string GameState::ErrorMessage() {
if (this->error == ERROR_NONE) {
return "NONE";
} else if (this->error == ERROR_NO_APP_INSTALLED) {
return "ERROR_NO_APP_INSTALLED";
}
return "UNKNOWN_ERROR";
}
void GameState::handleError() {
}

View File

@ -1,46 +0,0 @@
#pragma once
#include <string>
#include <optional>
#include "common/common.h"
#include "InstallerService.h"
class GameState {
enum eGameState {
STATE_ERROR,
STATE_GET_APP_INFORMATION,
STATE_CHECK_PATCH_POSSIBLE,
STATE_CHECK_PATCH_POSSIBLE_DONE
};
enum eErrorState {
ERROR_NONE,
ERROR_NO_APP_INSTALLED
};
private:
bool fstPatchPossibe = false;
bool cosPatchPossibe = false;
bool systemXMLPatchPossibe = false;
eGameState state;
eErrorState error = ERROR_NONE;
public:
GameState();
void render();
void update();
void checkPatchPossible();
void getAppInformation();
std::optional<appInformation> appInfo;
std::string ErrorMessage();
void handleError();
};

View File

@ -11,6 +11,39 @@ public:
//!Destructor
virtual ~Input() = default;
enum eButtons {
BUTTON_NONE = 0x0000,
VPAD_TOUCH = 0x80000000,
BUTTON_Z = 0x20000,
BUTTON_C = 0x10000,
BUTTON_A = 0x8000,
BUTTON_B = 0x4000,
BUTTON_X = 0x2000,
BUTTON_Y = 0x1000,
BUTTON_1 = BUTTON_Y,
BUTTON_2 = BUTTON_X,
BUTTON_LEFT = 0x0800,
BUTTON_RIGHT = 0x0400,
BUTTON_UP = 0x0200,
BUTTON_DOWN = 0x0100,
BUTTON_ZL = 0x0080,
BUTTON_ZR = 0x0040,
BUTTON_L = 0x0020,
BUTTON_R = 0x0010,
BUTTON_PLUS = 0x0008,
BUTTON_MINUS = 0x0004,
BUTTON_HOME = 0x0002,
BUTTON_SYNC = 0x0001,
STICK_R_LEFT = 0x04000000,
STICK_R_RIGHT = 0x02000000,
STICK_R_UP = 0x01000000,
STICK_R_DOWN = 0x00800000,
STICK_L_LEFT = 0x40000000,
STICK_L_RIGHT = 0x20000000,
STICK_L_UP = 0x10000000,
STICK_L_DOWN = 0x08000000
};
typedef struct {
uint32_t buttons_h;
uint32_t buttons_d;

View File

@ -31,7 +31,7 @@ appInformation supportedApps[] = {
InstallerService::eResults InstallerService::checkCOS(const std::string &path, char *hash) {
std::string cosFilePath = path + "/code/cos1.xml";
std::string cosFilePath = path + "/code/cos.xml";
DEBUG_FUNCTION_LINE("Loading %s", cosFilePath.c_str());
pugi::xml_document doc;
@ -41,7 +41,7 @@ InstallerService::eResults InstallerService::checkCOS(const std::string &path, c
return COS_XML_PARSING_FAILED;
}
patchCOS(&doc);
patchCOSXMLData(&doc);
std::stringstream ss;
doc.save(ss, " ", pugi::format_default, pugi::encoding_utf8);
@ -116,13 +116,18 @@ InstallerService::eResults InstallerService::checkFST(const std::string &path, c
DEBUG_FUNCTION_LINE("Failed to load title.fst");
return FAILED_TO_LOAD_FILE;
}
InstallerService::eResults res = patchFST(fstData, fstDataSize);
InstallerService::eResults res = patchFSTData(fstData, fstDataSize);
if (res != SUCCESS) {
free(fstData);
fstData = nullptr;
return res;
}
std::string newHash = Utils::calculateSHA1((const char *) fstData, fstDataSize);
free(fstData);
fstData = nullptr;
if (std::string(fstHash) == newHash) {
DEBUG_FUNCTION_LINE("title.fst is compatible");
return SUCCESS;
@ -132,7 +137,7 @@ InstallerService::eResults InstallerService::checkFST(const std::string &path, c
}
}
bool InstallerService::patchCOS(pugi::xml_document *doc) {
bool InstallerService::patchCOSXMLData(pugi::xml_document *doc) {
pugi::xml_node appEntry = doc->child("app");
appEntry.child("argstr").first_child().set_value("safe.rpx");
appEntry.child("avail_size").first_child().set_value("00000000");
@ -190,7 +195,7 @@ std::optional<appInformation> InstallerService::getInstalledAppInformation() {
return {};
}
InstallerService::eResults InstallerService::patchFST(uint8_t *fstData, uint32_t size) {
InstallerService::eResults InstallerService::patchFSTData(uint8_t *fstData, uint32_t size) {
auto *fstHeader = (FSTHeader *) fstData;
if (strncmp(FSTHEADER_MAGIC, fstHeader->magic, 3) != 0) {
DEBUG_FUNCTION_LINE("FST magic is wrong %s", fstHeader->magic);
@ -232,47 +237,206 @@ InstallerService::eResults InstallerService::patchFST(uint8_t *fstData, uint32_t
return InstallerService::SUCCESS;
}
std::string InstallerService::ErrorMessage(InstallerService::eResults results) {
if (results == SUCCESS) {
std::string InstallerService::ErrorDescription(InstallerService::eResults error) {
if (error == SUCCESS) {
return "Success";
} else if (results == NO_COMPATIBLE_APP_INSTALLED) {
} else if (error == NO_COMPATIBLE_APP_INSTALLED) {
return "No compatible application was found on the console.";
} else if (error == FAILED_TO_COPY_FILES) {
return "Unable to copy files.";
} else if (error == FAILED_TO_CHECK_HASH_COPIED_FILES) {
return "The copy of a file has a different hash.";
} else if (error == SYSTEM_XML_INFORMATION_NOT_FOUND) {
return "Expected hashes for the target system.xml were not found.";
} else if (error == SYSTEM_XML_PARSING_FAILED) {
return "Failed to parse the system.xml";
} else if (error == SYSTEM_XML_HASH_MISMATCH_RESTORE_FAILED) {
return "DO NOT REBOOT BEFORE FIXING THIS: Failed to restore the system.xml after an error.";
} else if (error == SYSTEM_XML_HASH_MISMATCH) {
return "The patched system.xml had an unexpected hash but was successfully restored";
} else if (error == RPX_HASH_MISMATCH) {
return "The installed safe.rpx had an unexpected hash but was successfully restored";
} else if (error == RPX_HASH_MISMATCH_RESTORE_FAILED) {
return "DO NOT REBOOT BEFORE FIXING THIS: Failed to restore the safe.rpx after an error.";
} else if (error == COS_XML_PARSING_FAILED) {
return "Failed to parse the cos.xml";
} else if (error == COS_XML_HASH_MISMATCH) {
return "The patched cos.xml had an unexpected hash but was successfully restored";
} else if (error == COS_XML_HASH_MISMATCH_RESTORE_FAILED) {
return "DO NOT REBOOT BEFORE FIXING THIS: Failed to restore the cos.xml after an error";
} else if (error == MALLOC_FAILED) {
return "Failed to allocate memory";
} else if (error == FST_HASH_MISMATCH) {
return "The patched title.fst had an unexpected hash but was successfully restored";
} else if (error == FST_HASH_MISMATCH_RESTORE_FAILED) {
return "DO NOT REBOOT BEFORE FIXING THIS: Failed to restore the title.fst after an error";
} else if (error == FST_HEADER_MISMATCH) {
return "Unexpected header in title.fst found. The file is probably broken.";
} else if (error == FST_NO_USABLE_SECTION_FOUND) {
return "Unable to patch title.fst to allow FailST";
} else if (error == FAILED_TO_LOAD_FILE) {
return "Failed to load file.";
} else {
return "UNKNOWN ERROR";
}
}
std::string InstallerService::ErrorMessage(InstallerService::eResults error) {
if (error == SUCCESS) {
return "Success";
} else if (error == NO_COMPATIBLE_APP_INSTALLED) {
return "NO_COMPATIBLE_APP_INSTALLED";
} else if (results == FAILED_TO_COPY_FILES) {
} else if (error == FAILED_TO_COPY_FILES) {
return "FAILED_TO_COPY_FILES";
} else if (results == FAILED_TO_CHECK_HASH_COPIED_FILES) {
} else if (error == FAILED_TO_CHECK_HASH_COPIED_FILES) {
return "FAILED_TO_CHECK_HASH_COPIED_FILES";
} else if (results == SYSTEM_XML_INFORMATION_NOT_FOUND) {
} else if (error == SYSTEM_XML_INFORMATION_NOT_FOUND) {
return "SYSTEM_XML_INFORMATION_NOT_FOUND";
} else if (results == SYSTEM_XML_PARSING_FAILED) {
} else if (error == SYSTEM_XML_PARSING_FAILED) {
return "SYSTEM_XML_PARSING_FAILED";
} else if (results == SYSTEM_XML_HASH_MISMATCH_RESTORE_FAILED) {
} else if (error == SYSTEM_XML_HASH_MISMATCH_RESTORE_FAILED) {
return "SYSTEM_XML_HASH_MISMATCH_RESTORE_FAILED";
} else if (results == SYSTEM_XML_HASH_MISMATCH) {
} else if (error == SYSTEM_XML_HASH_MISMATCH) {
return "SYSTEM_XML_HASH_MISMATCH";
} else if (results == RPX_HASH_MISMATCH) {
} else if (error == RPX_HASH_MISMATCH) {
return "RPX_HASH_MISMATCH";
} else if (results == RPX_HASH_MISMATCH_RESTORE_FAILED) {
} else if (error == RPX_HASH_MISMATCH_RESTORE_FAILED) {
return "RPX_HASH_MISMATCH_RESTORE_FAILED";
} else if (results == COS_XML_PARSING_FAILED) {
} else if (error == COS_XML_PARSING_FAILED) {
return "COS_XML_PARSING_FAILED";
} else if (results == COS_XML_HASH_MISMATCH) {
} else if (error == COS_XML_HASH_MISMATCH) {
return "COS_XML_HASH_MISMATCH";
} else if (results == COS_XML_HASH_MISMATCH_RESTORE_FAILED) {
} else if (error == COS_XML_HASH_MISMATCH_RESTORE_FAILED) {
return "COS_XML_HASH_MISMATCH_RESTORE_FAILED";
} else if (results == MALLOC_FAILED) {
} else if (error == MALLOC_FAILED) {
return "MALLOC_FAILED";
} else if (results == FST_HASH_MISMATCH) {
} else if (error == FST_HASH_MISMATCH) {
return "FST_HASH_MISMATCH";
} else if (results == FST_HASH_MISMATCH_RESTORE_FAILED) {
} else if (error == FST_HASH_MISMATCH_RESTORE_FAILED) {
return "FST_HASH_MISMATCH_RESTORE_FAILED";
} else if (results == FST_HEADER_MISMATCH) {
} else if (error == FST_HEADER_MISMATCH) {
return "FST_HEADER_MISMATCH";
} else if (results == FST_NO_USABLE_SECTION_FOUND) {
} else if (error == FST_NO_USABLE_SECTION_FOUND) {
return "FST_NO_USABLE_SECTION_FOUND";
} else if (results == FAILED_TO_LOAD_FILE) {
} else if (error == FAILED_TO_LOAD_FILE) {
return "FAILED_TO_LOAD_FILE";
} else {
return "UNKNOWN ERROR";
}
}
InstallerService::eResults InstallerService::patchFST(const std::string &path, const char *fstHash) {
std::string fstFilePath = path + "/code/title.fst";
std::string fstBackupFilePath = path + "/code/backup.fst";
std::string fstTargetFilePath = path + "/code/titla.fst";
if (!FSUtils::copyFile(fstFilePath, fstBackupFilePath)) {
DEBUG_FUNCTION_LINE("Failed to copy files");
return FAILED_TO_COPY_FILES;
}
std::string srcHash = Utils::hashFile(fstFilePath);
std::string dstHash = Utils::hashFile(fstBackupFilePath);
if (srcHash != dstHash) {
::remove(fstBackupFilePath.c_str());
DEBUG_FUNCTION_LINE("Hashes do not match. %s %s", srcHash.c_str(), dstHash.c_str());
return FAILED_TO_CHECK_HASH_COPIED_FILES;
}
uint8_t *fstData = nullptr;
uint32_t fstDataSize = 0;
DEBUG_FUNCTION_LINE("Trying to load FST from %s", fstFilePath.c_str());
if (FSUtils::LoadFileToMem(fstFilePath.c_str(), &fstData, &fstDataSize) < 0) {
DEBUG_FUNCTION_LINE("Failed to load title.fst");
return FAILED_TO_LOAD_FILE;
}
InstallerService::eResults res = patchFSTData(fstData, fstDataSize);
if (res != SUCCESS) {
free(fstData);
return res;
}
FSUtils::saveBufferToFile(fstTargetFilePath.c_str(), fstData, fstDataSize);
free(fstData);
fstData = nullptr;
std::string newHash = Utils::hashFile(fstTargetFilePath);
if (std::string(fstHash) == newHash) {
::remove(fstBackupFilePath.c_str());
DEBUG_FUNCTION_LINE("Successfully patched the title.fst");
return SUCCESS;
} else {
DEBUG_FUNCTION_LINE("Hash mismatch! Expected %s but got %s while patching FST", fstHash, newHash.c_str());
}
FSUtils::copyFile(fstBackupFilePath, fstTargetFilePath);
std::string srcHash2 = Utils::hashFile(fstTargetFilePath);
if (srcHash != srcHash2) {
DEBUG_FUNCTION_LINE("Something went wrong. Failed to restore the title.fst. DO NOT RESTART THE SYSTEM until you manually restored the title.fst");
return FST_HASH_MISMATCH_RESTORE_FAILED;
}
::remove(fstBackupFilePath.c_str());
return FST_HASH_MISMATCH;
}
InstallerService::eResults InstallerService::patchCOS(const std::string &path, char *hash) {
std::string cosFilePath = path + "/code/cos.xml";
std::string cosBackupFilePath = path + "/code/cback.xml";
std::string cosTargetFilePath = path + "/code/cos.xml";
if (!FSUtils::copyFile(cosFilePath, cosBackupFilePath)) {
DEBUG_FUNCTION_LINE("Failed to copy files");
return FAILED_TO_COPY_FILES;
}
std::string srcHash = Utils::hashFile(cosFilePath);
std::string dstHash = Utils::hashFile(cosBackupFilePath);
if (srcHash != dstHash) {
::remove(cosBackupFilePath.c_str());
DEBUG_FUNCTION_LINE("Hashes do not match. %s %s", srcHash.c_str(), dstHash.c_str());
return FAILED_TO_CHECK_HASH_COPIED_FILES;
}
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file(cosFilePath.c_str());
if (!result) {
::remove(cosBackupFilePath.c_str());
DEBUG_FUNCTION_LINE("failed to open %s : %s", cosFilePath.c_str(), result.description());
return COS_XML_PARSING_FAILED;
}
patchCOSXMLData(&doc);
doc.save_file(cosTargetFilePath.c_str(), " ", pugi::format_default, pugi::encoding_utf8);
std::string newHash = Utils::hashFile(cosTargetFilePath);
if (std::string(hash) == newHash) {
::remove(cosBackupFilePath.c_str());
DEBUG_FUNCTION_LINE("Successfully patched the cos.xml");
return SUCCESS;
} else {
DEBUG_FUNCTION_LINE("Hash mismatch! Expected %s but got %s while patching cos.xml", hash, newHash.c_str());
}
FSUtils::copyFile(cosBackupFilePath, cosTargetFilePath);
std::string srcHash2 = Utils::hashFile(cosTargetFilePath);
if (srcHash != srcHash2) {
DEBUG_FUNCTION_LINE("Something went wrong. Failed to restore the title.fst. DO NOT RESTART THE SYSTEM until you manually restored the cos.xml");
return COS_XML_HASH_MISMATCH_RESTORE_FAILED;
}
::remove(cosBackupFilePath.c_str());
return COS_XML_HASH_MISMATCH;
}

View File

@ -28,6 +28,8 @@ public:
FAILED_TO_LOAD_FILE = -18,
};
static eResults patchCOS(const std::string &path, char *hash);
static eResults checkCOS(const std::string &path, char *hash);
static eResults checkSystemXML(const std::string &path, uint64_t titleId);
@ -36,10 +38,14 @@ public:
static std::optional<appInformation> getInstalledAppInformation();
static std::string ErrorMessage(eResults results);
static std::string ErrorMessage(eResults error);
static std::string ErrorDescription(eResults error);
static eResults patchFST(const std::string &path, const char *hash);
private:
static eResults patchFST(uint8_t *data, uint32_t size);
static eResults patchFSTData(uint8_t *fstData, uint32_t size);
static bool patchCOS(pugi::xml_document *doc);
static bool patchCOSXMLData(pugi::xml_document *doc);
};

59
source/VPADInput.h Normal file
View File

@ -0,0 +1,59 @@
#pragma once
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <vpad/input.h>
#include "Input.h"
class VPadInput : public Input {
public:
//!Constructor
VPadInput() {
memset(&vpad, 0, sizeof(vpad));
}
//!Destructor
~VPadInput() override {}
bool update(int32_t width, int32_t height) {
lastData = data;
VPADReadError vpadError = VPAD_READ_NO_SAMPLES;
VPADRead(VPAD_CHAN_0, &vpad, 1, &vpadError);
if (vpadError == VPAD_READ_SUCCESS) {
data.buttons_r = vpad.release;
data.buttons_h = vpad.hold;
data.buttons_d = vpad.trigger;
data.validPointer = !vpad.tpNormal.validity;
data.touched = vpad.tpNormal.touched;
VPADGetTPCalibratedPoint(VPAD_CHAN_0, &tpCalib, &vpad.tpFiltered1);
//! calculate the screen offsets
data.x = -(width >> 1) + (int32_t) (((float) tpCalib.x / 1280.0f) * (float) width);
data.y = -(height >> 1) + (int32_t) (float) height - (((float) tpCalib.y / 720.0f) * (float) height);
return true;
}
return false;
}
private:
VPADStatus vpad{};
VPADTouchData tpCalib{};
};

View File

@ -55,7 +55,7 @@ bool WiiUScreen::Init() {
void WiiUScreen::DeInit() {
if (sConsoleHasForeground) {
OSScreenShutdown();
WiiUScreen::ProcCallbackReleased(NULL);
WiiUScreen::ProcCallbackReleased(nullptr);
}
}
@ -76,11 +76,14 @@ void WiiUScreen::drawLinef(const char *fmt, ...) {
va_end(va);
}
void WiiUScreen::drawLine() {
WiiUScreen::drawLine("");
}
void WiiUScreen::drawLine(const char *msg) {
ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_BOTH, 0, consoleCursorY++, msg);
}
void WiiUScreen::flipBuffers() {
ScreenUtils::flipBuffers(CONSOLE_SCREEN_BOTH);
}

View File

@ -37,6 +37,9 @@ public:
static void drawLinef(const char *fmt, ...);
static void drawLine(const char *fmt);
static void drawLine();
static void flipBuffers();
static void clearScreen();

View File

@ -9,7 +9,7 @@
int32_t FSUtils::LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size) {
//! always initialze input
*inbuffer = NULL;
*inbuffer = nullptr;
if (size)
*size = 0;
@ -20,8 +20,8 @@ int32_t FSUtils::LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_
uint32_t filesize = lseek(iFd, 0, SEEK_END);
lseek(iFd, 0, SEEK_SET);
uint8_t *buffer = (uint8_t *) malloc(filesize);
if (buffer == NULL) {
auto *buffer = (uint8_t *) malloc(filesize);
if (buffer == nullptr) {
close(iFd);
return -2;
}
@ -44,7 +44,7 @@ int32_t FSUtils::LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_
if (done != filesize) {
free(buffer);
buffer = NULL;
buffer = nullptr;
return -3;
}

View File

@ -8,12 +8,14 @@
#include <iosuhax.h>
#include <iosuhax_devoptab.h>
#include <string_view>
#include <vector>
#include "WiiUScreen.h"
#include "utils/logger.h"
#include "InstallerService.h"
#include "../build/safe_payload.h"
#include "GameState.h"
#include "ApplicationState.h"
#include "VPADInput.h"
constexpr bool strings_equal(char const *a, char const *b) {
return std::string_view(a) == b;
@ -25,14 +27,22 @@ void initIOSUHax();
void deInitIOSUHax();
int sFSAFd = -1;
bool sIosuhaxMount = false;
int hello_thread() {
int main_loop() {
DEBUG_FUNCTION_LINE("Creating state");
GameState state;
ApplicationState state;
VPadInput input;
if (sFSAFd < 0 || !sIosuhaxMount) {
state.setError(ApplicationState::eErrorState::ERROR_IOSUHAX_FAILED);
}
DEBUG_FUNCTION_LINE("Entering main loop");
while (WHBProcIsRunning()) {
state.update();
input.update(1280, 720);
state.update(&input);
state.render();
}
@ -47,7 +57,7 @@ int main(int argc, char **argv) {
initIOSUHax();
hello_thread();
main_loop();
deInitIOSUHax();
@ -57,9 +67,6 @@ int main(int argc, char **argv) {
return 0;
}
int sFSAFd = -1;
bool sIosuhaxMount = false;
void initIOSUHax() {
sIosuhaxMount = false;
int res = IOSUHAX_Open(nullptr);