mirror of
https://github.com/wiiu-env/homebrew_on_menu_plugin.git
synced 2024-11-22 10:39:16 +01:00
Reimplement the data structure and file reading
This commit is contained in:
parent
74560db545
commit
15ab8b4c3b
86
src/FileInfos.h
Normal file
86
src/FileInfos.h
Normal file
@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
#include "utils/logger.h"
|
||||
#include <coreinit/mcp.h>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <wuhb_utils/utils.h>
|
||||
#include "utils/utils.h"
|
||||
|
||||
class FileInfos {
|
||||
public:
|
||||
explicit FileInfos(const std::string &relativePath) : relativeFilepath(relativePath) {
|
||||
this->lowerTitleID = hash_string(relativePath.c_str());
|
||||
}
|
||||
~FileInfos() {
|
||||
std::lock_guard<std::mutex> lock(mountLock);
|
||||
if (isMounted) {
|
||||
UnmountBundle();
|
||||
}
|
||||
}
|
||||
bool MountBundle(const std::string &romfsName) {
|
||||
if (isMounted) {
|
||||
if (mountPath != romfsName) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Can't mount as %s because it's already mounted with a different name (%s)", romfsName.c_str(), mountPath.c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!isBundle) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Mounting not possible, is not a bundle");
|
||||
return false;
|
||||
}
|
||||
auto fullMountPath = std::string("/vol/external01/").append(this->relativeFilepath);
|
||||
int32_t outRes = -1;
|
||||
if (WUHBUtils_MountBundle(romfsName.c_str(), fullMountPath.c_str(), BundleSource_FileDescriptor_CafeOS, &outRes) != WUHB_UTILS_RESULT_SUCCESS || outRes < 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to mount bundle: %s", romfsName.c_str());
|
||||
return false;
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Succesfully mounted %s", romfsName.c_str());
|
||||
this->isMounted = true;
|
||||
mountPath = romfsName;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UnmountBundle() {
|
||||
if (!isBundle) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Skip unmounting, is not a bundle");
|
||||
return true;
|
||||
}
|
||||
if (!isMounted) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Skip unmounting, is not mounted");
|
||||
return true;
|
||||
}
|
||||
int32_t outRes = -1;
|
||||
if (WUHBUtils_UnmountBundle(mountPath.c_str(), &outRes) != WUHB_UTILS_RESULT_SUCCESS || outRes < 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to unmount bundle: %s", mountPath.c_str());
|
||||
return false;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Successfully unmounted bundle %s", this->mountPath.c_str());
|
||||
}
|
||||
this->isMounted = false;
|
||||
this->mountPath.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string relativeFilepath;
|
||||
std::string filename;
|
||||
|
||||
std::string longname;
|
||||
std::string shortname;
|
||||
std::string author;
|
||||
|
||||
uint32_t lowerTitleID;
|
||||
MCPTitleListType titleInfo{};
|
||||
|
||||
int32_t fileCount = 0;
|
||||
|
||||
bool isBundle = false;
|
||||
|
||||
std::mutex accessLock;
|
||||
|
||||
private:
|
||||
std::mutex mountLock;
|
||||
std::string mountPath;
|
||||
bool isMounted = false;
|
||||
};
|
@ -1,97 +0,0 @@
|
||||
#include "FileWrapper.h"
|
||||
#include "fileinfos.h"
|
||||
#include "utils/StringTools.h"
|
||||
#include "utils/logger.h"
|
||||
#include <coreinit/cache.h>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <wuhb_utils/utils.h>
|
||||
|
||||
FileHandleWrapper gFileHandleWrapper[FILE_WRAPPER_SIZE] __attribute__((section(".data")));
|
||||
|
||||
std::mutex fileWrapperMutex;
|
||||
|
||||
int FileHandleWrapper_GetSlot() {
|
||||
std::lock_guard<std::mutex> lock(fileWrapperMutex);
|
||||
int res = -1;
|
||||
for (int i = 0; i < FILE_WRAPPER_SIZE; i++) {
|
||||
if (!gFileHandleWrapper[i].inUse) {
|
||||
gFileHandleWrapper[i].inUse = true;
|
||||
res = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
OSMemoryBarrier();
|
||||
return res;
|
||||
}
|
||||
|
||||
bool FileHandleWrapper_FreeSlot(uint32_t slot) {
|
||||
if (slot >= FILE_WRAPPER_SIZE) {
|
||||
return false;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(fileWrapperMutex);
|
||||
gFileHandleWrapper[slot].handle = 0;
|
||||
gFileHandleWrapper[slot].inUse = false;
|
||||
OSMemoryBarrier();
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool FileHandleWrapper_FreeAll() {
|
||||
std::lock_guard<std::mutex> lock(fileWrapperMutex);
|
||||
for (int i = 0; i < FILE_WRAPPER_SIZE; i++) {
|
||||
FileHandleWrapper_FreeSlot(i);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int OpenFileForID(int id, const char *filepath, uint32_t *handle) {
|
||||
if (!mountRomfs(id)) {
|
||||
return -1;
|
||||
}
|
||||
char romName[10];
|
||||
snprintf(romName, 10, "%08X", id);
|
||||
|
||||
char *dyn_path = (char *) malloc(strlen(filepath) + 1);
|
||||
char last = 0;
|
||||
int j = 0;
|
||||
for (int i = 0; filepath[i] != 0; i++) {
|
||||
if (filepath[i] == '/') {
|
||||
if (filepath[i] != last) {
|
||||
dyn_path[j++] = filepath[i];
|
||||
}
|
||||
} else {
|
||||
dyn_path[j++] = filepath[i];
|
||||
}
|
||||
last = filepath[i];
|
||||
}
|
||||
dyn_path[j] = 0;
|
||||
|
||||
auto completePath = string_format("%s:/%s", romName, dyn_path);
|
||||
|
||||
WUHBFileHandle fileHandle = 0;
|
||||
if (WUHBUtils_FileOpen(completePath.c_str(), &fileHandle) == WUHB_UTILS_RESULT_SUCCESS) {
|
||||
int handle_wrapper_slot = FileHandleWrapper_GetSlot();
|
||||
|
||||
if (handle_wrapper_slot < 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("No free slot");
|
||||
if (WUHBUtils_FileClose(fileHandle) != WUHB_UTILS_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to close file %08X", fileHandle);
|
||||
}
|
||||
unmountRomfs(id);
|
||||
return -2;
|
||||
}
|
||||
gFileHandleWrapper[handle_wrapper_slot].handle = fileHandle;
|
||||
*handle = 0xFF000000 | (id << 12) | (handle_wrapper_slot & 0x00000FFF);
|
||||
gFileInfos[id].openedFiles++;
|
||||
return 0;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to open file %s", filepath);
|
||||
if (gFileInfos[id].openedFiles == 0) {
|
||||
unmountRomfs(id);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
typedef struct FileHandleWrapper_t {
|
||||
uint32_t handle;
|
||||
bool inUse;
|
||||
} FileHandleWrapper;
|
||||
|
||||
#define FILE_WRAPPER_SIZE 64
|
||||
extern FileHandleWrapper gFileHandleWrapper[FILE_WRAPPER_SIZE];
|
||||
|
||||
int OpenFileForID(int id, const char *path, uint32_t *handle);
|
||||
bool FileHandleWrapper_FreeAll();
|
@ -71,7 +71,7 @@ void initSaveData() {
|
||||
DECL_FUNCTION(int32_t, LoadConsoleAccount__Q2_2nn3actFUc13ACTLoadOptionPCcb, nn::act::SlotNo slot, nn::act::ACTLoadOption unk1, char const *unk2, bool unk3) {
|
||||
int32_t result = real_LoadConsoleAccount__Q2_2nn3actFUc13ACTLoadOptionPCcb(slot, unk1, unk2, unk3);
|
||||
if (result >= 0 && gInWiiUMenu) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Changed account, we need to init the save data");
|
||||
DEBUG_FUNCTION_LINE("Changed account, we need to init the save data");
|
||||
// If the account has changed, we need to init save data for this account
|
||||
// Calls our function replacement.
|
||||
SAVEInit();
|
||||
|
@ -1,74 +0,0 @@
|
||||
#include "fileinfos.h"
|
||||
#include "utils/logger.h"
|
||||
#include <coreinit/cache.h>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <wuhb_utils/utils.h>
|
||||
|
||||
FileInfos gFileInfos[FILE_INFO_SIZE] __attribute__((section(".data")));
|
||||
std::mutex fileinfoMutex;
|
||||
|
||||
int32_t getIDByLowerTitleID(uint32_t lowerTitleID) {
|
||||
std::lock_guard<std::mutex> lock(fileinfoMutex);
|
||||
int res = -1;
|
||||
for (int i = 0; i < FILE_INFO_SIZE; i++) {
|
||||
if (strlen(gFileInfos[i].path) > 0 && gFileInfos[i].lowerTitleID == lowerTitleID) {
|
||||
res = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
OSMemoryBarrier();
|
||||
return res;
|
||||
}
|
||||
|
||||
void unmountRomfs(uint32_t id) {
|
||||
if (id >= FILE_INFO_SIZE) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(fileinfoMutex);
|
||||
if (gFileInfos[id].romfsMounted) {
|
||||
char romName[10];
|
||||
snprintf(romName, 10, "%08X", id);
|
||||
int32_t outRes;
|
||||
if (WUHBUtils_UnmountBundle(romName, &outRes) || outRes != 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to unmount \"%s\"", romName);
|
||||
}
|
||||
gFileInfos[id].romfsMounted = false;
|
||||
}
|
||||
OSMemoryBarrier();
|
||||
}
|
||||
|
||||
void unmountAllRomfs() {
|
||||
for (int i = 0; i < FILE_INFO_SIZE; i++) {
|
||||
unmountRomfs(i);
|
||||
}
|
||||
}
|
||||
|
||||
bool mountRomfs(uint32_t id) {
|
||||
if (id >= FILE_INFO_SIZE) {
|
||||
DEBUG_FUNCTION_LINE_ERR("HANDLE WAS TOO BIG %d", id);
|
||||
return false;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(fileinfoMutex);
|
||||
bool result = false;
|
||||
if (!gFileInfos[id].romfsMounted) {
|
||||
char buffer[256];
|
||||
snprintf(buffer, 256, "/vol/external01/%s", gFileInfos[id].path);
|
||||
char romName[10];
|
||||
snprintf(romName, 10, "%08X", id);
|
||||
DEBUG_FUNCTION_LINE("Mount %s as %s", buffer, romName);
|
||||
int32_t res = 0;
|
||||
if (WUHBUtils_MountBundle(romName, buffer, BundleSource_FileDescriptor_CafeOS, &res) == WUHB_UTILS_RESULT_SUCCESS && res == 0) {
|
||||
DEBUG_FUNCTION_LINE("Mounted successfully ");
|
||||
gFileInfos[id].romfsMounted = true;
|
||||
result = true;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Mounting failed %d", res);
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
OSMemoryBarrier();
|
||||
return result;
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <coreinit/mcp.h>
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
|
||||
extern std::mutex fileinfoMutex;
|
||||
|
||||
typedef struct WUT_PACKED FileInfos_ {
|
||||
char path[256];
|
||||
char filename[256];
|
||||
char shortname[64];
|
||||
char longname[64];
|
||||
char author[64];
|
||||
int32_t source;
|
||||
uint32_t lowerTitleID;
|
||||
bool romfsMounted;
|
||||
int openedFiles;
|
||||
MCPTitleListType titleInfo;
|
||||
} FileInfos;
|
||||
|
||||
#define FILE_INFO_SIZE 300
|
||||
extern FileInfos gFileInfos[FILE_INFO_SIZE];
|
||||
|
||||
int32_t getIDByLowerTitleID(uint32_t lowerTitleID);
|
||||
|
||||
void unmountRomfs(uint32_t id);
|
||||
|
||||
void unmountAllRomfs();
|
||||
|
||||
bool mountRomfs(uint32_t id);
|
@ -62,7 +62,7 @@ BOOL DirList::LoadPath(const std::string &folder, const char *filter, uint32_t f
|
||||
std::string folderpath(folder);
|
||||
uint32_t length = folderpath.size();
|
||||
|
||||
//! clear path of double slashes
|
||||
//! clear relativeFilepath of double slashes
|
||||
StringTools::RemoveDoubleSlashs(folderpath);
|
||||
|
||||
//! remove last slash if exists
|
||||
|
@ -132,7 +132,7 @@ int32_t FSUtils::CreateSubfolder(const char *fullpath) {
|
||||
int32_t FSUtils::saveBufferToFile(const char *path, void *buffer, uint32_t size) {
|
||||
CFile file(path, CFile::WriteOnly);
|
||||
if (!file.isOpen()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to open %s\n", path);
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to open %s\n", path);
|
||||
return 0;
|
||||
}
|
||||
int32_t written = file.write((const uint8_t *) buffer, size);
|
||||
@ -147,13 +147,13 @@ bool FSUtils::copyFile(const std::string &in, const std::string &out) {
|
||||
|
||||
int source = open(in.c_str(), O_RDONLY, 0);
|
||||
if (source < 0) {
|
||||
DEBUG_FUNCTION_LINE("Failed to open source %s", in.c_str());
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to open source %s", in.c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
int dest = open(out.c_str(), 0x602, 0644);
|
||||
if (dest < 0) {
|
||||
DEBUG_FUNCTION_LINE("Failed to open dest %s", out.c_str());
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to open dest %s", out.c_str());
|
||||
close(source);
|
||||
return false;
|
||||
}
|
||||
@ -161,7 +161,7 @@ bool FSUtils::copyFile(const std::string &in, const std::string &out) {
|
||||
auto bufferSize = 128 * 1024;
|
||||
char *buf = (char *) malloc(bufferSize);
|
||||
if (buf == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Failed to alloc buffer");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
54
src/fs/FileReader.cpp
Normal file
54
src/fs/FileReader.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include "FileReader.h"
|
||||
#include "../utils/logger.h"
|
||||
#include <cstring>
|
||||
|
||||
int64_t FileReader::read(uint8_t *buffer, uint32_t size) {
|
||||
if (isReadFromBuffer) {
|
||||
if (input_buffer == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
uint32_t toRead = size;
|
||||
if (toRead > input_size - input_pos) {
|
||||
toRead = input_size - input_pos;
|
||||
}
|
||||
if (toRead == 0) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(buffer, &input_buffer[input_pos], toRead);
|
||||
input_pos += toRead;
|
||||
return toRead;
|
||||
} else if (isReadFromFile) {
|
||||
int res = ::read(file_fd, buffer, size);
|
||||
return res;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
FileReader::FileReader(std::string &path) {
|
||||
int fd;
|
||||
if ((fd = open(path.c_str(), O_RDONLY)) >= 0) {
|
||||
this->isReadFromFile = true;
|
||||
this->isReadFromBuffer = false;
|
||||
this->file_fd = fd;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("## INFO ## Failed to open file %s", path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
FileReader::~FileReader() {
|
||||
if (isReadFromFile) {
|
||||
::close(this->file_fd);
|
||||
}
|
||||
}
|
||||
|
||||
FileReader::FileReader(uint8_t *buffer, uint32_t size) {
|
||||
this->input_buffer = buffer;
|
||||
this->input_size = size;
|
||||
this->input_pos = 0;
|
||||
this->isReadFromBuffer = true;
|
||||
this->isReadFromFile = false;
|
||||
}
|
||||
|
||||
bool FileReader::isReady() {
|
||||
return this->isReadFromFile || this->isReadFromBuffer;
|
||||
}
|
37
src/fs/FileReader.h
Normal file
37
src/fs/FileReader.h
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
class FileReader {
|
||||
|
||||
public:
|
||||
FileReader(uint8_t *buffer, uint32_t size);
|
||||
|
||||
explicit FileReader(std::string &path);
|
||||
|
||||
virtual ~FileReader();
|
||||
|
||||
virtual int64_t read(uint8_t *buffer, uint32_t size);
|
||||
|
||||
virtual bool isReady();
|
||||
|
||||
virtual uint32_t getHandle(){
|
||||
return reinterpret_cast<uint32_t>(this);
|
||||
}
|
||||
|
||||
protected:
|
||||
FileReader() = default;
|
||||
|
||||
private:
|
||||
bool isReadFromBuffer = false;
|
||||
uint8_t *input_buffer = nullptr;
|
||||
uint32_t input_size = 0;
|
||||
uint32_t input_pos = 0;
|
||||
|
||||
bool isReadFromFile = false;
|
||||
int file_fd = 0;
|
||||
};
|
79
src/fs/FileReaderWUHB.cpp
Normal file
79
src/fs/FileReaderWUHB.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
#include "FileReaderWUHB.h"
|
||||
#include "utils/StringTools.h"
|
||||
#include "utils/logger.h"
|
||||
#include <coreinit/cache.h>
|
||||
#include <wuhb_utils/utils.h>
|
||||
|
||||
FileReaderWUHB::FileReaderWUHB(const std::shared_ptr<FileInfos>& info, const std::string &relativeFilepath, bool autoUnmount) {
|
||||
if (!info) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Info was NULL");
|
||||
return;
|
||||
}
|
||||
if (!info->isBundle) {
|
||||
DEBUG_FUNCTION_LINE("Failed to init file reader for %s, is not a bundle.", info->relativeFilepath.c_str());
|
||||
return;
|
||||
}
|
||||
this->autoUnmount = autoUnmount;
|
||||
this->info = info;
|
||||
std::lock_guard<std::mutex> lock(info->accessLock);
|
||||
|
||||
auto romfsName = string_format("%08X", info->lowerTitleID);
|
||||
|
||||
if (!info->MountBundle(romfsName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto filepath = romfsName.append(":/").append(relativeFilepath);
|
||||
|
||||
WUHBUtilsStatus status;
|
||||
if ((status = WUHBUtils_FileOpen(filepath.c_str(), &this->fileHandle)) != WUHB_UTILS_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE("Failed to open file in bundle: %s error: %d", filepath.c_str(), status);
|
||||
return;
|
||||
}
|
||||
this->info->fileCount++;
|
||||
|
||||
this->initDone = true;
|
||||
OSMemoryBarrier();
|
||||
}
|
||||
|
||||
FileReaderWUHB::~FileReaderWUHB() {
|
||||
if (!this->initDone) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(info->accessLock);
|
||||
|
||||
if (this->fileHandle != 0) {
|
||||
if (WUHBUtils_FileClose(this->fileHandle) != WUHB_UTILS_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("WUHBUtils_FileClose failed for %08X", this->fileHandle);
|
||||
}
|
||||
this->fileHandle = 0;
|
||||
info->fileCount--;
|
||||
}
|
||||
|
||||
if (autoUnmount && info->fileCount <= 0) {
|
||||
if (!info->UnmountBundle()) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to unmount");
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Filecount is %d, we don't want to unmount yet", info->fileCount);
|
||||
}
|
||||
OSMemoryBarrier();
|
||||
}
|
||||
|
||||
int64_t FileReaderWUHB::read(uint8_t *buffer, uint32_t size) {
|
||||
if (!this->initDone) {
|
||||
DEBUG_FUNCTION_LINE_ERR("read file but init was not successful");
|
||||
return -1;
|
||||
}
|
||||
int32_t outRes = -1;
|
||||
if (WUHBUtils_FileRead(this->fileHandle, buffer, size, &outRes) == WUHB_UTILS_RESULT_SUCCESS) {
|
||||
return outRes;
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_ERR("WUHBUtils_FileRead failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool FileReaderWUHB::isReady() {
|
||||
return this->initDone;
|
||||
}
|
18
src/fs/FileReaderWUHB.h
Normal file
18
src/fs/FileReaderWUHB.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include "../FileInfos.h"
|
||||
#include "FileReader.h"
|
||||
#include <wuhb_utils/utils.h>
|
||||
|
||||
|
||||
class FileReaderWUHB : public FileReader {
|
||||
bool initDone = false;
|
||||
std::shared_ptr<FileInfos> info;
|
||||
WUHBFileHandle fileHandle = 0;
|
||||
bool autoUnmount = false;
|
||||
|
||||
public:
|
||||
explicit FileReaderWUHB(const std::shared_ptr<FileInfos>& info, const std::string &relativeFilepath, bool autoUnmount);
|
||||
~FileReaderWUHB() override;
|
||||
int64_t read(uint8_t *buffer, uint32_t size) override;
|
||||
bool isReady() override;
|
||||
};
|
290
src/main.cpp
290
src/main.cpp
@ -1,8 +1,9 @@
|
||||
#include "FileWrapper.h"
|
||||
#include "FileInfos.h"
|
||||
#include "SaveRedirection.h"
|
||||
#include "fileinfos.h"
|
||||
#include "filelist.h"
|
||||
#include "fs/FSUtils.h"
|
||||
#include "fs/FileReader.h"
|
||||
#include "fs/FileReaderWUHB.h"
|
||||
#include "utils/StringTools.h"
|
||||
#include "utils/ini.h"
|
||||
#include <content_redirection/redirection.h>
|
||||
@ -14,10 +15,12 @@
|
||||
#include <coreinit/systeminfo.h>
|
||||
#include <coreinit/title.h>
|
||||
#include <cstring>
|
||||
#include <forward_list>
|
||||
#include <fs/DirList.h>
|
||||
#include <malloc.h>
|
||||
#include <mutex>
|
||||
#include <nn/acp.h>
|
||||
#include <optional>
|
||||
#include <rpxloader/rpxloader.h>
|
||||
#include <sdutils/sdutils.h>
|
||||
#include <sysapp/launch.h>
|
||||
@ -38,13 +41,19 @@ WUPS_PLUGIN_AUTHOR("Maschell");
|
||||
WUPS_PLUGIN_LICENSE("GPL");
|
||||
|
||||
#define UPPER_TITLE_ID_HOMEBREW 0x0005000F
|
||||
|
||||
#define TITLE_ID_HOMEBREW_MASK (((uint64_t) UPPER_TITLE_ID_HOMEBREW) << 32)
|
||||
|
||||
ACPMetaXml gLaunchXML __attribute__((section(".data")));
|
||||
MCPTitleListType current_launched_title_info __attribute__((section(".data")));
|
||||
BOOL gHomebrewLaunched __attribute__((section(".data")));
|
||||
|
||||
|
||||
std::mutex fileInfosMutex;
|
||||
std::forward_list<std::shared_ptr<FileInfos>> fileInfos;
|
||||
|
||||
std::mutex fileReaderListMutex;
|
||||
std::forward_list<std::unique_ptr<FileReader>> openFileReaders;
|
||||
|
||||
void readCustomTitlesFromSD();
|
||||
|
||||
WUPS_USE_WUT_DEVOPTAB();
|
||||
@ -52,8 +61,6 @@ WUPS_USE_WUT_DEVOPTAB();
|
||||
INITIALIZE_PLUGIN() {
|
||||
memset((void *) ¤t_launched_title_info, 0, sizeof(current_launched_title_info));
|
||||
memset((void *) &gLaunchXML, 0, sizeof(gLaunchXML));
|
||||
memset((void *) &gFileInfos, 0, sizeof(gFileInfos));
|
||||
memset((void *) &gFileHandleWrapper, 0, sizeof(gFileHandleWrapper));
|
||||
gHomebrewLaunched = FALSE;
|
||||
|
||||
// Use libwuhbutils.
|
||||
@ -82,6 +89,18 @@ bool sSDUtilsInitDone = false;
|
||||
bool sSDIsMounted = false;
|
||||
bool sTitleRebooting = false;
|
||||
|
||||
|
||||
void Cleanup() {
|
||||
{
|
||||
const std::lock_guard<std::mutex> lock1(fileReaderListMutex);
|
||||
openFileReaders.clear();
|
||||
}
|
||||
{
|
||||
const std::lock_guard<std::mutex> lock(fileInfosMutex);
|
||||
fileInfos.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void SDAttachedHandler([[maybe_unused]] SDUtilsAttachStatus status) {
|
||||
if (!sTitleRebooting) {
|
||||
_SYSLaunchTitleWithStdArgsInNoSplash(OSGetTitleID(), nullptr);
|
||||
@ -90,35 +109,31 @@ void SDAttachedHandler([[maybe_unused]] SDUtilsAttachStatus status) {
|
||||
}
|
||||
|
||||
ON_APPLICATION_START() {
|
||||
Cleanup();
|
||||
initLogging();
|
||||
|
||||
if (OSGetTitleID() == 0x0005001010040000L || // Wii U Menu JPN
|
||||
OSGetTitleID() == 0x0005001010040100L || // Wii U Menu USA
|
||||
OSGetTitleID() == 0x0005001010040200L) { // Wii U Menu EUR
|
||||
gInWiiUMenu = true;
|
||||
|
||||
if (SDUtils_Init() >= 0) {
|
||||
sSDUtilsInitDone = true;
|
||||
sTitleRebooting = false;
|
||||
SDUtils_AddAttachHandler(SDAttachedHandler);
|
||||
}
|
||||
if (SDUtils_IsSdCardMounted(&sSDIsMounted) >= 0 && sSDIsMounted) {
|
||||
readCustomTitlesFromSD();
|
||||
}
|
||||
} else {
|
||||
gInWiiUMenu = false;
|
||||
}
|
||||
|
||||
if (_SYSGetSystemApplicationTitleId(SYSTEM_APP_ID_HEALTH_AND_SAFETY) != OSGetTitleID()) {
|
||||
DEBUG_FUNCTION_LINE("gHomebrewLaunched to FALSE");
|
||||
gHomebrewLaunched = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
ON_APPLICATION_ENDS() {
|
||||
Cleanup();
|
||||
SaveRedirectionCleanUp();
|
||||
unmountAllRomfs();
|
||||
memset((void *) &gFileInfos, 0, sizeof(gFileInfos));
|
||||
FileHandleWrapper_FreeAll();
|
||||
deinitLogging();
|
||||
gInWiiUMenu = false;
|
||||
if (sSDUtilsInitDone) {
|
||||
@ -129,19 +144,29 @@ ON_APPLICATION_ENDS() {
|
||||
sSDIsMounted = false;
|
||||
}
|
||||
|
||||
|
||||
std::optional<std::shared_ptr<FileInfos>> getIDByLowerTitleID(uint32_t titleid_lower) {
|
||||
std::lock_guard<std::mutex> lock(fileInfosMutex);
|
||||
for (auto &cur : fileInfos) {
|
||||
if (cur->lowerTitleID == titleid_lower) {
|
||||
return cur;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void fillXmlForTitleID(uint32_t titleid_upper, uint32_t titleid_lower, ACPMetaXml *out_buf) {
|
||||
int32_t id = getIDByLowerTitleID(titleid_lower);
|
||||
if (id < 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to get id by titleid");
|
||||
auto titleIdInfoOpt = getIDByLowerTitleID(titleid_lower);
|
||||
if (!titleIdInfoOpt.has_value()) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to get info by titleid");
|
||||
return;
|
||||
}
|
||||
if (id >= FILE_INFO_SIZE) {
|
||||
return;
|
||||
}
|
||||
out_buf->title_id = ((uint64_t) titleid_upper * 0x100000000) + titleid_lower;
|
||||
strncpy(out_buf->longname_en, gFileInfos[id].longname, 64);
|
||||
strncpy(out_buf->shortname_en, gFileInfos[id].shortname, 64);
|
||||
strncpy(out_buf->publisher_en, gFileInfos[id].author, 64);
|
||||
auto &titleInfo = titleIdInfoOpt.value();
|
||||
|
||||
out_buf->title_id = (((uint64_t) titleid_upper) << 32) + titleid_lower;
|
||||
strncpy(out_buf->longname_en, titleInfo->longname.c_str(), sizeof(out_buf->longname_en) - 1);
|
||||
strncpy(out_buf->shortname_en, titleInfo->shortname.c_str(), sizeof(out_buf->shortname_en) - 1);
|
||||
strncpy(out_buf->publisher_en, titleInfo->author.c_str(), sizeof(out_buf->publisher_en) - 1);
|
||||
out_buf->e_manual = 1;
|
||||
out_buf->e_manual_version = 0;
|
||||
out_buf->title_version = 1;
|
||||
@ -157,34 +182,22 @@ void fillXmlForTitleID(uint32_t titleid_upper, uint32_t titleid_lower, ACPMetaXm
|
||||
out_buf->reserved_flag0 = 0x00010001;
|
||||
out_buf->reserved_flag6 = 0x00000003;
|
||||
out_buf->pc_usk = 128;
|
||||
strncpy(out_buf->product_code, "WUP-P-HBLD", strlen("WUP-P-HBLD") + 1);
|
||||
strncpy(out_buf->content_platform, "WUP", strlen("WUP") + 1);
|
||||
strncpy(out_buf->company_code, "0001", strlen("0001") + 1);
|
||||
}
|
||||
|
||||
/* hash: compute hash value of string */
|
||||
unsigned int hash(char *str) {
|
||||
unsigned int h;
|
||||
unsigned char *p;
|
||||
|
||||
h = 0;
|
||||
for (p = (unsigned char *) str; *p != '\0'; p++) {
|
||||
h = 37 * h + *p;
|
||||
}
|
||||
return h; // or, h % ARRAY_SIZE;
|
||||
strncpy(out_buf->product_code, "WUP-P-HBLD", sizeof(out_buf->product_code) - 1);
|
||||
strncpy(out_buf->content_platform, "WUP", sizeof(out_buf->content_platform) - 1);
|
||||
strncpy(out_buf->company_code, "0001", sizeof(out_buf->company_code) - 1);
|
||||
}
|
||||
|
||||
static int handler(void *user, const char *section, const char *name,
|
||||
const char *value) {
|
||||
auto *fInfo = (FileInfos *) user;
|
||||
auto *fInfo = (std::shared_ptr<FileInfos> *) user;
|
||||
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
|
||||
|
||||
if (MATCH("menu", "longname")) {
|
||||
strncpy(fInfo->longname, value, 64 - 1);
|
||||
fInfo->operator->()->longname = value;
|
||||
} else if (MATCH("menu", "shortname")) {
|
||||
strncpy(fInfo->shortname, value, 64 - 1);
|
||||
fInfo->operator->()->shortname = value;
|
||||
} else if (MATCH("menu", "author")) {
|
||||
strncpy(fInfo->author, value, 64 - 1);
|
||||
fInfo->operator->()->author = value;
|
||||
} else {
|
||||
return 0; /* unknown section/name, error */
|
||||
}
|
||||
@ -194,20 +207,16 @@ static int handler(void *user, const char *section, const char *name,
|
||||
|
||||
bool CheckFileExistsHelper(const char *path);
|
||||
void readCustomTitlesFromSD() {
|
||||
std::lock_guard<std::mutex> lock(fileInfosMutex);
|
||||
if (!fileInfos.empty()) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Using cached value");
|
||||
return;
|
||||
}
|
||||
// Reset current infos
|
||||
unmountAllRomfs();
|
||||
memset((void *) &gFileInfos, 0, sizeof(gFileInfos));
|
||||
|
||||
DirList dirList("fs:/vol/external01/wiiu/apps", ".rpx,.wuhb", DirList::Files | DirList::CheckSubfolders, 1);
|
||||
dirList.SortList();
|
||||
|
||||
int j = 0;
|
||||
for (int i = 0; i < dirList.GetFilecount(); i++) {
|
||||
if (j >= FILE_INFO_SIZE) {
|
||||
DEBUG_FUNCTION_LINE_ERR("TOO MANY TITLES");
|
||||
break;
|
||||
}
|
||||
|
||||
//! skip wiiload temp files
|
||||
if (strcasecmp(dirList.GetFilename(i), "temp.rpx") == 0) {
|
||||
continue;
|
||||
@ -228,48 +237,61 @@ void readCustomTitlesFromSD() {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
auto repl = "fs:/vol/external01/";
|
||||
auto input = dirList.GetFilepath(i);
|
||||
const char * relativeFilepath;
|
||||
|
||||
if (std::string_view(input).starts_with(repl)) {
|
||||
strncpy(gFileInfos[j].path, &input[strlen(repl)], sizeof(gFileInfos[j].path));
|
||||
relativeFilepath = &input[strlen(repl)];
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Skip %s, Path doesn't start with %s (This should never happen", input, repl);
|
||||
continue;
|
||||
}
|
||||
|
||||
gFileInfos[j].lowerTitleID = hash(gFileInfos[j].path);
|
||||
auto fileInfo = make_shared_nothrow<FileInfos>(relativeFilepath);
|
||||
if (!fileInfo) {
|
||||
DEBUG_FUNCTION_LINE_ERR("No more memory");
|
||||
break;
|
||||
}
|
||||
|
||||
MCPTitleListType *cur_title_info = &(gFileInfos[j].titleInfo);
|
||||
std::lock_guard<std::mutex> infoLock(fileInfo->accessLock);
|
||||
|
||||
snprintf(cur_title_info->path, sizeof(cur_title_info->path), "/custom/%08X%08X", UPPER_TITLE_ID_HOMEBREW, gFileInfos[j].lowerTitleID);
|
||||
auto *cur_title_info = &(fileInfo->titleInfo);
|
||||
|
||||
strncpy(gFileInfos[j].filename, dirList.GetFilename(i), sizeof(gFileInfos[j].filename));
|
||||
strncpy(gFileInfos[j].longname, dirList.GetFilename(i), sizeof(gFileInfos[j].longname));
|
||||
strncpy(gFileInfos[j].shortname, dirList.GetFilename(i), sizeof(gFileInfos[j].shortname));
|
||||
strncpy(gFileInfos[j].author, dirList.GetFilename(i), sizeof(gFileInfos[j].author));
|
||||
gFileInfos[j].source = 0; //SD Card;
|
||||
snprintf(cur_title_info->path, sizeof(cur_title_info->path), "/custom/%08X%08X", UPPER_TITLE_ID_HOMEBREW, fileInfo->lowerTitleID);
|
||||
|
||||
const char *indexedDevice = "mlc";
|
||||
strncpy(cur_title_info->indexedDevice, indexedDevice, sizeof(cur_title_info->indexedDevice));
|
||||
strncpy(cur_title_info->indexedDevice, indexedDevice, sizeof(cur_title_info->indexedDevice) - 1);
|
||||
|
||||
fileInfo->filename = dirList.GetFilename(i);
|
||||
fileInfo->longname = dirList.GetFilename(i);
|
||||
fileInfo->shortname = dirList.GetFilename(i);
|
||||
fileInfo->author = dirList.GetFilename(i);
|
||||
|
||||
// System apps don't have a splash screen.
|
||||
cur_title_info->appType = MCP_APP_TYPE_SYSTEM_APPS;
|
||||
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Check %s", fileInfo->filename.c_str());
|
||||
|
||||
// Check if the bootTvTex and bootDrcTex exists
|
||||
if (std::string_view(gFileInfos[j].filename).ends_with(".wuhb")) {
|
||||
if (std::string_view(fileInfo->filename).ends_with(".wuhb")) {
|
||||
int result = 0;
|
||||
|
||||
#define TMP_BUNDLE_NAME "romfscheck"
|
||||
|
||||
if (WUHBUtils_MountBundle(TMP_BUNDLE_NAME, dirList.GetFilepath(i), BundleSource_FileDescriptor, &result) == WUHB_UTILS_RESULT_SUCCESS && result >= 0) {
|
||||
fileInfo->isBundle = true;
|
||||
uint8_t *buffer;
|
||||
uint32_t bufferSize;
|
||||
|
||||
auto readRes = WUHBUtils_ReadWholeFile(TMP_BUNDLE_NAME ":/meta/meta.ini", &buffer, &bufferSize);
|
||||
if (readRes == WUHB_UTILS_RESULT_SUCCESS) {
|
||||
buffer[bufferSize - 1] = '\0';
|
||||
if (ini_parse_string((const char *) buffer, handler, &gFileInfos[j]) < 0) {
|
||||
if (ini_parse_string((const char *) buffer, handler, &fileInfo) < 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to parse meta.ini");
|
||||
}
|
||||
free(buffer);
|
||||
@ -283,6 +305,7 @@ void readCustomTitlesFromSD() {
|
||||
if (CheckFileExistsHelper(bootTvTexPath) && CheckFileExistsHelper(bootDrcTexPath)) {
|
||||
// Show splash screens
|
||||
cur_title_info->appType = MCP_APP_TYPE_GAME;
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Title has splashscreen");
|
||||
}
|
||||
|
||||
int32_t unmountRes;
|
||||
@ -294,12 +317,12 @@ void readCustomTitlesFromSD() {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to unmount \"%s\"", TMP_BUNDLE_NAME);
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("%s is not a .wuhb file: %d", dirList.GetFilepath(i), result);
|
||||
DEBUG_FUNCTION_LINE_ERR("%s is not a valid .wuhb file: %d", dirList.GetFilepath(i), result);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
cur_title_info->titleId = TITLE_ID_HOMEBREW_MASK | gFileInfos[j].lowerTitleID;
|
||||
cur_title_info->titleId = TITLE_ID_HOMEBREW_MASK | fileInfo->lowerTitleID;
|
||||
cur_title_info->titleVersion = 1;
|
||||
cur_title_info->groupId = 0x400;
|
||||
|
||||
@ -307,7 +330,7 @@ void readCustomTitlesFromSD() {
|
||||
cur_title_info->sdkVersion = __OSGetProcessSDKVersion();
|
||||
cur_title_info->unk0x60 = 0;
|
||||
|
||||
j++;
|
||||
fileInfos.push_front(fileInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@ -327,39 +350,43 @@ bool CheckFileExistsHelper(const char *path) {
|
||||
}
|
||||
|
||||
DECL_FUNCTION(int32_t, MCP_TitleList, uint32_t handle, uint32_t *outTitleCount, MCPTitleListType *titleList, uint32_t size) {
|
||||
int32_t result = real_MCP_TitleList(handle, outTitleCount, titleList, size);
|
||||
uint32_t titlecount = *outTitleCount;
|
||||
int32_t result = real_MCP_TitleList(handle, outTitleCount, titleList, size);
|
||||
|
||||
std::lock_guard<std::mutex> lock(fileinfoMutex);
|
||||
for (auto &gFileInfo : gFileInfos) {
|
||||
if (gFileInfo.lowerTitleID == 0) {
|
||||
break;
|
||||
}
|
||||
memcpy(&(titleList[titlecount]), &(gFileInfo.titleInfo), sizeof(gFileInfo.titleInfo));
|
||||
titlecount++;
|
||||
if (!gInWiiUMenu) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Not in Wii U Menu");
|
||||
return result;
|
||||
}
|
||||
|
||||
*outTitleCount = titlecount;
|
||||
uint32_t titleCount = *outTitleCount;
|
||||
|
||||
std::lock_guard<std::mutex> lock(fileInfosMutex);
|
||||
readCustomTitlesFromSD();
|
||||
|
||||
for (auto &gFileInfo : fileInfos) {
|
||||
memcpy(&(titleList[titleCount]), &(gFileInfo->titleInfo), sizeof(MCPTitleListType));
|
||||
titleCount++;
|
||||
}
|
||||
|
||||
*outTitleCount = titleCount;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DECL_FUNCTION(int32_t, ACPCheckTitleLaunchByTitleListTypeEx, MCPTitleListType *title, uint32_t u2) {
|
||||
if ((title->titleId & TITLE_ID_HOMEBREW_MASK) == TITLE_ID_HOMEBREW_MASK) {
|
||||
int32_t id = getIDByLowerTitleID(title->titleId & 0xFFFFFFFF);
|
||||
if (id >= 0) {
|
||||
std::lock_guard<std::mutex> lock(fileInfosMutex);
|
||||
auto fileInfo = getIDByLowerTitleID(title->titleId & 0xFFFFFFFF);
|
||||
if (fileInfo.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Starting a homebrew title");
|
||||
|
||||
fillXmlForTitleID((title->titleId & 0xFFFFFFFF00000000) >> 32, (title->titleId & 0xFFFFFFFF), &gLaunchXML);
|
||||
|
||||
std::string bundleFilePath = std::string("/vol/external01/") + gFileInfos[id].path;
|
||||
|
||||
gHomebrewLaunched = TRUE;
|
||||
|
||||
RPXLoader_LoadFromSDOnNextLaunch(gFileInfos[id].path);
|
||||
RPXLoader_LoadFromSDOnNextLaunch(fileInfo.value()->relativeFilepath.c_str());
|
||||
return 0;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to get the id for titleID %016llX", title->titleId);
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to get info for titleID %016llX", title->titleId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -367,41 +394,42 @@ DECL_FUNCTION(int32_t, ACPCheckTitleLaunchByTitleListTypeEx, MCPTitleListType *t
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DECL_FUNCTION(int, FSOpenFile, FSClient *client, FSCmdBlock *block, char *path, const char *mode, uint32_t *handle, int error) {
|
||||
const char *start = "/vol/storage_mlc01/sys/title/0005000F";
|
||||
const char *icon = ".tga";
|
||||
const char *tga = ".tga";
|
||||
const char *iconTex = "iconTex.tga";
|
||||
const char *sound = ".btsnd";
|
||||
|
||||
std::string_view pathStr = path;
|
||||
|
||||
if (pathStr.ends_with(icon) || pathStr.ends_with(sound)) {
|
||||
if (strncmp(path, start, strlen(start)) == 0) {
|
||||
int res = FS_STATUS_NOT_FOUND;
|
||||
|
||||
if (pathStr.ends_with(iconTex)) {
|
||||
// fallback to dummy icon if loaded homebrew is no .wuhb
|
||||
*handle = 0x13371338;
|
||||
res = FS_STATUS_OK;
|
||||
}
|
||||
|
||||
uint32_t lowerTitleID;
|
||||
char *id = path + 1 + strlen(start);
|
||||
id[8] = 0;
|
||||
char *ending = id + 9;
|
||||
sscanf(id, "%08X", &lowerTitleID);
|
||||
int32_t idVal = getIDByLowerTitleID(lowerTitleID);
|
||||
if (idVal >= 0) {
|
||||
if (!std::string_view(gFileInfos[idVal].filename).ends_with(".wuhb")) {
|
||||
return res;
|
||||
if (pathStr.starts_with(start)) {
|
||||
std::unique_ptr<FileReader> reader;
|
||||
if (pathStr.ends_with(tga) || pathStr.ends_with(sound)) {
|
||||
char *id = path + 1 + strlen(start);
|
||||
id[8] = 0;
|
||||
char *relativePath = id + 9;
|
||||
auto lowerTitleID = strtoul(id, 0, 16);
|
||||
auto fileInfo = getIDByLowerTitleID(lowerTitleID);
|
||||
if (fileInfo.has_value()) {
|
||||
reader = make_unique_nothrow<FileReaderWUHB>(fileInfo.value(), relativePath, !gHomebrewLaunched);
|
||||
if (reader && !reader->isReady()) {
|
||||
reader.reset();
|
||||
}
|
||||
if (OpenFileForID(idVal, ending, handle) >= 0) {
|
||||
return FS_STATUS_OK;
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to find id for titleID %08X", lowerTitleID);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
// If the icon is requested and loading it from a bundle failed, we fall back to a default one.
|
||||
if (reader == nullptr && pathStr.ends_with(iconTex)) {
|
||||
reader = make_unique_nothrow<FileReader>((uint8_t *) iconTex_tga, iconTex_tga_size);
|
||||
if (reader && !reader->isReady()) {
|
||||
reader.reset();
|
||||
}
|
||||
}
|
||||
if (reader) {
|
||||
std::lock_guard<std::mutex> lock(fileReaderListMutex);
|
||||
*handle = reader->getHandle();
|
||||
openFileReaders.push_front(std::move(reader));
|
||||
return FS_STATUS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@ -410,48 +438,18 @@ DECL_FUNCTION(int, FSOpenFile, FSClient *client, FSCmdBlock *block, char *path,
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSCloseFile, FSClient *client, FSCmdBlock *block, FSFileHandle handle, uint32_t flags) {
|
||||
if (handle == 0x13371338) {
|
||||
return FS_STATUS_OK;
|
||||
} else if ((handle & 0xFF000000) == 0xFF000000) {
|
||||
int32_t fd = (handle & 0x00000FFF);
|
||||
int32_t romid = (handle & 0x00FFF000) >> 12;
|
||||
std::lock_guard<std::mutex> lock(fileinfoMutex);
|
||||
uint32_t rl_handle = gFileHandleWrapper[fd].handle;
|
||||
if (WUHBUtils_FileClose(rl_handle) != WUHB_UTILS_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to close file %08X", rl_handle);
|
||||
}
|
||||
if (gFileInfos[romid].openedFiles--) {
|
||||
DCFlushRange(&gFileInfos[romid].openedFiles, 4);
|
||||
if (gFileInfos[romid].openedFiles <= 0) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("unmount romfs no more handles");
|
||||
unmountRomfs(romid);
|
||||
}
|
||||
}
|
||||
if (remove_locked_first_if(fileReaderListMutex, openFileReaders, [handle](auto &cur) { return cur->getHandle() == handle; })) {
|
||||
return FS_STATUS_OK;
|
||||
}
|
||||
|
||||
return real_FSCloseFile(client, block, handle, flags);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSReadFile, FSClient *client, FSCmdBlock *block, uint8_t *buffer, uint32_t size, uint32_t count, FSFileHandle handle, uint32_t unk1, uint32_t flags) {
|
||||
if (handle == 0x13371338) {
|
||||
uint32_t cpySize = size * count;
|
||||
if (iconTex_tga_size < cpySize) {
|
||||
cpySize = iconTex_tga_size;
|
||||
}
|
||||
memcpy(buffer, iconTex_tga, cpySize);
|
||||
return (FSStatus) (cpySize / size);
|
||||
} else if ((handle & 0xFF000000) == 0xFF000000) {
|
||||
uint32_t fd = (handle & 0x00000FFF);
|
||||
[[maybe_unused]] uint32_t romid = (handle & 0x00FFF000) >> 12;
|
||||
|
||||
uint32_t rl_handle = gFileHandleWrapper[fd].handle;
|
||||
|
||||
int readSize = 0;
|
||||
if (WUHBUtils_FileRead(rl_handle, buffer, (size * count), &readSize) == WUHB_UTILS_RESULT_SUCCESS) {
|
||||
return (FSStatus) (readSize / size);
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to read file");
|
||||
OSFatal("Failed to read file");
|
||||
const std::lock_guard<std::mutex> lock(fileReaderListMutex);
|
||||
for (auto &reader : openFileReaders) {
|
||||
if ((uint32_t) reader.get() == (uint32_t) handle) {
|
||||
return (FSStatus) (reader->read(buffer, size * count) / size);
|
||||
}
|
||||
}
|
||||
FSStatus result = real_FSReadFile(client, block, buffer, size, count, handle, unk1, flags);
|
||||
@ -604,9 +602,9 @@ DECL_FUNCTION(uint32_t, MCPGetTitleInternal, uint32_t mcp_handle, void *input, u
|
||||
if (input != nullptr) {
|
||||
auto *inputPtrAsU32 = (uint32_t *) input;
|
||||
if (inputPtrAsU32[0] == UPPER_TITLE_ID_HOMEBREW && out_cnt >= 1) {
|
||||
for (auto &gFileInfo : gFileInfos) {
|
||||
if (gFileInfo.lowerTitleID == inputPtrAsU32[1]) {
|
||||
memcpy(&titles[0], &(gFileInfo.titleInfo), sizeof(MCPTitleListType));
|
||||
for (auto &gFileInfo : fileInfos) {
|
||||
if (gFileInfo->lowerTitleID == inputPtrAsU32[1]) {
|
||||
memcpy(&titles[0], &(gFileInfo->titleInfo), sizeof(MCPTitleListType));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ const char *StringTools::FullpathToFilename(const char *path) {
|
||||
void StringTools::RemoveDoubleSlashs(std::string &str) {
|
||||
uint32_t length = str.size();
|
||||
|
||||
//! clear path of double slashes
|
||||
//! clear relativeFilepath of double slashes
|
||||
for (uint32_t i = 1; i < length; ++i) {
|
||||
if (str[i - 1] == '/' && str[i] == '/') {
|
||||
str.erase(i, 1);
|
||||
|
@ -1,39 +0,0 @@
|
||||
#include "utils/logger.h"
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <whb/log.h>
|
||||
|
||||
// https://gist.github.com/ccbrown/9722406
|
||||
void dumpHex(const void *data, size_t size) {
|
||||
char ascii[17];
|
||||
size_t i, j;
|
||||
ascii[16] = '\0';
|
||||
DEBUG_FUNCTION_LINE_WRITE("0x%08X (0x0000): ", data);
|
||||
for (i = 0; i < size; ++i) {
|
||||
WHBLogWritef("%02X ", ((unsigned char *) data)[i]);
|
||||
if (((unsigned char *) data)[i] >= ' ' && ((unsigned char *) data)[i] <= '~') {
|
||||
ascii[i % 16] = ((unsigned char *) data)[i];
|
||||
} else {
|
||||
ascii[i % 16] = '.';
|
||||
}
|
||||
if ((i + 1) % 8 == 0 || i + 1 == size) {
|
||||
WHBLogWritef(" ");
|
||||
if ((i + 1) % 16 == 0) {
|
||||
WHBLogPrintf("| %s ", ascii);
|
||||
if (i + 1 < size) {
|
||||
DEBUG_FUNCTION_LINE_WRITE("0x%08X (0x%04X); ", data + i + 1, i + 1);
|
||||
}
|
||||
} else if (i + 1 == size) {
|
||||
ascii[(i + 1) % 16] = '\0';
|
||||
if ((i + 1) % 16 <= 8) {
|
||||
WHBLogWritef(" ");
|
||||
}
|
||||
for (j = (i + 1) % 16; j < 16; ++j) {
|
||||
WHBLogWritef(" ");
|
||||
}
|
||||
WHBLogPrintf("| %s ", ascii);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
13
src/utils/utils.cpp
Normal file
13
src/utils/utils.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include <stdint.h>
|
||||
|
||||
/* hash: compute hash value of string */
|
||||
unsigned int hash_string(const char *str) {
|
||||
unsigned int h;
|
||||
unsigned char *p;
|
||||
|
||||
h = 0;
|
||||
for (p = (unsigned char *) str; *p != '\0'; p++) {
|
||||
h = 37 * h + *p;
|
||||
}
|
||||
return h; // or, h % ARRAY_SIZE;
|
||||
}
|
@ -1,36 +1,32 @@
|
||||
#ifndef __UTILS_H_
|
||||
#define __UTILS_H_
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <forward_list>
|
||||
#include <malloc.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
uint32_t hash_string(const char *);
|
||||
|
||||
#define LIMIT(x, min, max) \
|
||||
({ \
|
||||
typeof(x) _x = x; \
|
||||
typeof(min) _min = min; \
|
||||
typeof(max) _max = max; \
|
||||
(((_x) < (_min)) ? (_min) : ((_x) > (_max)) ? (_max) \
|
||||
: (_x)); \
|
||||
})
|
||||
|
||||
#define DegToRad(a) ((a) *0.01745329252f)
|
||||
#define RadToDeg(a) ((a) *57.29577951f)
|
||||
|
||||
#define ALIGN4(x) (((x) + 3) & ~3)
|
||||
#define ALIGN32(x) (((x) + 31) & ~31)
|
||||
|
||||
#define le16(i) ((((uint16_t) ((i) &0xFF)) << 8) | ((uint16_t) (((i) &0xFF00) >> 8)))
|
||||
#define le32(i) ((((uint32_t) le16((i) &0xFFFF)) << 16) | ((uint32_t) le16(((i) &0xFFFF0000) >> 16)))
|
||||
#define le64(i) ((((uint64_t) le32((i) &0xFFFFFFFFLL)) << 32) | ((uint64_t) le32(((i) &0xFFFFFFFF00000000LL) >> 32)))
|
||||
|
||||
//Needs to have log_init() called beforehand.
|
||||
void dumpHex(const void *data, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
template<class T, class... Args>
|
||||
std::unique_ptr<T> make_unique_nothrow(Args &&...args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
|
||||
return std::unique_ptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template<class T, class... Args>
|
||||
std::shared_ptr<T> make_shared_nothrow(Args &&...args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
|
||||
return std::shared_ptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template<typename T, class Allocator, class Predicate>
|
||||
bool remove_locked_first_if(std::mutex &mutex, std::forward_list<T, Allocator> &list, Predicate pred) {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
auto oit = list.before_begin(), it = std::next(oit);
|
||||
while (it != list.end()) {
|
||||
if (pred(*it)) {
|
||||
list.erase_after(oit);
|
||||
return true;
|
||||
}
|
||||
oit = it++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __UTILS_H_
|
||||
|
Loading…
Reference in New Issue
Block a user