Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 34 additions & 8 deletions source/BootUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <nn/act.h>
#include <nn/cmpt/cmpt.h>
#include <padscore/kpad.h>
#include <sstream>
#include <string>
#include <sysapp/launch.h>
#include <sysapp/title.h>
Expand Down Expand Up @@ -39,6 +40,18 @@ void bootHomebrewLauncher() {
_SYSLaunchTitleWithStdArgsInNoSplash(titleId, nullptr);
}

void bootWiiuTitle(const std::string &hexId) {
uint64_t titleId;
std::stringstream ss;
ss << std::hex << hexId;
ss >> titleId;

handleAccountSelection();

titleId = _SYSGetSystemApplicationTitleId(static_cast<SYSTEM_APP_ID>(titleId));
_SYSLaunchTitleWithStdArgsInNoSplash(titleId, nullptr);
}

void handleAccountSelection() {
nn::act::Initialize();
nn::act::SlotNo defaultSlot = nn::act::GetDefaultAccount();
Expand Down Expand Up @@ -83,7 +96,7 @@ void handleAccountSelection() {
nn::act::Finalize();
}

static void launchvWiiTitle(uint64_t titleId) {
void launchvWiiTitle(uint64_t titleId) {
// we need to init kpad for cmpt
KPADInit();

Expand Down Expand Up @@ -114,7 +127,7 @@ void bootvWiiMenu() {
launchvWiiTitle(0);
}

uint64_t getVWiiHBLTitleId() {
uint64_t getVWiiTitleId(const std::string& hexId) {
// fall back to booting the vWii system menu if anything fails
uint64_t titleId = 0;

Expand All @@ -126,13 +139,15 @@ uint64_t getVWiiHBLTitleId() {
if (FSAMount(client, "/dev/slccmpt01", "/vol/storage_slccmpt01", FSA_MOUNT_FLAG_GLOBAL_MOUNT, nullptr, 0) >= 0) {
FSStat stat;

// test if the OHBC or HBC is installed
if (FSAGetStat(client, "/vol/storage_slccmpt01/title/00010001/4f484243/content/00000000.app", &stat) >= 0) {
titleId = 0x000100014F484243L; // 'OHBC'
} else if (FSAGetStat(client, "/vol/storage_slccmpt01/title/00010001/4c554c5a/content/00000000.app", &stat) >= 0) {
titleId = 0x000100014C554C5AL; // 'LULZ'
const std::string hexValue{ hexId.size() > 2 ? hexId.substr(2) : hexId };
const std::string titleString{ "/vol/storage_slccmpt01/title/00010001/" + hexValue + "/content/00000000.app" };
if (FSAGetStat(client, titleString.c_str(), &stat) >= 0) {
std::stringstream ss;
ss << std::hex << hexId;
ss >> titleId;
titleId |= 0x0001000100000000L;
} else {
DEBUG_FUNCTION_LINE("Cannot find HBC");
DEBUG_FUNCTION_LINE("Cannot find title 0x%s", hexId.c_str());
}
FSAUnmount(client, "/vol/storage_slccmpt01", static_cast<FSAUnmountFlags>(2));
} else {
Expand All @@ -145,6 +160,17 @@ uint64_t getVWiiHBLTitleId() {
} else {
DEBUG_FUNCTION_LINE_ERR("Failed to add FSAClient");
}

return titleId;
}

uint64_t getVWiiHBLTitleId() {
// Try 'OHBC' first and if it fails, try 'LULZ'
uint64_t titleId = getVWiiTitleId("4f484243");
if (titleId == 0) {
titleId = getVWiiTitleId("4c554c5a");
}

return titleId;
}

Expand Down
7 changes: 7 additions & 0 deletions source/BootUtils.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
#pragma once

#include <cstdint>
#include <string>

void launchvWiiTitle(uint64_t titleId);

void bootWiiUMenu();

void bootHomebrewLauncher();

void bootWiiuTitle(const std::string& hexId);

void bootvWiiMenu();

void bootHomebrewChannel();

uint64_t getVWiiTitleId(const std::string& hexId);

uint64_t getVWiiHBLTitleId();
99 changes: 76 additions & 23 deletions source/MenuUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,17 @@
#include <malloc.h>
#include <memory>
#include <nn/act/client_cpp.h>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <vpad/input.h>

#define AUTOBOOT_MODULE_VERSION "v0.1.2"

const char *autoboot_config_strings[] = {
"wiiu_menu",
"homebrew_launcher",
"vwii_system_menu",
"vwii_homebrew_channel",
};
// Initialize with the autoboot_base_config_strings data
std::vector<std::string> autoboot_config_strings = { autoboot_base_config_strings.begin(), autoboot_base_config_strings.end() };
std::vector<BootOption> custom_boot_options;

template<typename... Args>
std::string string_format(const std::string &format, Args... args) {
Expand All @@ -33,36 +32,90 @@ std::string string_format(const std::string &format, Args... args) {
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
}

int32_t readAutobootOption(std::string &configPath) {
FILE *f = fopen(configPath.c_str(), "r");
if (f) {
char buf[128]{};
fgets(buf, sizeof(buf), f);
fclose(f);
std::string trim(const std::string& str) {
std::string result;
for (auto& ch : str) {
if (!std::isspace(ch)) {
result += ch;
}
}

return result;
}

for (uint32_t i = 0; i < sizeof(autoboot_config_strings) / sizeof(char *); i++) {
if (strncmp(autoboot_config_strings[i], buf, strlen(autoboot_config_strings[i])) == 0) {
void readBootOptionsFromSD(const std::string &configPath) {
std::ifstream fileStream(configPath.c_str(), std::ios::in);
if (fileStream.is_open()) {
DEBUG_FUNCTION_LINE("bootOptions.cfg open");

constexpr size_t bufSize{ 256 };
for (char line[bufSize]; fileStream.getline(line, bufSize);) {
DEBUG_FUNCTION_LINE(" Line \"%s\"", line);
std::istringstream parsingLine{std::string{line}};
memset(line, 0, bufSize);

std::vector<std::string> tokens;
for (char tmp[bufSize]; parsingLine.getline(tmp, bufSize, ',');) {
DEBUG_FUNCTION_LINE(" Token \"%s\"", tmp);
tokens.push_back(trim(tmp));
memset(tmp, 0, bufSize);
}

if (tokens.size() == 3)
{
const std::string subSystem{ tokens[2] };
const std::string vWiiStr{ "vwii" };
const bool vWii{ std::equal(subSystem.begin(), subSystem.end(),
vWiiStr.begin(), vWiiStr.end(), [](unsigned char a, unsigned char b) {
return std::tolower(a) == std::tolower(b);
})
};

custom_boot_options.push_back(BootOption{tokens[0], tokens[1], vWii});
}
}
} else {
DEBUG_FUNCTION_LINE("Failed to open bootOptions.cfg");
}
}

int32_t readAutobootOption(const std::string &configPath) {
std::ifstream fileStream(configPath.c_str(), std::ios::in);
if (fileStream.is_open()) {
std::string readOption;
fileStream >> readOption;

for (size_t i = 0; i < autoboot_config_strings.size(); ++i) {
if (autoboot_config_strings[i] == readOption) {
return i;
}
}

for (size_t i = 0; i < custom_boot_options.size(); ++i) {
if (custom_boot_options[i].title == readOption) {
return BOOT_OPTION_MAX_OPTIONS + i;
}
}
}

return -1;
}

void writeAutobootOption(std::string &configPath, int32_t autobootOption) {
FILE *f = fopen(configPath.c_str(), "w");
if (f) {
if (autobootOption >= 0) {
fputs(autoboot_config_strings[autobootOption], f);
void writeAutobootOption(const std::string &configPath, int32_t autobootOption) {
const int32_t customAutoBootOption{ autobootOption - BOOT_OPTION_MAX_OPTIONS };
std::ofstream outStream(configPath.c_str(), std::ios::out);
if (outStream.is_open()) {
if (customAutoBootOption >= 0) {
outStream << custom_boot_options[customAutoBootOption].title;
} else if (autobootOption >= 0) {
outStream << autoboot_config_strings[autobootOption];
} else {
fputs("none", f);
outStream << "none";
}

fclose(f);
}
}

int32_t handleMenuScreen(std::string &configPath, int32_t autobootOptionInput, const std::map<uint32_t, std::string> &menu) {
int32_t handleMenuScreen(const std::string &configPath, int32_t autobootOptionInput, const std::map<uint32_t, std::string> &menu) {
auto screenBuffer = DrawUtils::InitOSScreen();
if (!screenBuffer) {
OSFatal("Failed to alloc memory for screen");
Expand Down
29 changes: 25 additions & 4 deletions source/MenuUtils.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "ACTAccountInfo.h"
#include <array>
#include <cstdint>
#include <map>
#include <memory>
Expand All @@ -20,18 +21,38 @@
#define COLOR_BORDER Color(204, 204, 204, 255)
#define COLOR_BORDER_HIGHLIGHTED Color(0x3478e4ff)

struct BootOption {
std::string title;
std::string hexId;
bool vWii;
};

enum {
BOOT_OPTION_WII_U_MENU,
BOOT_OPTION_WII_U_MENU = 0,
BOOT_OPTION_HOMEBREW_LAUNCHER,
BOOT_OPTION_VWII_SYSTEM_MENU,
BOOT_OPTION_VWII_HOMEBREW_CHANNEL,

BOOT_OPTION_MAX_OPTIONS
};

int32_t readAutobootOption(std::string &configPath);
constexpr std::array<const char*, BOOT_OPTION_MAX_OPTIONS> autoboot_base_config_strings{
"wiiu_menu",
"homebrew_launcher",
"vwii_system_menu",
"vwii_homebrew_channel",
};

extern std::vector<std::string> autoboot_config_strings;
extern std::vector<BootOption> custom_boot_options;

void readBootOptionsFromSD(const std::string &configPath);

int32_t readAutobootOption(const std::string &configPath);

void writeAutobootOption(std::string &configPath, int32_t autobootOption);
void writeAutobootOption(const std::string &configPath, int32_t autobootOption);

int32_t handleMenuScreen(std::string &configPath, int32_t autobootOptionInput, const std::map<uint32_t, std::string> &menu);
int32_t handleMenuScreen(const std::string &configPath, int32_t autobootOptionInput, const std::map<uint32_t, std::string> &menu);

nn::act::SlotNo handleAccountSelectScreen(const std::vector<std::shared_ptr<AccountInfo>> &data);

Expand Down
26 changes: 25 additions & 1 deletion source/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ int32_t main(int32_t argc, char **argv) {
if (stat(hblInstallerPath.c_str(), &st) >= 0) {
showHBL = true;
}

readBootOptionsFromSD(std::string(argv[0]) + "/bootOptions.cfg");
} else {
readBootOptionsFromSD("fs:/vol/external01/wiiu/bootOptions.cfg");
}

int32_t bootSelection = readAutobootOption(configPath);
Expand All @@ -95,14 +99,34 @@ int32_t main(int32_t argc, char **argv) {
menu[BOOT_OPTION_VWII_HOMEBREW_CHANNEL] = "vWii Homebrew Channel";
}

for (size_t i = 0; i < custom_boot_options.size(); ++i) {
const BootOption& option{ custom_boot_options[i] };
menu[BOOT_OPTION_MAX_OPTIONS + i] = option.title + " (" + (option.vWii ? "vWii" : "WiiU") + " " + option.hexId + ")";
}

if ((bootSelection == -1) ||
(bootSelection == BOOT_OPTION_HOMEBREW_LAUNCHER && !showHBL) ||
(bootSelection == BOOT_OPTION_VWII_HOMEBREW_CHANNEL && !showvHBL) ||
(vpad.hold & VPAD_BUTTON_PLUS)) {
bootSelection = handleMenuScreen(configPath, bootSelection, menu);
}

if (bootSelection >= 0) {
const int32_t customBootSelection{bootSelection - BOOT_OPTION_MAX_OPTIONS};
if (customBootSelection >= 0) {
if (static_cast<size_t>(customBootSelection) < custom_boot_options.size()) {
const BootOption &selectedOption{custom_boot_options[customBootSelection]};
if (selectedOption.vWii) {
const uint64_t titleId = getVWiiTitleId(selectedOption.hexId);
DEBUG_FUNCTION_LINE("Launching vWii title %016llx", titleId);
launchvWiiTitle(titleId);
} else {
DEBUG_FUNCTION_LINE("Launching WiiU title %s", selectedOption.hexId);
bootWiiuTitle(selectedOption.hexId);
}
} else {
bootWiiUMenu();
}
} else if (bootSelection >= 0) {
switch (bootSelection) {
case BOOT_OPTION_WII_U_MENU:
bootWiiUMenu();
Expand Down