WiiUPluginLoaderBackend/source/utils/utils.cpp

197 lines
5.6 KiB
C++
Raw Normal View History

#include "utils.h"
#include "StringTools.h"
#include "fs/CFile.hpp"
#include "globals.h"
#include "json.hpp"
#include "logger.h"
#include <algorithm>
#include <coreinit/ios.h>
2024-11-27 20:44:36 +01:00
#include <malloc.h>
#include <string>
#include <sys/dirent.h>
#include <wups/storage.h>
2023-12-16 12:44:20 +01:00
static std::string sPluginPath;
static std::string sModulePath;
static std::string sEnvironmentPath;
std::string getEnvironmentPath() {
if (!sEnvironmentPath.empty()) {
return sEnvironmentPath;
2023-12-16 12:44:20 +01:00
}
2024-11-27 20:44:36 +01:00
char environmentPath[0x100] = {};
2024-11-27 20:44:36 +01:00
if (const auto handle = IOS_Open("/dev/mcp", IOS_OPEN_READ); handle >= 0) {
int in = 0xF9; // IPC_CUSTOM_COPY_ENVIRONMENT_PATH
if (IOS_Ioctl(handle, 100, &in, sizeof(in), environmentPath, sizeof(environmentPath)) != IOS_ERROR_OK) {
return "fs:/vol/external01/wiiu/environments/aroma";
}
IOS_Close(handle);
}
sEnvironmentPath = environmentPath;
return sEnvironmentPath;
}
std::string getPluginPath() {
if (!sPluginPath.empty()) {
return sPluginPath;
}
sPluginPath = getEnvironmentPath().append("/plugins");
2023-12-16 12:44:20 +01:00
return sPluginPath;
}
2019-08-15 10:45:18 +02:00
std::string getModulePath() {
if (!sModulePath.empty()) {
return sModulePath;
}
sModulePath = getEnvironmentPath().append("/modules");
return sModulePath;
}
2019-08-15 10:45:18 +02:00
// https://gist.github.com/ccbrown/9722406
2024-11-27 20:44:36 +01:00
void dumpHex(const void *data, const size_t size) {
2019-08-15 10:45:18 +02:00
char ascii[17];
size_t i, j;
ascii[16] = '\0';
DEBUG_FUNCTION_LINE("0x%08X (0x0000): ", data);
for (i = 0; i < size; ++i) {
2020-05-08 11:17:24 +02:00
WHBLogWritef("%02X ", ((unsigned char *) data)[i]);
2020-05-03 12:30:15 +02:00
if (((unsigned char *) data)[i] >= ' ' && ((unsigned char *) data)[i] <= '~') {
ascii[i % 16] = ((unsigned char *) data)[i];
2019-08-15 10:45:18 +02:00
} else {
ascii[i % 16] = '.';
}
2020-05-03 12:30:15 +02:00
if ((i + 1) % 8 == 0 || i + 1 == size) {
2020-05-08 11:17:24 +02:00
WHBLogWritef(" ");
2020-05-03 12:30:15 +02:00
if ((i + 1) % 16 == 0) {
2020-05-08 11:17:24 +02:00
WHBLogPrintf("| %s ", ascii);
2020-05-03 12:30:15 +02:00
if (i + 1 < size) {
DEBUG_FUNCTION_LINE("0x%08X (0x%04X); ", ((uint32_t) data) + i + 1, i + 1);
2019-08-15 10:45:18 +02:00
}
2020-05-03 12:30:15 +02:00
} else if (i + 1 == size) {
ascii[(i + 1) % 16] = '\0';
if ((i + 1) % 16 <= 8) {
2020-05-08 11:17:24 +02:00
WHBLogWritef(" ");
2019-08-15 10:45:18 +02:00
}
2020-05-03 12:30:15 +02:00
for (j = (i + 1) % 16; j < 16; ++j) {
2020-05-08 11:17:24 +02:00
WHBLogWritef(" ");
2019-08-15 10:45:18 +02:00
}
2020-05-08 11:17:24 +02:00
WHBLogPrintf("| %s ", ascii);
2019-08-15 10:45:18 +02:00
}
}
}
}
OSDynLoad_Error CustomDynLoadAlloc(int32_t size, int32_t align, void **outAddr) {
if (!outAddr) {
return OS_DYNLOAD_INVALID_ALLOCATOR_PTR;
}
if (align >= 0 && align < 4) {
align = 4;
} else if (align < 0 && align > -4) {
align = -4;
}
2024-11-27 20:44:36 +01:00
if (*outAddr = memalign(align, size); !*outAddr) {
return OS_DYNLOAD_OUT_OF_MEMORY;
}
// keep track of allocated memory to clean it up if RPLs won't get unloaded properly
gAllocatedAddresses.push_back(*outAddr);
return OS_DYNLOAD_OK;
}
void CustomDynLoadFree(void *addr) {
free(addr);
// Remove from list
2024-11-27 20:44:36 +01:00
if (const auto it = std::ranges::find(gAllocatedAddresses, addr); it != gAllocatedAddresses.end()) {
gAllocatedAddresses.erase(it);
}
}
bool ParseJsonFromFile(const std::string &filePath, nlohmann::json &outJson) {
CFile file(filePath, CFile::ReadOnly);
if (!file.isOpen() || file.size() == 0) {
return false;
}
auto *json_data = (uint8_t *) memalign(0x40, ROUNDUP(file.size() + 1, 0x40));
if (!json_data) {
return false;
}
bool result = true;
uint64_t readRes = file.read(json_data, file.size());
if (readRes == file.size()) {
json_data[file.size()] = '\0';
outJson = nlohmann::json::parse(json_data, nullptr, false);
} else {
result = false;
}
file.close();
free(json_data);
return result;
}
std::vector<std::string> getPluginFilePaths(std::string_view basePath) {
std::vector<std::string> result;
struct dirent *dp;
DIR *dfd;
if (basePath.empty()) {
DEBUG_FUNCTION_LINE_ERR("Failed to scan plugin dir: Path was empty");
return result;
}
if ((dfd = opendir(basePath.data())) == nullptr) {
DEBUG_FUNCTION_LINE_ERR("Couldn't open dir %s", basePath.data());
return result;
}
while ((dp = readdir(dfd)) != nullptr) {
if (dp->d_type == DT_DIR) {
continue;
}
if (std::string_view(dp->d_name).starts_with('.') || std::string_view(dp->d_name).starts_with('_') || !std::string_view(dp->d_name).ends_with(".wps")) {
DEBUG_FUNCTION_LINE_WARN("Skip file %s/%s", basePath.data(), dp->d_name);
continue;
}
auto full_file_path = string_format("%s/%s", basePath.data(), dp->d_name);
result.push_back(full_file_path);
}
closedir(dfd);
return result;
}
std::vector<std::string> getNonBaseAromaPluginFilenames(std::string_view basePath) {
std::vector<std::string> result;
for (const auto &filePath : getPluginFilePaths(basePath)) {
std::string fileName = StringTools::FullpathToFilename(filePath.c_str());
const char *baseAromaFileNames[] = {
"AromaBasePlugin.wps",
"drc_region_free.wps",
"homebrew_on_menu.wps",
"regionfree.wps",
};
bool found = false;
for (const auto &cur : baseAromaFileNames) {
if (fileName == cur) {
found = true;
break;
}
}
if (!found) {
result.push_back(fileName);
}
}
return result;
}