mirror of
https://github.com/wiiu-env/wiiload_plugin.git
synced 2024-11-27 21:14:14 +01:00
Rewrite logic, clean up and remove unused parts
This commit is contained in:
parent
9d44e51a75
commit
d4984dafbe
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,3 +9,4 @@ cmake-build-debug/
|
||||
.idea/
|
||||
*.rpx
|
||||
*.txt
|
||||
*.zip
|
||||
|
@ -1,6 +1,6 @@
|
||||
FROM ghcr.io/wiiu-env/devkitppc:20231112
|
||||
|
||||
COPY --from=ghcr.io/wiiu-env/wiiupluginsystem:0.8.0-dev-20231221-ca17105 /artifacts $DEVKITPRO
|
||||
COPY --from=ghcr.io/wiiu-env/wiiupluginsystem:0.8.0-dev-20240302-3b5cc2f /artifacts $DEVKITPRO
|
||||
COPY --from=ghcr.io/wiiu-env/libwupsbackend:20230621 /artifacts $DEVKITPRO
|
||||
COPY --from=ghcr.io/wiiu-env/librpxloader:20230621 /artifacts $DEVKITPRO
|
||||
COPY --from=ghcr.io/wiiu-env/libnotifications:20230621 /artifacts $DEVKITPRO
|
||||
|
1
Makefile
1
Makefile
@ -23,7 +23,6 @@ WUMS_ROOT := $(DEVKITPRO)/wums
|
||||
TARGET := wiiload
|
||||
BUILD := build
|
||||
SOURCES := src \
|
||||
src/fs \
|
||||
src/utils
|
||||
DATA := data
|
||||
INCLUDES := src
|
||||
|
71
src/config.cpp
Normal file
71
src/config.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
#include "config.h"
|
||||
#include "globals.h"
|
||||
#include "utils/TcpReceiver.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/utils.h"
|
||||
#include <string>
|
||||
#include <wups/config/WUPSConfigItemBoolean.h>
|
||||
#include <wups/storage.h>
|
||||
|
||||
static void gServerEnabledChanged(ConfigItemBoolean *item, bool newValue) {
|
||||
if (std::string_view(WIILOAD_ENABLED_STRING) != item->identifier) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Unexpected identifier in bool callback: %s", item->identifier);
|
||||
return;
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("New value in gWiiloadServerEnabled: %d", newValue);
|
||||
gWiiloadServerEnabled = newValue;
|
||||
|
||||
gTcpReceiverThread.reset();
|
||||
|
||||
if (gWiiloadServerEnabled) {
|
||||
DEBUG_FUNCTION_LINE("Starting server!");
|
||||
gTcpReceiverThread = make_unique_nothrow<TcpReceiver>(4299);
|
||||
if (gTcpReceiverThread == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to create wiiload thread");
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Wiiload server has been stopped!");
|
||||
}
|
||||
// If the value has changed, we store it in the storage.
|
||||
WUPSStorageError res;
|
||||
if ((res = WUPSStorageAPI::Store(item->identifier, gWiiloadServerEnabled)) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to store gWiiloadServerEnabled: %s (%d)", WUPSStorageAPI_GetStatusStr(res), res);
|
||||
}
|
||||
}
|
||||
|
||||
static WUPSConfigAPICallbackStatus ConfigMenuOpenedCallback(WUPSConfigCategoryHandle rootHandle) {
|
||||
try {
|
||||
WUPSConfigCategory root = WUPSConfigCategory(rootHandle);
|
||||
|
||||
root.add(WUPSConfigItemBoolean::Create(WIILOAD_ENABLED_STRING, "Enable Wiiload",
|
||||
DEFAULT_WIILOAD_ENABLED_VALUE, gWiiloadServerEnabled,
|
||||
&gServerEnabledChanged));
|
||||
|
||||
} catch (std::exception &e) {
|
||||
OSReport("Exception: %s\n", e.what());
|
||||
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR;
|
||||
}
|
||||
return WUPSCONFIG_API_CALLBACK_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static void ConfigMenuClosedCallback() {
|
||||
// Save all changes
|
||||
if (WUPSStorageAPI::SaveStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to close storage");
|
||||
}
|
||||
}
|
||||
|
||||
void InitConfigAndStorage() {
|
||||
WUPSConfigAPIOptionsV1 configOptions = {.name = "Wiiload Plugin"};
|
||||
if (WUPSConfigAPI_Init(configOptions, ConfigMenuOpenedCallback, ConfigMenuClosedCallback) != WUPSCONFIG_API_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to init config api");
|
||||
}
|
||||
|
||||
if (WUPSStorageAPI::GetOrStoreDefault(WIILOAD_ENABLED_STRING, gWiiloadServerEnabled, DEFAULT_WIILOAD_ENABLED_VALUE) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to get or create item \"%s\"", WIILOAD_ENABLED_STRING);
|
||||
}
|
||||
|
||||
if (WUPSStorageAPI::SaveStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to save storage");
|
||||
}
|
||||
}
|
6
src/config.h
Normal file
6
src/config.h
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#define WIILOAD_ENABLED_STRING "enabled"
|
||||
#define DEFAULT_WIILOAD_ENABLED_VALUE true
|
||||
|
||||
void InitConfigAndStorage();
|
172
src/fs/CFile.cpp
172
src/fs/CFile.cpp
@ -1,172 +0,0 @@
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <fs/CFile.hpp>
|
||||
#include <strings.h>
|
||||
|
||||
CFile::CFile() {
|
||||
iFd = -1;
|
||||
mem_file = nullptr;
|
||||
filesize = 0;
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
CFile::CFile(const std::string &filepath, eOpenTypes mode) {
|
||||
iFd = -1;
|
||||
this->open(filepath, mode);
|
||||
}
|
||||
|
||||
CFile::CFile(const uint8_t *mem, int32_t size) {
|
||||
iFd = -1;
|
||||
this->open(mem, size);
|
||||
}
|
||||
|
||||
CFile::~CFile() {
|
||||
this->close();
|
||||
}
|
||||
|
||||
int32_t CFile::open(const std::string &filepath, eOpenTypes mode) {
|
||||
this->close();
|
||||
|
||||
int32_t openMode = 0;
|
||||
|
||||
// This depend on the devoptab implementation.
|
||||
// see https://github.com/devkitPro/wut/blob/master/libraries/wutdevoptab/devoptab_fs_open.c#L21 fpr reference
|
||||
|
||||
switch (mode) {
|
||||
default:
|
||||
case ReadOnly: // file must exist
|
||||
openMode = O_RDONLY;
|
||||
break;
|
||||
case WriteOnly: // file will be created / zerod
|
||||
openMode = O_TRUNC | O_CREAT | O_WRONLY;
|
||||
break;
|
||||
case ReadWrite: // file must exist
|
||||
openMode = O_RDWR;
|
||||
break;
|
||||
case Append: // append to file, file will be created if missing. write only
|
||||
openMode = O_CREAT | O_APPEND | O_WRONLY;
|
||||
break;
|
||||
}
|
||||
|
||||
//! Using fopen works only on the first launch as expected
|
||||
//! on the second launch it causes issues because we don't overwrite
|
||||
//! the .data sections which is needed for a normal application to re-init
|
||||
//! this will be added with launching as RPX
|
||||
iFd = ::open(filepath.c_str(), openMode);
|
||||
if (iFd < 0)
|
||||
return iFd;
|
||||
|
||||
|
||||
filesize = ::lseek(iFd, 0, SEEK_END);
|
||||
::lseek(iFd, 0, SEEK_SET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t CFile::open(const uint8_t *mem, int32_t size) {
|
||||
this->close();
|
||||
|
||||
mem_file = mem;
|
||||
filesize = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CFile::close() {
|
||||
if (iFd >= 0)
|
||||
::close(iFd);
|
||||
|
||||
iFd = -1;
|
||||
mem_file = NULL;
|
||||
filesize = 0;
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
int32_t CFile::read(uint8_t *ptr, size_t size) {
|
||||
if (iFd >= 0) {
|
||||
int32_t ret = ::read(iFd, ptr, size);
|
||||
if (ret > 0)
|
||||
pos += ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t readsize = size;
|
||||
|
||||
if (readsize > (int64_t) (filesize - pos))
|
||||
readsize = filesize - pos;
|
||||
|
||||
if (readsize <= 0)
|
||||
return readsize;
|
||||
|
||||
if (mem_file != NULL) {
|
||||
memcpy(ptr, mem_file + pos, readsize);
|
||||
pos += readsize;
|
||||
return readsize;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int64_t CFile::write(const uint8_t *ptr, size_t size) {
|
||||
if (iFd >= 0) {
|
||||
size_t done = 0;
|
||||
while (done < size) {
|
||||
int32_t ret = ::write(iFd, ptr, size - done);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
ptr += ret;
|
||||
done += ret;
|
||||
pos += ret;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t CFile::seek(long int offset, int32_t origin) {
|
||||
int32_t ret = 0;
|
||||
int64_t newPos = pos;
|
||||
|
||||
if (origin == SEEK_SET) {
|
||||
newPos = offset;
|
||||
} else if (origin == SEEK_CUR) {
|
||||
newPos += offset;
|
||||
} else if (origin == SEEK_END) {
|
||||
newPos = filesize + offset;
|
||||
}
|
||||
|
||||
if (newPos < 0) {
|
||||
pos = 0;
|
||||
} else {
|
||||
pos = newPos;
|
||||
}
|
||||
|
||||
if (iFd >= 0)
|
||||
ret = ::lseek(iFd, pos, SEEK_SET);
|
||||
|
||||
if (mem_file != NULL) {
|
||||
if (pos > filesize) {
|
||||
pos = filesize;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t CFile::fwrite(const char *format, ...) {
|
||||
char tmp[512];
|
||||
tmp[0] = 0;
|
||||
int32_t result = -1;
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||
result = this->write((uint8_t *) tmp, strlen(tmp));
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fcntl.h>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
#include <wut_types.h>
|
||||
|
||||
class CFile {
|
||||
public:
|
||||
enum eOpenTypes {
|
||||
ReadOnly,
|
||||
WriteOnly,
|
||||
ReadWrite,
|
||||
Append
|
||||
};
|
||||
|
||||
CFile();
|
||||
|
||||
CFile(const std::string &filepath, eOpenTypes mode);
|
||||
|
||||
CFile(const uint8_t *memory, int32_t memsize);
|
||||
|
||||
virtual ~CFile();
|
||||
|
||||
int32_t open(const std::string &filepath, eOpenTypes mode);
|
||||
|
||||
int32_t open(const uint8_t *memory, int32_t memsize);
|
||||
|
||||
[[nodiscard]] BOOL isOpen() const {
|
||||
if (iFd >= 0)
|
||||
return true;
|
||||
|
||||
if (mem_file)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void close();
|
||||
|
||||
int32_t read(uint8_t *ptr, size_t size);
|
||||
|
||||
int64_t write(const uint8_t *ptr, size_t size);
|
||||
|
||||
int32_t fwrite(const char *format, ...);
|
||||
|
||||
int32_t seek(long int offset, int32_t origin);
|
||||
|
||||
[[nodiscard]] uint64_t tell() const {
|
||||
return pos;
|
||||
};
|
||||
|
||||
[[nodiscard]] uint64_t size() const {
|
||||
return filesize;
|
||||
};
|
||||
|
||||
void rewind() {
|
||||
this->seek(0, SEEK_SET);
|
||||
};
|
||||
|
||||
protected:
|
||||
int32_t iFd;
|
||||
const uint8_t *mem_file;
|
||||
uint64_t filesize;
|
||||
uint64_t pos;
|
||||
};
|
@ -1,213 +0,0 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2010
|
||||
* by Dimok
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any
|
||||
* purpose, including commercial applications, and to alter it and
|
||||
* redistribute it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you
|
||||
* must not claim that you wrote the original software. If you use
|
||||
* this software in a product, an acknowledgment in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and
|
||||
* must not be misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* DirList Class
|
||||
* for WiiXplorer 2010
|
||||
***************************************************************************/
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <strings.h>
|
||||
#include <sys/dirent.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <fs/DirList.h>
|
||||
#include <utils/StringTools.h>
|
||||
|
||||
DirList::DirList() {
|
||||
Flags = 0;
|
||||
Filter = 0;
|
||||
Depth = 0;
|
||||
}
|
||||
|
||||
DirList::DirList(const std::string &path, const char *filter, uint32_t flags, uint32_t maxDepth) {
|
||||
this->LoadPath(path, filter, flags, maxDepth);
|
||||
this->SortList();
|
||||
}
|
||||
|
||||
DirList::~DirList() {
|
||||
ClearList();
|
||||
}
|
||||
|
||||
BOOL DirList::LoadPath(const std::string &folder, const char *filter, uint32_t flags, uint32_t maxDepth) {
|
||||
if (folder.empty()) return false;
|
||||
|
||||
Flags = flags;
|
||||
Filter = filter;
|
||||
Depth = maxDepth;
|
||||
|
||||
std::string folderpath(folder);
|
||||
uint32_t length = folderpath.size();
|
||||
|
||||
//! clear path of double slashes
|
||||
StringTools::RemoveDoubleSlashs(folderpath);
|
||||
|
||||
//! remove last slash if exists
|
||||
if (length > 0 && folderpath[length - 1] == '/')
|
||||
folderpath.erase(length - 1);
|
||||
|
||||
//! add root slash if missing
|
||||
if (folderpath.find('/') == std::string::npos) {
|
||||
folderpath += '/';
|
||||
}
|
||||
|
||||
return InternalLoadPath(folderpath);
|
||||
}
|
||||
|
||||
BOOL DirList::InternalLoadPath(std::string &folderpath) {
|
||||
if (folderpath.size() < 3)
|
||||
return false;
|
||||
|
||||
struct dirent *dirent = nullptr;
|
||||
DIR *dir = NULL;
|
||||
|
||||
dir = opendir(folderpath.c_str());
|
||||
if (dir == NULL)
|
||||
return false;
|
||||
|
||||
while ((dirent = readdir(dir)) != 0) {
|
||||
BOOL isDir = dirent->d_type & DT_DIR;
|
||||
const char *filename = dirent->d_name;
|
||||
|
||||
if (isDir) {
|
||||
if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0)
|
||||
continue;
|
||||
|
||||
if ((Flags & CheckSubfolders) && (Depth > 0)) {
|
||||
int32_t length = folderpath.size();
|
||||
if (length > 2 && folderpath[length - 1] != '/') {
|
||||
folderpath += '/';
|
||||
}
|
||||
folderpath += filename;
|
||||
|
||||
Depth--;
|
||||
InternalLoadPath(folderpath);
|
||||
folderpath.erase(length);
|
||||
Depth++;
|
||||
}
|
||||
|
||||
if (!(Flags & Dirs))
|
||||
continue;
|
||||
} else if (!(Flags & Files)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Filter) {
|
||||
char *fileext = strrchr(filename, '.');
|
||||
if (!fileext)
|
||||
continue;
|
||||
|
||||
if (StringTools::strtokcmp(fileext, Filter, ",") == 0)
|
||||
AddEntrie(folderpath, filename, isDir);
|
||||
} else {
|
||||
AddEntrie(folderpath, filename, isDir);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DirList::AddEntrie(const std::string &filepath, const char *filename, BOOL isDir) {
|
||||
if (!filename)
|
||||
return;
|
||||
|
||||
int32_t pos = FileInfo.size();
|
||||
|
||||
FileInfo.resize(pos + 1);
|
||||
|
||||
FileInfo[pos].FilePath = (char *) malloc(filepath.size() + strlen(filename) + 2);
|
||||
if (!FileInfo[pos].FilePath) {
|
||||
FileInfo.resize(pos);
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(FileInfo[pos].FilePath, "%s/%s", filepath.c_str(), filename);
|
||||
FileInfo[pos].isDir = isDir;
|
||||
}
|
||||
|
||||
void DirList::ClearList() {
|
||||
for (uint32_t i = 0; i < FileInfo.size(); ++i) {
|
||||
if (FileInfo[i].FilePath) {
|
||||
free(FileInfo[i].FilePath);
|
||||
FileInfo[i].FilePath = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
FileInfo.clear();
|
||||
std::vector<DirEntry>().swap(FileInfo);
|
||||
}
|
||||
|
||||
const char *DirList::GetFilename(int32_t ind) const {
|
||||
if (!valid(ind))
|
||||
return "";
|
||||
|
||||
return StringTools::FullpathToFilename(FileInfo[ind].FilePath);
|
||||
}
|
||||
|
||||
static BOOL SortCallback(const DirEntry &f1, const DirEntry &f2) {
|
||||
if (f1.isDir && !(f2.isDir)) return true;
|
||||
if (!(f1.isDir) && f2.isDir) return false;
|
||||
|
||||
if (f1.FilePath && !f2.FilePath) return true;
|
||||
if (!f1.FilePath) return false;
|
||||
|
||||
if (strcasecmp(f1.FilePath, f2.FilePath) > 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DirList::SortList() {
|
||||
if (FileInfo.size() > 1)
|
||||
std::sort(FileInfo.begin(), FileInfo.end(), SortCallback);
|
||||
}
|
||||
|
||||
void DirList::SortList(BOOL (*SortFunc)(const DirEntry &a, const DirEntry &b)) {
|
||||
if (FileInfo.size() > 1)
|
||||
std::sort(FileInfo.begin(), FileInfo.end(), SortFunc);
|
||||
}
|
||||
|
||||
uint64_t DirList::GetFilesize(int32_t index) const {
|
||||
struct stat st {};
|
||||
const char *path = GetFilepath(index);
|
||||
|
||||
if (!path || stat(path, &st) != 0)
|
||||
return 0;
|
||||
|
||||
return st.st_size;
|
||||
}
|
||||
|
||||
int32_t DirList::GetFileIndex(const char *filename) const {
|
||||
if (!filename)
|
||||
return -1;
|
||||
|
||||
for (int32_t i = 0; i < FileInfo.size(); ++i) {
|
||||
if (strcasecmp(GetFilename(i), filename) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
117
src/fs/DirList.h
117
src/fs/DirList.h
@ -1,117 +0,0 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2010
|
||||
* by Dimok
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any
|
||||
* purpose, including commercial applications, and to alter it and
|
||||
* redistribute it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you
|
||||
* must not claim that you wrote the original software. If you use
|
||||
* this software in a product, an acknowledgment in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and
|
||||
* must not be misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* DirList Class
|
||||
* for WiiXplorer 2010
|
||||
***************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wut_types.h>
|
||||
|
||||
typedef struct {
|
||||
char *FilePath;
|
||||
BOOL isDir;
|
||||
} DirEntry;
|
||||
|
||||
class DirList {
|
||||
public:
|
||||
//!Constructor
|
||||
DirList();
|
||||
|
||||
//!\param path Path from where to load the filelist of all files
|
||||
//!\param filter A fileext that needs to be filtered
|
||||
//!\param flags search/filter flags from the enum
|
||||
explicit DirList(const std::string &path, const char *filter = nullptr, uint32_t flags = Files | Dirs, uint32_t maxDepth = 0xffffffff);
|
||||
|
||||
//!Destructor
|
||||
virtual ~DirList();
|
||||
|
||||
//! Load all the files from a directory
|
||||
BOOL LoadPath(const std::string &path, const char *filter = nullptr, uint32_t flags = Files | Dirs, uint32_t maxDepth = 0xffffffff);
|
||||
|
||||
//! Get a filename of the list
|
||||
//!\param list index
|
||||
[[nodiscard]] const char *GetFilename(int32_t index) const;
|
||||
|
||||
//! Get the a filepath of the list
|
||||
//!\param list index
|
||||
[[nodiscard]] const char *GetFilepath(int32_t index) const {
|
||||
if (!valid(index)) return "";
|
||||
else
|
||||
return FileInfo[index].FilePath;
|
||||
}
|
||||
|
||||
//! Get the a filesize of the list
|
||||
//!\param list index
|
||||
[[nodiscard]] uint64_t GetFilesize(int32_t index) const;
|
||||
|
||||
//! Is index a dir or a file
|
||||
//!\param list index
|
||||
[[nodiscard]] BOOL IsDir(int32_t index) const {
|
||||
if (!valid(index)) return false;
|
||||
return FileInfo[index].isDir;
|
||||
};
|
||||
|
||||
//! Get the filecount of the whole list
|
||||
[[nodiscard]] int32_t GetFilecount() const {
|
||||
return FileInfo.size();
|
||||
};
|
||||
|
||||
//! Sort list by filepath
|
||||
void SortList();
|
||||
|
||||
//! Custom sort command for custom sort functions definitions
|
||||
void SortList(BOOL (*SortFunc)(const DirEntry &a, const DirEntry &b));
|
||||
|
||||
//! Get the index of the specified filename
|
||||
int32_t GetFileIndex(const char *filename) const;
|
||||
|
||||
//! Enum for search/filter flags
|
||||
enum {
|
||||
Files = 0x01,
|
||||
Dirs = 0x02,
|
||||
CheckSubfolders = 0x08,
|
||||
};
|
||||
|
||||
protected:
|
||||
// Internal parser
|
||||
BOOL InternalLoadPath(std::string &path);
|
||||
|
||||
//!Add a list entrie
|
||||
void AddEntrie(const std::string &filepath, const char *filename, BOOL isDir);
|
||||
|
||||
//! Clear the list
|
||||
void ClearList();
|
||||
|
||||
//! Check if valid pos is requested
|
||||
[[nodiscard]] inline BOOL valid(uint32_t pos) const {
|
||||
return (pos < FileInfo.size());
|
||||
};
|
||||
|
||||
uint32_t Flags{};
|
||||
uint32_t Depth{};
|
||||
const char *Filter{};
|
||||
std::vector<DirEntry> FileInfo;
|
||||
};
|
@ -1,145 +0,0 @@
|
||||
#include <fcntl.h>
|
||||
#include <fs/CFile.hpp>
|
||||
#include <fs/FSUtils.h>
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <utils/logger.h>
|
||||
|
||||
int32_t FSUtils::LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size) {
|
||||
//! always initialze input
|
||||
*inbuffer = nullptr;
|
||||
if (size)
|
||||
*size = 0;
|
||||
|
||||
int32_t iFd = open(filepath, O_RDONLY);
|
||||
if (iFd < 0)
|
||||
return -1;
|
||||
|
||||
uint32_t filesize = lseek(iFd, 0, SEEK_END);
|
||||
lseek(iFd, 0, SEEK_SET);
|
||||
|
||||
auto *buffer = (uint8_t *) malloc(filesize);
|
||||
if (buffer == nullptr) {
|
||||
close(iFd);
|
||||
return -2;
|
||||
}
|
||||
|
||||
uint32_t blocksize = 0x4000;
|
||||
uint32_t done = 0;
|
||||
int32_t readBytes = 0;
|
||||
|
||||
while (done < filesize) {
|
||||
if (done + blocksize > filesize) {
|
||||
blocksize = filesize - done;
|
||||
}
|
||||
readBytes = read(iFd, buffer + done, blocksize);
|
||||
if (readBytes <= 0)
|
||||
break;
|
||||
done += readBytes;
|
||||
}
|
||||
|
||||
close(iFd);
|
||||
|
||||
if (done != filesize) {
|
||||
free(buffer);
|
||||
buffer = nullptr;
|
||||
return -3;
|
||||
}
|
||||
|
||||
*inbuffer = buffer;
|
||||
|
||||
//! sign is optional input
|
||||
if (size) {
|
||||
*size = filesize;
|
||||
}
|
||||
|
||||
return filesize;
|
||||
}
|
||||
|
||||
int32_t FSUtils::CheckFile(const char *filepath) {
|
||||
if (!filepath)
|
||||
return 0;
|
||||
|
||||
struct stat filestat {};
|
||||
|
||||
char dirnoslash[strlen(filepath) + 2];
|
||||
snprintf(dirnoslash, sizeof(dirnoslash), "%s", filepath);
|
||||
|
||||
while (dirnoslash[strlen(dirnoslash) - 1] == '/')
|
||||
dirnoslash[strlen(dirnoslash) - 1] = '\0';
|
||||
|
||||
char *notRoot = strrchr(dirnoslash, '/');
|
||||
if (!notRoot) {
|
||||
strcat(dirnoslash, "/");
|
||||
}
|
||||
|
||||
if (stat(dirnoslash, &filestat) == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t FSUtils::CreateSubfolder(const char *fullpath) {
|
||||
if (!fullpath)
|
||||
return 0;
|
||||
|
||||
int32_t result = 0;
|
||||
|
||||
char dirnoslash[strlen(fullpath) + 1];
|
||||
strcpy(dirnoslash, fullpath);
|
||||
|
||||
int32_t pos = strlen(dirnoslash) - 1;
|
||||
while (dirnoslash[pos] == '/') {
|
||||
dirnoslash[pos] = '\0';
|
||||
pos--;
|
||||
}
|
||||
|
||||
if (CheckFile(dirnoslash)) {
|
||||
return 1;
|
||||
} else {
|
||||
char parentpath[strlen(dirnoslash) + 2];
|
||||
strcpy(parentpath, dirnoslash);
|
||||
char *ptr = strrchr(parentpath, '/');
|
||||
|
||||
if (!ptr) {
|
||||
//!Device root directory (must be with '/')
|
||||
strcat(parentpath, "/");
|
||||
struct stat filestat {};
|
||||
if (stat(parentpath, &filestat) == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptr++;
|
||||
ptr[0] = '\0';
|
||||
|
||||
result = CreateSubfolder(parentpath);
|
||||
}
|
||||
|
||||
if (!result)
|
||||
return 0;
|
||||
|
||||
if (mkdir(dirnoslash, 0777) == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
BOOL FSUtils::saveBufferToFile(const char *path, void *buffer, uint32_t size) {
|
||||
CFile file(path, CFile::WriteOnly);
|
||||
if (!file.isOpen()) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to open %s\n", path);
|
||||
return false;
|
||||
}
|
||||
if (file.write((const uint8_t *) buffer, size) != size) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to write file %s\n", path);
|
||||
file.close();
|
||||
return false;
|
||||
}
|
||||
file.close();
|
||||
return true;
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
#ifndef __FS_UTILS_H_
|
||||
#define __FS_UTILS_H_
|
||||
|
||||
#include <wut_types.h>
|
||||
|
||||
class FSUtils {
|
||||
public:
|
||||
static int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size);
|
||||
|
||||
//! todo: C++ class
|
||||
static int32_t CreateSubfolder(const char *fullpath);
|
||||
|
||||
static int32_t CheckFile(const char *filepath);
|
||||
|
||||
static BOOL saveBufferToFile(const char *path, void *buffer, uint32_t size);
|
||||
};
|
||||
|
||||
#endif // __FS_UTILS_H_
|
@ -1,5 +1,5 @@
|
||||
#include "globals.h"
|
||||
|
||||
bool gLibRPXLoaderInitDone __attribute__((section(".data"))) = false;
|
||||
bool gWiiloadServerEnabled __attribute__((section(".data"))) = true;
|
||||
bool gNotificationModuleLoaded __attribute__((section(".data"))) = true;
|
||||
bool gLibRPXLoaderInitDone = false;
|
||||
std::unique_ptr<TcpReceiver> gTcpReceiverThread = nullptr;
|
||||
bool gWiiloadServerEnabled = true;
|
@ -1,5 +1,7 @@
|
||||
#include <stdint.h>
|
||||
#include "utils/TcpReceiver.h"
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
|
||||
extern bool gLibRPXLoaderInitDone;
|
||||
extern std::unique_ptr<TcpReceiver> gTcpReceiverThread;
|
||||
extern bool gWiiloadServerEnabled;
|
||||
extern bool gNotificationModuleLoaded;
|
84
src/main.cpp
84
src/main.cpp
@ -1,7 +1,9 @@
|
||||
#include "main.h"
|
||||
#include "config.h"
|
||||
#include "globals.h"
|
||||
#include "utils/TcpReceiver.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/utils.h"
|
||||
#include <coreinit/debug.h>
|
||||
#include <notifications/notifications.h>
|
||||
#include <rpxloader/rpxloader.h>
|
||||
@ -12,18 +14,11 @@ WUPS_PLUGIN_NAME("Wiiload");
|
||||
WUPS_PLUGIN_DESCRIPTION("Wiiload Server");
|
||||
WUPS_PLUGIN_VERSION(VERSION_FULL);
|
||||
WUPS_PLUGIN_AUTHOR("Maschell");
|
||||
WUPS_PLUGIN_LICENSE("GPL");
|
||||
WUPS_PLUGIN_LICENSE("GPL3");
|
||||
|
||||
WUPS_USE_WUT_DEVOPTAB();
|
||||
|
||||
WUPS_USE_STORAGE("wiiload"); // Unqiue id for the storage api
|
||||
#define WIILOAD_ENABLED_STRING "enabled"
|
||||
|
||||
std::unique_ptr<TcpReceiver> tcpReceiverThread = nullptr;
|
||||
|
||||
|
||||
static WUPSConfigAPICallbackStatus ConfigMenuOpenedCallback(WUPSConfigCategoryHandle rootHandle);
|
||||
static void ConfigMenuClosedCallback();
|
||||
WUPS_USE_STORAGE("wiiload"); // Unique id for the storage api
|
||||
|
||||
INITIALIZE_PLUGIN() {
|
||||
RPXLoaderStatus error;
|
||||
@ -32,77 +27,16 @@ INITIALIZE_PLUGIN() {
|
||||
} else {
|
||||
gLibRPXLoaderInitDone = true;
|
||||
}
|
||||
gTcpReceiverThread.reset();
|
||||
|
||||
NotificationModuleStatus res;
|
||||
if ((res = NotificationModule_InitLibrary()) != NOTIFICATION_MODULE_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to init NotificationModule: %s", NotificationModule_GetStatusStr(res));
|
||||
gNotificationModuleLoaded = false;
|
||||
} else {
|
||||
NotificationModule_SetDefaultValue(NOTIFICATION_MODULE_NOTIFICATION_TYPE_ERROR, NOTIFICATION_MODULE_DEFAULT_OPTION_DURATION_BEFORE_FADE_OUT, 10.0f);
|
||||
gNotificationModuleLoaded = true;
|
||||
}
|
||||
|
||||
WUPSConfigAPIOptionsV1 configOptions = {.name = "Wiiload Plugin"};
|
||||
if (WUPSConfigAPI_Init(configOptions, ConfigMenuOpenedCallback, ConfigMenuClosedCallback) != WUPSCONFIG_API_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to init config api");
|
||||
}
|
||||
|
||||
if (WUPSStorageAPI::GetOrStoreDefault(WIILOAD_ENABLED_STRING, gWiiloadServerEnabled, true) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to get or create item \"%s\"", WIILOAD_ENABLED_STRING);
|
||||
}
|
||||
|
||||
if (WUPSStorageAPI::SaveStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to save storage");
|
||||
}
|
||||
}
|
||||
|
||||
void gServerEnabledChanged(ConfigItemBoolean *item, bool newValue) {
|
||||
if (std::string_view(WIILOAD_ENABLED_STRING) != item->identifier) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Unexpected identifier in bool callback: %s", item->identifier);
|
||||
return;
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("New value in gWiiloadServerEnabled: %d", newValue);
|
||||
gWiiloadServerEnabled = newValue;
|
||||
|
||||
tcpReceiverThread.reset();
|
||||
|
||||
if (gWiiloadServerEnabled) {
|
||||
DEBUG_FUNCTION_LINE("Starting server!");
|
||||
tcpReceiverThread = std::make_unique<TcpReceiver>(4299);
|
||||
|
||||
if (tcpReceiverThread == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to create wiiload thread");
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Wiiload server has been stopped!");
|
||||
}
|
||||
// If the value has changed, we store it in the storage.
|
||||
auto res = WUPSStorageAPI::Store(item->identifier, gWiiloadServerEnabled);
|
||||
if (res != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to store gWiiloadServerEnabled: %s", WUPSStorageAPI_GetStatusStr(res));
|
||||
}
|
||||
}
|
||||
|
||||
static WUPSConfigAPICallbackStatus ConfigMenuOpenedCallback(WUPSConfigCategoryHandle rootHandle) {
|
||||
try {
|
||||
WUPSConfigCategory root = WUPSConfigCategory(rootHandle);
|
||||
|
||||
root.add(WUPSConfigItemBoolean::Create(WIILOAD_ENABLED_STRING, "Enable Wiiload",
|
||||
true, gWiiloadServerEnabled,
|
||||
&gServerEnabledChanged));
|
||||
|
||||
} catch (std::exception &e) {
|
||||
OSReport("Exception T_T : %s\n", e.what());
|
||||
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR;
|
||||
}
|
||||
return WUPSCONFIG_API_CALLBACK_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static void ConfigMenuClosedCallback() {
|
||||
// Save all changes
|
||||
if (WUPSStorageAPI::SaveStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to close storage");
|
||||
}
|
||||
InitConfigAndStorage();
|
||||
}
|
||||
|
||||
/* Entry point */
|
||||
@ -110,8 +44,8 @@ ON_APPLICATION_START() {
|
||||
initLogging();
|
||||
if (gWiiloadServerEnabled) {
|
||||
DEBUG_FUNCTION_LINE("Start wiiload thread");
|
||||
tcpReceiverThread = std::make_unique<TcpReceiver>(4299);
|
||||
if (tcpReceiverThread == nullptr) {
|
||||
gTcpReceiverThread = make_unique_nothrow<TcpReceiver>(4299);
|
||||
if (gTcpReceiverThread == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to create wiiload thread");
|
||||
}
|
||||
} else {
|
||||
@ -120,6 +54,6 @@ ON_APPLICATION_START() {
|
||||
}
|
||||
|
||||
ON_APPLICATION_ENDS() {
|
||||
tcpReceiverThread.reset();
|
||||
gTcpReceiverThread.reset();
|
||||
deinitLogging();
|
||||
}
|
110
src/utils/FSUtils.cpp
Normal file
110
src/utils/FSUtils.cpp
Normal file
@ -0,0 +1,110 @@
|
||||
#include "FSUtils.h"
|
||||
#include "logger.h"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
bool FSUtils::CheckFile(const char *filepath) {
|
||||
if (!filepath || strlen(filepath) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct stat filestat {};
|
||||
|
||||
char dirnoslash[strlen(filepath) + 2];
|
||||
snprintf(dirnoslash, sizeof(dirnoslash), "%s", filepath);
|
||||
|
||||
while (dirnoslash[strlen(dirnoslash) - 1] == '/') {
|
||||
dirnoslash[strlen(dirnoslash) - 1] = '\0';
|
||||
}
|
||||
|
||||
char *notRoot = strrchr(dirnoslash, '/');
|
||||
if (!notRoot) {
|
||||
strcat(dirnoslash, "/");
|
||||
}
|
||||
|
||||
if (stat(dirnoslash, &filestat) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FSUtils::CreateSubfolder(const char *fullpath) {
|
||||
if (!fullpath || strlen(fullpath) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
|
||||
char dirnoslash[strlen(fullpath) + 1];
|
||||
strcpy(dirnoslash, fullpath);
|
||||
|
||||
auto pos = strlen(dirnoslash) - 1;
|
||||
while (dirnoslash[pos] == '/') {
|
||||
dirnoslash[pos] = '\0';
|
||||
pos--;
|
||||
}
|
||||
|
||||
if (CheckFile(dirnoslash)) {
|
||||
return true;
|
||||
} else {
|
||||
char parentpath[strlen(dirnoslash) + 2];
|
||||
strcpy(parentpath, dirnoslash);
|
||||
char *ptr = strrchr(parentpath, '/');
|
||||
|
||||
if (!ptr) {
|
||||
//!Device root directory (must be with '/')
|
||||
strcat(parentpath, "/");
|
||||
struct stat filestat {};
|
||||
if (stat(parentpath, &filestat) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ptr++;
|
||||
ptr[0] = '\0';
|
||||
|
||||
result = CreateSubfolder(parentpath);
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mkdir(dirnoslash, 0777) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FSUtils::saveBufferToFile(const char *path, void *buffer, uint32_t size) {
|
||||
int fd = open(path, O_CREAT | O_TRUNC | O_WRONLY);
|
||||
if (fd < 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to open %s. %d", path, fd);
|
||||
return -1;
|
||||
}
|
||||
auto sizeToWrite = size;
|
||||
auto *ptr = buffer;
|
||||
int32_t curResult;
|
||||
int64_t totalSizeWritten = 0;
|
||||
while (sizeToWrite > 0) {
|
||||
curResult = write(fd, ptr, sizeToWrite);
|
||||
if (curResult < 0) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
if (curResult == 0) {
|
||||
break;
|
||||
}
|
||||
ptr = (void *) (((uint32_t) ptr) + curResult);
|
||||
totalSizeWritten += curResult;
|
||||
sizeToWrite -= curResult;
|
||||
}
|
||||
close(fd);
|
||||
return totalSizeWritten == size;
|
||||
}
|
12
src/utils/FSUtils.h
Normal file
12
src/utils/FSUtils.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <wut_types.h>
|
||||
|
||||
class FSUtils {
|
||||
public:
|
||||
static bool CreateSubfolder(const char *fullpath);
|
||||
|
||||
static bool CheckFile(const char *filepath);
|
||||
|
||||
static bool saveBufferToFile(const char *path, void *buffer, uint32_t size);
|
||||
};
|
@ -1,209 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010
|
||||
* by Dimok
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any
|
||||
* purpose, including commercial applications, and to alter it and
|
||||
* redistribute it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you
|
||||
* must not claim that you wrote the original software. If you use
|
||||
* this software in a product, an acknowledgment in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and
|
||||
* must not be misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* for WiiXplorer 2010
|
||||
***************************************************************************/
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <strings.h>
|
||||
#include <utils/StringTools.h>
|
||||
#include <vector>
|
||||
#include <wchar.h>
|
||||
#include <wut_types.h>
|
||||
|
||||
|
||||
BOOL StringTools::EndsWith(const std::string &a, const std::string &b) {
|
||||
if (b.size() > a.size()) return false;
|
||||
return std::equal(a.begin() + a.size() - b.size(), a.end(), b.begin());
|
||||
}
|
||||
|
||||
const char *StringTools::byte_to_binary(int32_t x) {
|
||||
static char b[9];
|
||||
b[0] = '\0';
|
||||
|
||||
int32_t z;
|
||||
for (z = 128; z > 0; z >>= 1) {
|
||||
strcat(b, ((x & z) == z) ? "1" : "0");
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
std::string StringTools::removeCharFromString(std::string &input, char toBeRemoved) {
|
||||
std::string output = input;
|
||||
size_t position;
|
||||
while (1) {
|
||||
position = output.find(toBeRemoved);
|
||||
if (position == std::string::npos)
|
||||
break;
|
||||
output.erase(position, 1);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
const char *StringTools::fmt(const char *format, ...) {
|
||||
static char strChar[512];
|
||||
strChar[0] = 0;
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if ((vsprintf(strChar, format, va) >= 0)) {
|
||||
va_end(va);
|
||||
return (const char *) strChar;
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const wchar_t *StringTools::wfmt(const char *format, ...) {
|
||||
static char tmp[512];
|
||||
static wchar_t strWChar[512];
|
||||
strWChar[0] = 0;
|
||||
tmp[0] = 0;
|
||||
|
||||
if (!format)
|
||||
return (const wchar_t *) strWChar;
|
||||
|
||||
if (strcmp(format, "") == 0)
|
||||
return (const wchar_t *) strWChar;
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||
int bt;
|
||||
int32_t strlength = strlen(tmp);
|
||||
bt = mbstowcs(strWChar, tmp, (strlength < 512) ? strlength : 512);
|
||||
|
||||
if (bt > 0) {
|
||||
strWChar[bt] = 0;
|
||||
return (const wchar_t *) strWChar;
|
||||
}
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32_t StringTools::strprintf(std::string &str, const char *format, ...) {
|
||||
static char tmp[512];
|
||||
tmp[0] = 0;
|
||||
int32_t result = 0;
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||
str = tmp;
|
||||
result = str.size();
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string StringTools::strfmt(const char *format, ...) {
|
||||
std::string str;
|
||||
static char tmp[512];
|
||||
tmp[0] = 0;
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||
str = tmp;
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
BOOL StringTools::char2wchar_t(const char *strChar, wchar_t *dest) {
|
||||
if (!strChar || !dest)
|
||||
return false;
|
||||
|
||||
int bt;
|
||||
bt = mbstowcs(dest, strChar, strlen(strChar));
|
||||
if (bt > 0) {
|
||||
dest[bt] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t StringTools::strtokcmp(const char *string, const char *compare, const char *separator) {
|
||||
if (!string || !compare)
|
||||
return -1;
|
||||
|
||||
char TokCopy[512];
|
||||
strncpy(TokCopy, compare, sizeof(TokCopy));
|
||||
TokCopy[511] = '\0';
|
||||
|
||||
char *strTok = strtok(TokCopy, separator);
|
||||
|
||||
while (strTok != NULL) {
|
||||
if (strcasecmp(string, strTok) == 0) {
|
||||
return 0;
|
||||
}
|
||||
strTok = strtok(NULL, separator);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t StringTools::strextcmp(const char *string, const char *extension, char seperator) {
|
||||
if (!string || !extension)
|
||||
return -1;
|
||||
|
||||
char *ptr = strrchr(string, seperator);
|
||||
if (!ptr)
|
||||
return -1;
|
||||
|
||||
return strcasecmp(ptr + 1, extension);
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> StringTools::stringSplit(const std::string &inValue, const std::string &splitter) {
|
||||
std::string value = inValue;
|
||||
std::vector<std::string> result;
|
||||
while (true) {
|
||||
uint32_t index = value.find(splitter);
|
||||
if (index == std::string::npos) {
|
||||
result.push_back(value);
|
||||
break;
|
||||
}
|
||||
std::string first = value.substr(0, index);
|
||||
result.push_back(first);
|
||||
if (index + splitter.size() == value.length()) {
|
||||
result.push_back("");
|
||||
break;
|
||||
}
|
||||
if (index + splitter.size() > value.length()) {
|
||||
break;
|
||||
}
|
||||
value = value.substr(index + splitter.size(), value.length());
|
||||
}
|
||||
return result;
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010
|
||||
* by Dimok
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any
|
||||
* purpose, including commercial applications, and to alter it and
|
||||
* redistribute it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you
|
||||
* must not claim that you wrote the original software. If you use
|
||||
* this software in a product, an acknowledgment in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and
|
||||
* must not be misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* for WiiXplorer 2010
|
||||
***************************************************************************/
|
||||
#ifndef __STRING_TOOLS_H
|
||||
#define __STRING_TOOLS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wut_types.h>
|
||||
|
||||
class StringTools {
|
||||
public:
|
||||
static BOOL EndsWith(const std::string &a, const std::string &b);
|
||||
|
||||
static const char *byte_to_binary(int32_t x);
|
||||
|
||||
static std::string removeCharFromString(std::string &input, char toBeRemoved);
|
||||
|
||||
static const char *fmt(const char *format, ...);
|
||||
|
||||
static const wchar_t *wfmt(const char *format, ...);
|
||||
|
||||
static int32_t strprintf(std::string &str, const char *format, ...);
|
||||
|
||||
static std::string strfmt(const char *format, ...);
|
||||
|
||||
static BOOL char2wchar_t(const char *src, wchar_t *dest);
|
||||
|
||||
static int32_t strtokcmp(const char *string, const char *compare, const char *separator);
|
||||
|
||||
static int32_t strextcmp(const char *string, const char *extension, char seperator);
|
||||
|
||||
static const char *FullpathToFilename(const char *path) {
|
||||
if (!path) return path;
|
||||
|
||||
const char *ptr = path;
|
||||
const char *Filename = ptr;
|
||||
|
||||
while (*ptr != '\0') {
|
||||
if (ptr[0] == '/' && ptr[1] != '\0')
|
||||
Filename = ptr + 1;
|
||||
|
||||
++ptr;
|
||||
}
|
||||
|
||||
return Filename;
|
||||
}
|
||||
|
||||
static void RemoveDoubleSlashs(std::string &str) {
|
||||
uint32_t length = str.size();
|
||||
|
||||
//! clear path of double slashes
|
||||
for (uint32_t i = 1; i < length; ++i) {
|
||||
if (str[i - 1] == '/' && str[i] == '/') {
|
||||
str.erase(i, 1);
|
||||
i--;
|
||||
length--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<std::string> stringSplit(const std::string &value, const std::string &splitter);
|
||||
};
|
||||
|
||||
#endif /* __STRING_TOOLS_H */
|
@ -1,5 +1,5 @@
|
||||
#include "TcpReceiver.h"
|
||||
#include "fs/FSUtils.h"
|
||||
#include "FSUtils.h"
|
||||
#include "globals.h"
|
||||
#include "utils/net.h"
|
||||
#include "utils/utils.h"
|
||||
@ -16,7 +16,7 @@
|
||||
#include <wups_backend/PluginUtils.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#define RPX_TEMP_PATH "fs:/vol/external01/wiiu/apps/"
|
||||
#define APPS_TEMP_PATH "fs:/vol/external01/wiiu/apps/"
|
||||
#define RPX_TEMP_FILE "fs:/vol/external01/wiiu/apps/temp.rpx"
|
||||
#define WUHB_TEMP_FILE "fs:/vol/external01/wiiu/apps/temp.wuhb"
|
||||
#define WUHB_TEMP_FILE_2 "fs:/vol/external01/wiiu/apps/temp2.wuhb"
|
||||
@ -52,14 +52,15 @@ bool TcpReceiver::createSocket() {
|
||||
bindAddress.sin_port = serverPort;
|
||||
bindAddress.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
|
||||
int32_t ret;
|
||||
if ((ret = bind(serverSocket, (struct sockaddr *) &bindAddress, 16)) < 0) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Failed to bind socket: %d errno: %d", ret, errno);
|
||||
cleanupSocket();
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((ret = listen(serverSocket, 1)) < 0) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Failed to bind socket: %d errno: %d", ret, errno);
|
||||
cleanupSocket();
|
||||
return false;
|
||||
}
|
||||
@ -86,18 +87,45 @@ void TcpReceiver::executeThread() {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
struct sockaddr_in clientAddr {};
|
||||
memset(&clientAddr, 0, sizeof(clientAddr));
|
||||
|
||||
len = 16;
|
||||
int32_t clientSocket = accept(serverSocket, (struct sockaddr *) &clientAddr, &len);
|
||||
struct sockaddr_in clientAddr = {};
|
||||
len = 16;
|
||||
int32_t clientSocket = accept(serverSocket, (struct sockaddr *) &clientAddr, &len);
|
||||
if (clientSocket >= 0) {
|
||||
uint32_t ipAddress = clientAddr.sin_addr.s_addr;
|
||||
DEBUG_FUNCTION_LINE("Waiting for wiiload connection");
|
||||
int32_t result = loadToMemory(clientSocket, ipAddress);
|
||||
auto result = loadToMemory(clientSocket, ipAddress);
|
||||
close(clientSocket);
|
||||
|
||||
if (result >= 0) {
|
||||
switch (result) {
|
||||
case SUCCESS:
|
||||
break;
|
||||
case FILE_UNCOMPRESS_ERROR:
|
||||
NotificationModule_AddErrorNotification("Wiiload plugin: Failed to decrompress recieved data. Launching will be aborted.");
|
||||
break;
|
||||
case NOT_ENOUGH_MEMORY:
|
||||
NotificationModule_AddErrorNotification("Wiiload plugin: Not enough memory. Launching will be aborted.");
|
||||
break;
|
||||
case RECV_ERROR:
|
||||
NotificationModule_AddErrorNotification("Wiiload plugin: Failed to receive data. Launching will be aborted.");
|
||||
break;
|
||||
case UNSUPPORTED_FORMAT:
|
||||
NotificationModule_AddErrorNotification("Wiiload plugin: Tried to load an unsupported file. Launching will be aborted.");
|
||||
break;
|
||||
case PLUGIN_PARSE_FAILED:
|
||||
NotificationModule_AddErrorNotification("Wiiload plugin: Failed to load plugin. Maybe unsupported version? Launching will be aborted.");
|
||||
break;
|
||||
case PLUGIN_LOAD_LINK_FAILED:
|
||||
NotificationModule_AddErrorNotification("Wiiload plugin: Failed to load plugins. Maybe unsupported version? Launching will be aborted.");
|
||||
break;
|
||||
case FILE_SAVE_BUFFER_ERROR:
|
||||
NotificationModule_AddErrorNotification("Wiiload plugin: Failed to save file to the sd card. Launching will be aborted.");
|
||||
break;
|
||||
case LAUNCH_FAILED:
|
||||
NotificationModule_AddErrorNotification("Wiiload plugin: Failed to launch homebrew. Launching will be aborted.");
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == SUCCESS) {
|
||||
break;
|
||||
}
|
||||
} else if (!exitRequested) {
|
||||
@ -113,26 +141,203 @@ void TcpReceiver::executeThread() {
|
||||
DEBUG_FUNCTION_LINE("Stopping wiiload server.");
|
||||
}
|
||||
|
||||
int32_t TcpReceiver::loadToMemory(int32_t clientSocket, uint32_t ipAddress) {
|
||||
TcpReceiver::eLoadResults TcpReceiver::tryLoadWUHB(void *data, uint32_t fileSize, std::string &loadedPathOut) {
|
||||
if (memcmp(data, "WUHB", 4) == 0) {
|
||||
DEBUG_FUNCTION_LINE("Try to load a .wuhb");
|
||||
if (!FSUtils::CreateSubfolder(APPS_TEMP_PATH)) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Failed to create directory: %s", APPS_TEMP_PATH);
|
||||
return FILE_SAVE_BUFFER_ERROR;
|
||||
}
|
||||
if (FSUtils::saveBufferToFile(WUHB_TEMP_FILE, data, fileSize)) {
|
||||
loadedPathOut = WUHB_TEMP_FILE_EX;
|
||||
} else if (FSUtils::saveBufferToFile(WUHB_TEMP_FILE_2, data, fileSize)) {
|
||||
loadedPathOut = WUHB_TEMP_FILE_2_EX;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_WARN("Failed to save .wuhb file to the sd card. Launching will be aborted.");
|
||||
return FILE_SAVE_BUFFER_ERROR;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Loaded data is not a WUHB");
|
||||
return UNSUPPORTED_FORMAT;
|
||||
}
|
||||
|
||||
TcpReceiver::eLoadResults TcpReceiver::tryLoadRPX(uint8_t *data, uint32_t fileSize, std::string &loadedPathOut) {
|
||||
if (data[0x7] == 0xCA && data[0x8] == 0xFE && data[0x9] != 0x50 && data[0xA] != 0x4C) {
|
||||
DEBUG_FUNCTION_LINE("Try to load a .rpx");
|
||||
if (!FSUtils::CreateSubfolder(APPS_TEMP_PATH)) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Failed to create directory: %s", APPS_TEMP_PATH);
|
||||
return FILE_SAVE_BUFFER_ERROR;
|
||||
}
|
||||
if (FSUtils::saveBufferToFile(RPX_TEMP_FILE, data, fileSize)) {
|
||||
loadedPathOut = RPX_TEMP_FILE_EX;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_WARN("Failed to save .rpx file to the sd card. Launching will be aborted.");
|
||||
return FILE_SAVE_BUFFER_ERROR;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Loaded data is not a RPX");
|
||||
return UNSUPPORTED_FORMAT;
|
||||
}
|
||||
|
||||
TcpReceiver::eLoadResults TcpReceiver::tryLoadWPS(uint8_t *data, uint32_t fileSize) {
|
||||
if (data[0x7] == 0xCA && data[0x8] == 0xFE && data[0x9] == 0x50 && data[0xA] == 0x4C) {
|
||||
auto newContainer = WUPSBackend::PluginUtils::getPluginForBuffer((char *) data, fileSize);
|
||||
if (newContainer) {
|
||||
auto plugins = WUPSBackend::PluginUtils::getLoadedPlugins(32);
|
||||
|
||||
auto &metaInformation = newContainer.value()->getMetaInformation();
|
||||
|
||||
// remove plugins with the same name and author as our new plugin
|
||||
plugins.erase(std::remove_if(plugins.begin(), plugins.end(),
|
||||
[metaInformation](auto &plugin) {
|
||||
return plugin->getMetaInformation()->getName() == metaInformation->getName() &&
|
||||
plugin->getMetaInformation()->getAuthor() == metaInformation->getAuthor();
|
||||
}),
|
||||
plugins.end());
|
||||
|
||||
// add the new plugin
|
||||
plugins.push_back(std::move(newContainer.value()));
|
||||
|
||||
#ifdef VERBOSE_DEBUG
|
||||
for (auto &plugin : plugins) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("name: %s", plugin->getMetaInformation()->getName().c_str());
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("author: %s", plugin->getMetaInformation()->getAuthor().c_str());
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X", plugin->getPluginData()->getHandle());
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("====");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (WUPSBackend::PluginUtils::LoadAndLinkOnRestart(plugins) != 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("WUPSBackend::PluginUtils::LoadAndLinkOnRestart failed");
|
||||
return PLUGIN_LOAD_LINK_FAILED;
|
||||
}
|
||||
return SUCCESS;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to parse plugin for buffer: %08X size %d", data, fileSize);
|
||||
return PLUGIN_PARSE_FAILED;
|
||||
}
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Loaded data is not a plugin");
|
||||
return UNSUPPORTED_FORMAT;
|
||||
}
|
||||
|
||||
TcpReceiver::eLoadResults TcpReceiver::loadBinary(void *data, uint32_t fileSize) {
|
||||
std::string loadedPath;
|
||||
eLoadResults error;
|
||||
if ((error = tryLoadWUHB(data, fileSize, loadedPath)) != UNSUPPORTED_FORMAT || (error = tryLoadRPX((uint8_t *) data, fileSize, loadedPath)) != UNSUPPORTED_FORMAT) {
|
||||
if (error == SUCCESS) {
|
||||
RPXLoaderStatus launchRes;
|
||||
if ((launchRes = RPXLoader_LaunchHomebrew(loadedPath.c_str())) != RPX_LOADER_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to start %s %s", loadedPath.c_str(), RPXLoader_GetStatusStr(launchRes));
|
||||
return LAUNCH_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
} else if ((error = tryLoadWPS((uint8_t *) data, fileSize)) != UNSUPPORTED_FORMAT) {
|
||||
if (error == SUCCESS) {
|
||||
_SYSLaunchTitleWithStdArgsInNoSplash(OSGetTitleID(), nullptr);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
return UNSUPPORTED_FORMAT;
|
||||
}
|
||||
|
||||
TcpReceiver::eLoadResults TcpReceiver::uncompressIfNeeded(const uint8_t *haxx, uint32_t fileSize, uint32_t fileSizeUnc, std::unique_ptr<uint8_t> &&in_data, std::unique_ptr<uint8_t> &out_data, uint32_t &fileSizeOut) {
|
||||
// Do we need to unzip this thing?
|
||||
if (haxx[4] > 0 || haxx[5] > 4) {
|
||||
std::unique_ptr<uint8_t> inflatedData;
|
||||
uint8_t *in_data_raw = in_data.get();
|
||||
// We need to unzip...
|
||||
if (in_data_raw[0] == 'P' && in_data_raw[1] == 'K' && in_data_raw[2] == 0x03 && in_data_raw[3] == 0x04) {
|
||||
// Section is compressed, inflate
|
||||
inflatedData = make_unique_nothrow<uint8_t>(fileSizeUnc);
|
||||
if (!inflatedData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("malloc failed");
|
||||
return NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
int32_t ret;
|
||||
z_stream s = {};
|
||||
|
||||
s.zalloc = Z_NULL;
|
||||
s.zfree = Z_NULL;
|
||||
s.opaque = Z_NULL;
|
||||
|
||||
ret = inflateInit(&s);
|
||||
if (ret != Z_OK) {
|
||||
DEBUG_FUNCTION_LINE_ERR("inflateInit failed %i", ret);
|
||||
return FILE_UNCOMPRESS_ERROR;
|
||||
}
|
||||
|
||||
s.avail_in = fileSize;
|
||||
s.next_in = (Bytef *) inflatedData.get();
|
||||
|
||||
s.avail_out = fileSizeUnc;
|
||||
s.next_out = (Bytef *) inflatedData.get();
|
||||
|
||||
ret = inflate(&s, Z_FINISH);
|
||||
if (ret != Z_OK && ret != Z_STREAM_END) {
|
||||
DEBUG_FUNCTION_LINE_ERR("inflate failed %i", ret);
|
||||
return FILE_UNCOMPRESS_ERROR;
|
||||
}
|
||||
|
||||
inflateEnd(&s);
|
||||
fileSizeOut = fileSizeUnc;
|
||||
out_data = std::move(inflatedData);
|
||||
return SUCCESS;
|
||||
} else {
|
||||
// Section is compressed, inflate
|
||||
inflatedData = make_unique_nothrow<uint8_t>(fileSizeUnc);
|
||||
if (!inflatedData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("malloc failed");
|
||||
return NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
uLongf f = fileSizeUnc;
|
||||
int32_t result = uncompress((Bytef *) inflatedData.get(), &f, (Bytef *) in_data_raw, fileSize);
|
||||
if (result != Z_OK) {
|
||||
DEBUG_FUNCTION_LINE_ERR("uncompress failed %i", result);
|
||||
return FILE_UNCOMPRESS_ERROR;
|
||||
}
|
||||
|
||||
fileSizeUnc = f;
|
||||
fileSizeOut = fileSizeUnc;
|
||||
out_data = std::move(inflatedData);
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
fileSizeOut = fileSize;
|
||||
out_data = std::move(in_data);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
TcpReceiver::eLoadResults TcpReceiver::loadToMemory(int32_t clientSocket, uint32_t ipAddress) {
|
||||
DEBUG_FUNCTION_LINE("Loading file from ip %08X", ipAddress);
|
||||
|
||||
uint32_t fileSize = 0;
|
||||
uint32_t fileSizeUnc = 0;
|
||||
unsigned char haxx[8];
|
||||
memset(haxx, 0, sizeof(haxx));
|
||||
uint32_t fileSize = 0;
|
||||
uint32_t fileSizeUnc = 0;
|
||||
unsigned char haxx[8] = {};
|
||||
//skip haxx
|
||||
recvwait(clientSocket, haxx, sizeof(haxx));
|
||||
recvwait(clientSocket, (unsigned char *) &fileSize, sizeof(fileSize));
|
||||
if (recvwait(clientSocket, haxx, sizeof(haxx)) != 0) {
|
||||
return RECV_ERROR;
|
||||
}
|
||||
if (recvwait(clientSocket, (unsigned char *) &fileSize, sizeof(fileSize)) != 0) {
|
||||
return RECV_ERROR;
|
||||
}
|
||||
|
||||
if (haxx[4] > 0 || haxx[5] > 4) {
|
||||
recvwait(clientSocket, (unsigned char *) &fileSizeUnc, sizeof(fileSizeUnc)); // Compressed protocol, read another 4 bytes
|
||||
if (recvwait(clientSocket, (unsigned char *) &fileSizeUnc, sizeof(fileSizeUnc)) != 0) { // Compressed protocol, read another 4 bytes
|
||||
return RECV_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t bytesRead = 0;
|
||||
|
||||
auto *loadAddress = (unsigned char *) memalign(0x40, fileSize);
|
||||
if (!loadAddress) {
|
||||
OSSleepTicks(OSSecondsToTicks(1));
|
||||
auto receivedData = make_unique_nothrow<uint8_t>(fileSize);
|
||||
if (!receivedData) {
|
||||
return NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
@ -142,7 +347,7 @@ int32_t TcpReceiver::loadToMemory(int32_t clientSocket, uint32_t ipAddress) {
|
||||
if (blockSize > (fileSize - bytesRead))
|
||||
blockSize = fileSize - bytesRead;
|
||||
|
||||
int32_t ret = recv(clientSocket, loadAddress + bytesRead, blockSize, 0);
|
||||
int32_t ret = recv(clientSocket, receivedData.get() + bytesRead, blockSize, 0);
|
||||
if (ret <= 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to receive file");
|
||||
break;
|
||||
@ -152,202 +357,16 @@ int32_t TcpReceiver::loadToMemory(int32_t clientSocket, uint32_t ipAddress) {
|
||||
}
|
||||
|
||||
if (bytesRead != fileSize) {
|
||||
free(loadAddress);
|
||||
DEBUG_FUNCTION_LINE_ERR("File loading not finished, %i of %i bytes received", bytesRead, fileSize);
|
||||
return FILE_READ_ERROR;
|
||||
return RECV_ERROR;
|
||||
}
|
||||
|
||||
bool res = false;
|
||||
bool loadedRPX = false;
|
||||
const char *file_path = nullptr;
|
||||
|
||||
// Do we need to unzip this thing?
|
||||
if (haxx[4] > 0 || haxx[5] > 4) {
|
||||
unsigned char *inflatedData;
|
||||
|
||||
// We need to unzip...
|
||||
if (loadAddress[0] == 'P' && loadAddress[1] == 'K' && loadAddress[2] == 0x03 && loadAddress[3] == 0x04) {
|
||||
//! TODO:
|
||||
//! mhmm this is incorrect, it has to parse the zip
|
||||
|
||||
// Section is compressed, inflate
|
||||
inflatedData = (unsigned char *) malloc(fileSizeUnc);
|
||||
if (!inflatedData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to malloc data");
|
||||
free(loadAddress);
|
||||
|
||||
return NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
int32_t ret = 0;
|
||||
z_stream s;
|
||||
memset(&s, 0, sizeof(s));
|
||||
|
||||
s.zalloc = Z_NULL;
|
||||
s.zfree = Z_NULL;
|
||||
s.opaque = Z_NULL;
|
||||
|
||||
ret = inflateInit(&s);
|
||||
if (ret != Z_OK) {
|
||||
DEBUG_FUNCTION_LINE_ERR("inflateInit failed %i", ret);
|
||||
free(loadAddress);
|
||||
free(inflatedData);
|
||||
|
||||
return FILE_READ_ERROR;
|
||||
}
|
||||
|
||||
s.avail_in = fileSize;
|
||||
s.next_in = (Bytef *) (&loadAddress[0]);
|
||||
|
||||
s.avail_out = fileSizeUnc;
|
||||
s.next_out = (Bytef *) &inflatedData[0];
|
||||
|
||||
ret = inflate(&s, Z_FINISH);
|
||||
if (ret != Z_OK && ret != Z_STREAM_END) {
|
||||
DEBUG_FUNCTION_LINE_ERR("inflate failed %i", ret);
|
||||
free(loadAddress);
|
||||
free(inflatedData);
|
||||
|
||||
return FILE_READ_ERROR;
|
||||
}
|
||||
|
||||
inflateEnd(&s);
|
||||
fileSize = fileSizeUnc;
|
||||
} else {
|
||||
// Section is compressed, inflate
|
||||
inflatedData = (unsigned char *) malloc(fileSizeUnc);
|
||||
if (!inflatedData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("malloc failed");
|
||||
free(loadAddress);
|
||||
|
||||
return NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
uLongf f = fileSizeUnc;
|
||||
int32_t result = uncompress((Bytef *) &inflatedData[0], &f, (Bytef *) loadAddress, fileSize);
|
||||
if (result != Z_OK) {
|
||||
DEBUG_FUNCTION_LINE_ERR("uncompress failed %i", result);
|
||||
return FILE_READ_ERROR;
|
||||
}
|
||||
|
||||
fileSizeUnc = f;
|
||||
fileSize = fileSizeUnc;
|
||||
}
|
||||
|
||||
if (memcmp(inflatedData, "WUHB", 4) == 0) {
|
||||
DEBUG_FUNCTION_LINE("Try to load a .wuhb");
|
||||
FSUtils::CreateSubfolder(RPX_TEMP_PATH);
|
||||
res = FSUtils::saveBufferToFile(WUHB_TEMP_FILE, inflatedData, fileSize);
|
||||
file_path = WUHB_TEMP_FILE_EX;
|
||||
if (!res) {
|
||||
// temp.wuhb might be mounted, let's try temp2.wuhb
|
||||
res = FSUtils::saveBufferToFile(WUHB_TEMP_FILE_2, inflatedData, fileSize);
|
||||
file_path = WUHB_TEMP_FILE_2_EX;
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
NotificationModule_AddErrorNotification("Wiiload plugin: Failed to save .wuhb file to the sd card. Launching will be aborted.");
|
||||
}
|
||||
|
||||
loadedRPX = true;
|
||||
} else if (inflatedData[0x7] == 0xCA && inflatedData[0x8] == 0xFE && inflatedData[0x9] != 0x50 && inflatedData[0xA] != 0x4C) {
|
||||
DEBUG_FUNCTION_LINE("Try to load a .rpx");
|
||||
FSUtils::CreateSubfolder(RPX_TEMP_PATH);
|
||||
res = FSUtils::saveBufferToFile(RPX_TEMP_FILE, inflatedData, fileSize);
|
||||
file_path = RPX_TEMP_FILE_EX;
|
||||
loadedRPX = true;
|
||||
|
||||
if (!res) {
|
||||
NotificationModule_AddErrorNotification("Wiiload plugin: Failed to save .rpx file to the sd card. Launching will be aborted.");
|
||||
}
|
||||
} else if (inflatedData[0x7] == 0xCA && inflatedData[0x8] == 0xFE && inflatedData[0x9] == 0x50 && inflatedData[0xA] == 0x4C) {
|
||||
auto newContainer = WUPSBackend::PluginUtils::getPluginForBuffer((char *) inflatedData, fileSize);
|
||||
if (newContainer) {
|
||||
auto plugins = WUPSBackend::PluginUtils::getLoadedPlugins(32);
|
||||
|
||||
auto &metaInformation = newContainer.value()->getMetaInformation();
|
||||
|
||||
// remove plugins with the same name and author as our new plugin
|
||||
plugins.erase(std::remove_if(plugins.begin(), plugins.end(),
|
||||
[metaInformation](auto &plugin) {
|
||||
return plugin->getMetaInformation()->getName() == metaInformation->getName() &&
|
||||
plugin->getMetaInformation()->getAuthor() == metaInformation->getAuthor();
|
||||
}),
|
||||
plugins.end());
|
||||
|
||||
// add the new plugin
|
||||
plugins.push_back(std::move(newContainer.value()));
|
||||
|
||||
#ifdef VERBOSE_DEBUG
|
||||
for (auto &plugin : plugins) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("name: %s", plugin->getMetaInformation()->getName().c_str());
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("author: %s", plugin->getMetaInformation()->getAuthor().c_str());
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X", plugin->getPluginData()->getHandle());
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("====");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (WUPSBackend::PluginUtils::LoadAndLinkOnRestart(plugins) != 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("WUPSBackend::PluginUtils::LoadAndLinkOnRestart failed");
|
||||
NotificationModule_AddErrorNotification("Wiiload plugin: Failed to load plugin. Launching will be aborted.");
|
||||
}
|
||||
|
||||
free(loadAddress);
|
||||
free(inflatedData);
|
||||
|
||||
_SYSLaunchTitleWithStdArgsInNoSplash(OSGetTitleID(), nullptr);
|
||||
return fileSize;
|
||||
} else {
|
||||
if (NotificationModule_AddErrorNotification("Wiiload plugin: Failed to load or parse the plugin. Launching will be aborted.") != NOTIFICATION_MODULE_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to display error notification");
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to parse plugin");
|
||||
}
|
||||
}
|
||||
free(inflatedData);
|
||||
} else {
|
||||
if (memcmp(loadAddress, "WUHB", 4) == 0) {
|
||||
DEBUG_FUNCTION_LINE("Try to load a .wuhb");
|
||||
FSUtils::CreateSubfolder(RPX_TEMP_PATH);
|
||||
res = FSUtils::saveBufferToFile(WUHB_TEMP_FILE, loadAddress, fileSize);
|
||||
file_path = WUHB_TEMP_FILE_EX;
|
||||
loadedRPX = true;
|
||||
} else if (loadAddress[0x7] == 0xCA && loadAddress[0x8] == 0xFE) {
|
||||
DEBUG_FUNCTION_LINE("Try to load a rpx");
|
||||
FSUtils::CreateSubfolder(RPX_TEMP_PATH);
|
||||
res = FSUtils::saveBufferToFile(RPX_TEMP_FILE, loadAddress, fileSize);
|
||||
file_path = RPX_TEMP_FILE_EX;
|
||||
loadedRPX = true;
|
||||
} else if (loadAddress[0x7] == 0xCA && loadAddress[0x8] == 0xFE && loadAddress[0x9] == 0x50) {
|
||||
OSFatal("Not implemented yet");
|
||||
}
|
||||
if (NotificationModule_AddErrorNotification("Failed to write file to the sd card.") != NOTIFICATION_MODULE_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to display error notification");
|
||||
}
|
||||
std::unique_ptr<uint8_t> finalData;
|
||||
eLoadResults err;
|
||||
if ((err = uncompressIfNeeded(haxx, fileSize, fileSizeUnc, std::move(receivedData), finalData, fileSize)) != SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
free(loadAddress);
|
||||
|
||||
if (!res) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to launch/save a homebrew to the sd card");
|
||||
return NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
if (loadedRPX) {
|
||||
if (!gLibRPXLoaderInitDone) {
|
||||
DEBUG_FUNCTION_LINE_ERR("RPXLoaderModule missing, failed to launch homebrew.");
|
||||
return NOT_SUPPORTED;
|
||||
}
|
||||
RPXLoaderStatus launchRes;
|
||||
if ((launchRes = RPXLoader_LaunchHomebrew(file_path)) != RPX_LOADER_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to start %s %s", file_path, RPXLoader_GetStatusStr(launchRes));
|
||||
return NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
SYSRelaunchTitle(0, nullptr);
|
||||
|
||||
return fileSize;
|
||||
return loadBinary(finalData.get(), fileSize);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -8,13 +9,15 @@
|
||||
class TcpReceiver : public CThread {
|
||||
public:
|
||||
enum eLoadResults {
|
||||
SUCCESS = 0,
|
||||
INVALID_INPUT = -1,
|
||||
FILE_OPEN_FAILURE = -2,
|
||||
FILE_READ_ERROR = -3,
|
||||
NOT_ENOUGH_MEMORY = -4,
|
||||
NOT_A_VALID_PLUGIN = -5,
|
||||
NOT_SUPPORTED = -6,
|
||||
SUCCESS = 0,
|
||||
UNSUPPORTED_FORMAT = -1,
|
||||
PLUGIN_PARSE_FAILED = -2,
|
||||
PLUGIN_LOAD_LINK_FAILED = -3,
|
||||
FILE_SAVE_BUFFER_ERROR = -4,
|
||||
FILE_UNCOMPRESS_ERROR = -5,
|
||||
NOT_ENOUGH_MEMORY = -6,
|
||||
RECV_ERROR = -7,
|
||||
LAUNCH_FAILED = -8,
|
||||
};
|
||||
|
||||
explicit TcpReceiver(int32_t port);
|
||||
@ -27,7 +30,13 @@ private:
|
||||
bool createSocket();
|
||||
void cleanupSocket();
|
||||
|
||||
static int32_t loadToMemory(int32_t clientSocket, uint32_t ipAddress);
|
||||
static eLoadResults loadToMemory(int32_t clientSocket, uint32_t ipAddress);
|
||||
|
||||
static TcpReceiver::eLoadResults tryLoadWUHB(void *data, uint32_t fileSize, std::string &loadedPathOut);
|
||||
static TcpReceiver::eLoadResults tryLoadRPX(uint8_t *data, uint32_t fileSize, std::string &loadedPathOut);
|
||||
static TcpReceiver::eLoadResults tryLoadWPS(uint8_t *data, uint32_t fileSize);
|
||||
static TcpReceiver::eLoadResults loadBinary(void *data, uint32_t fileSize);
|
||||
static TcpReceiver::eLoadResults uncompressIfNeeded(const uint8_t *haxx, uint32_t fileSize, uint32_t fileSizeUnc, std::unique_ptr<uint8_t> &&in_data, std::unique_ptr<uint8_t> &out_data, uint32_t &fileSizeOut);
|
||||
|
||||
bool exitRequested;
|
||||
int32_t serverPort;
|
||||
|
@ -1,37 +0,0 @@
|
||||
#include "utils/logger.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("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("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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,38 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <malloc.h>
|
||||
#include <memory>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#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)
|
||||
|
||||
// those work only in powers of 2
|
||||
#define ROUNDDOWN(val, align) ((val) & ~(align - 1))
|
||||
#define ROUNDUP(val, align) ROUNDDOWN(((val) + (align - 1)), align)
|
||||
|
||||
|
||||
#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<typename T>
|
||||
inline typename std::unique_ptr<T> make_unique_nothrow(size_t num) noexcept {
|
||||
return std::unique_ptr<T>(new (std::nothrow) std::remove_extent_t<T>[num]());
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user