mirror of
https://github.com/wiiu-env/PayloadLoaderInstaller.git
synced 2025-01-28 15:55:26 +01:00
WIP
This commit is contained in:
parent
c5bcadc8c4
commit
1091833da2
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "payload"]
|
||||
path = payload
|
||||
url = https://github.com/wiiu-env/PayloadFromRPX
|
34
Makefile
34
Makefile
@ -19,19 +19,21 @@ include $(DEVKITPRO)/wut/share/wut_rules
|
||||
#-------------------------------------------------------------------------------
|
||||
TARGET := $(notdir $(CURDIR))
|
||||
BUILD := build
|
||||
SOURCES := source
|
||||
SOURCES := source \
|
||||
source/utils \
|
||||
source/fs
|
||||
DATA := data
|
||||
INCLUDES := include
|
||||
INCLUDES := include source
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#-------------------------------------------------------------------------------
|
||||
CFLAGS := -g -Wall -O2 -ffunction-sections \
|
||||
CFLAGS := -g -Wall -O2 -ffunction-sections -fstack-protector-all \
|
||||
$(MACHDEP)
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
|
||||
|
||||
CXXFLAGS := $(CFLAGS)
|
||||
CXXFLAGS := $(CFLAGS) -std=c++17
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map)
|
||||
@ -81,7 +83,7 @@ endif
|
||||
|
||||
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC) safe.rpx.o
|
||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
@ -102,6 +104,7 @@ $(BUILD):
|
||||
#-------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
make clean -C payload
|
||||
@rm -fr $(BUILD) $(TARGET).rpx $(TARGET).elf
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
@ -113,15 +116,36 @@ DEPENDS := $(OFILES:.o=.d)
|
||||
#-------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#-------------------------------------------------------------------------------
|
||||
#-------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
safe_payload := ../payload/safe.rpx
|
||||
|
||||
all : $(OUTPUT).rpx
|
||||
|
||||
$(safe_payload):
|
||||
make -C ../payload
|
||||
|
||||
$(OUTPUT).rpx : $(OUTPUT).elf
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
$(OFILES) : safe_payload.h
|
||||
|
||||
$(OFILES_SRC) : $(HFILES_BIN)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# you need a rule like this for each extension you use as binary data
|
||||
#-------------------------------------------------------------------------------
|
||||
safe_payload.h: $(safe_payload)
|
||||
@bin2s -a 32 -H `(echo $(<F) | tr . _)`.h $< | $(AS) -o $(<F).o
|
||||
@echo '#pragma once' > $@
|
||||
@printf '#include "' >> $@
|
||||
@(printf $(<F) | tr . _) >> $@
|
||||
@echo '.h"' >> $@
|
||||
@printf '#define RPX_HASH "' >> $@
|
||||
@sha1sum $(<) | cut -f1 -d' ' | tr -d '\n' >> $@
|
||||
@printf '"' >> $@
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
%.bin.o %_bin.h : %.bin
|
||||
#-------------------------------------------------------------------------------
|
||||
|
1
payload
Submodule
1
payload
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 4cc24eda59805aa5d9eda6c7af1262966001efec
|
103
source/GameState.cpp
Normal file
103
source/GameState.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
#include "GameState.h"
|
||||
#include "WiiUScreen.h"
|
||||
#include "Input.h"
|
||||
|
||||
void GameState::render() {
|
||||
WiiUScreen::clearScreen();
|
||||
if (this->state == STATE_ERROR) {
|
||||
WiiUScreen::drawLinef("Error: %s", ErrorMessage().c_str());
|
||||
} else if (this->state == STATE_GET_APP_INFORMATION) {
|
||||
WiiUScreen::drawLine("Getting app information");
|
||||
} else if (this->state == STATE_CHECK_PATCH_POSSIBLE) {
|
||||
WiiUScreen::drawLine("Check if console can be patched.");
|
||||
} else if (this->state == STATE_CHECK_PATCH_POSSIBLE_DONE) {
|
||||
if (this->fstPatchPossibe) {
|
||||
WiiUScreen::drawLine("- title.fst can be patched!");
|
||||
} else {
|
||||
WiiUScreen::drawLine("x title.fst can NOT be patched!");
|
||||
}
|
||||
if (this->cosPatchPossibe) {
|
||||
WiiUScreen::drawLine("- cos.xml can be patched!");
|
||||
} else {
|
||||
WiiUScreen::drawLine("x cos.xml can NOT be patched!");
|
||||
}
|
||||
if (this->systemXMLPatchPossibe) {
|
||||
WiiUScreen::drawLine("- system.xml can be patched!");
|
||||
} else {
|
||||
WiiUScreen::drawLine("x system.xml can NOT be patched!");
|
||||
}
|
||||
}
|
||||
WiiUScreen::flipBuffers();
|
||||
}
|
||||
|
||||
Input GameState::getCurrentInput(){
|
||||
|
||||
}
|
||||
|
||||
void GameState::update(Input input) {
|
||||
if (this->state == STATE_ERROR) {
|
||||
handleError();
|
||||
} else if (this->state == STATE_GET_APP_INFORMATION) {
|
||||
getAppInformation();
|
||||
} else if (this->state == STATE_CHECK_PATCH_POSSIBLE) {
|
||||
checkPatchPossible();
|
||||
}
|
||||
}
|
||||
|
||||
GameState::GameState() {
|
||||
this->state = STATE_GET_APP_INFORMATION;
|
||||
DEBUG_FUNCTION_LINE("State has changed to \"STATE_GET_APP_INFORMATION\"");
|
||||
}
|
||||
|
||||
void GameState::checkPatchPossible() {
|
||||
DEBUG_FUNCTION_LINE("Check patch possible");
|
||||
if(!this->appInfo){
|
||||
this->state = STATE_ERROR;
|
||||
this->error = ERROR_NO_APP_INSTALLED;
|
||||
DEBUG_FUNCTION_LINE("ERROR");
|
||||
return;
|
||||
}
|
||||
DEBUG_FUNCTION_LINE("CHECK FST");
|
||||
InstallerService::eResults result;
|
||||
this->fstPatchPossibe = ((result = InstallerService::checkFST(this->appInfo->path, this->appInfo->fstHash)) == InstallerService::SUCCESS);
|
||||
if (result != InstallerService::SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE("ERROR: %s", InstallerService::ErrorMessage(result).c_str());
|
||||
}
|
||||
this->cosPatchPossibe = ((result = InstallerService::checkCOS(this->appInfo->path, this->appInfo->cosHash)) == InstallerService::SUCCESS);
|
||||
if (result != InstallerService::SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE("ERROR: %s", InstallerService::ErrorMessage(result).c_str());
|
||||
}
|
||||
this->systemXMLPatchPossibe = ((result = InstallerService::checkSystemXML("storage_slc_installer:/config", this->appInfo->titleId)) == InstallerService::SUCCESS);
|
||||
if (result != InstallerService::SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE("ERROR: %s", InstallerService::ErrorMessage(result).c_str());
|
||||
}
|
||||
this->state = STATE_CHECK_PATCH_POSSIBLE_DONE;
|
||||
|
||||
}
|
||||
|
||||
void GameState::getAppInformation() {
|
||||
DEBUG_FUNCTION_LINE("About to call getInstalledAppInformation");
|
||||
this->appInfo = InstallerService::getInstalledAppInformation();
|
||||
DEBUG_FUNCTION_LINE("back");
|
||||
if (!this->appInfo) {
|
||||
DEBUG_FUNCTION_LINE("ERROR =(");
|
||||
this->state = STATE_ERROR;
|
||||
this->error = ERROR_NO_APP_INSTALLED;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("WORKED!");
|
||||
this->state = STATE_CHECK_PATCH_POSSIBLE;
|
||||
}
|
||||
}
|
||||
|
||||
std::string GameState::ErrorMessage() {
|
||||
if (this->error == ERROR_NONE) {
|
||||
return "NONE";
|
||||
} else if (this->error == ERROR_NO_APP_INSTALLED) {
|
||||
return "ERROR_NO_APP_INSTALLED";
|
||||
}
|
||||
return "UNKNOWN_ERROR";
|
||||
}
|
||||
|
||||
void GameState::handleError() {
|
||||
|
||||
}
|
46
source/GameState.h
Normal file
46
source/GameState.h
Normal file
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include "common/common.h"
|
||||
#include "InstallerService.h"
|
||||
|
||||
class GameState {
|
||||
|
||||
enum eGameState {
|
||||
STATE_ERROR,
|
||||
STATE_GET_APP_INFORMATION,
|
||||
STATE_CHECK_PATCH_POSSIBLE,
|
||||
STATE_CHECK_PATCH_POSSIBLE_DONE
|
||||
};
|
||||
|
||||
enum eErrorState {
|
||||
ERROR_NONE,
|
||||
ERROR_NO_APP_INSTALLED
|
||||
};
|
||||
|
||||
private:
|
||||
bool fstPatchPossibe = false;
|
||||
bool cosPatchPossibe = false;
|
||||
bool systemXMLPatchPossibe = false;
|
||||
|
||||
eGameState state;
|
||||
eErrorState error = ERROR_NONE;
|
||||
public:
|
||||
GameState();
|
||||
|
||||
void render();
|
||||
|
||||
void update();
|
||||
|
||||
|
||||
void checkPatchPossible();
|
||||
|
||||
void getAppInformation();
|
||||
|
||||
std::optional<appInformation> appInfo;
|
||||
|
||||
std::string ErrorMessage();
|
||||
|
||||
void handleError();
|
||||
};
|
5
source/Input.cpp
Normal file
5
source/Input.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by Maschell on 15.10.2020.
|
||||
//
|
||||
|
||||
#include "Input.h"
|
27
source/Input.h
Normal file
27
source/Input.h
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
|
||||
class Input {
|
||||
public:
|
||||
//!Constructor
|
||||
Input() = default;
|
||||
|
||||
//!Destructor
|
||||
virtual ~Input() = default;
|
||||
|
||||
typedef struct {
|
||||
uint32_t buttons_h;
|
||||
uint32_t buttons_d;
|
||||
uint32_t buttons_r;
|
||||
bool validPointer;
|
||||
bool touched;
|
||||
float pointerAngle;
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
} PadData;
|
||||
|
||||
PadData data{};
|
||||
PadData lastData{};
|
||||
};
|
278
source/InstallerService.cpp
Normal file
278
source/InstallerService.cpp
Normal file
@ -0,0 +1,278 @@
|
||||
#include "common/common.h"
|
||||
#include "utils/logger.h"
|
||||
#include "WiiUScreen.h"
|
||||
#include "StringTools.h"
|
||||
#include "fs/FSUtils.h"
|
||||
#include "common/fst_structs.h"
|
||||
#include "InstallerService.h"
|
||||
#include "utils/utils.h"
|
||||
#include "utils/pugixml.hpp"
|
||||
#include <coreinit/mcp.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <cstdlib>
|
||||
#include <malloc.h>
|
||||
#include <sstream>
|
||||
|
||||
systemXMLInformation systemXMLHashInformation[] = {
|
||||
{WII_U_MENU_JAP, 0x0005001010040000, "2645065A42D18D390C78543E3C4FE7E1D1957A63"},
|
||||
{WII_U_MENU_USA, 0x0005001010040100, "124562D41A02C7112DDD5F9A8F0EE5DF97E23471"},
|
||||
{WII_U_MENU_EUR, 0x0005001010040200, "F06041A4E5B3F899E748F1BAEB524DE058809F1D"},
|
||||
{HEALTH_SAFETY_JAP, 0x000500101004E000, "066D672824128713F0A7D156142A68B998080148"},
|
||||
{HEALTH_SAFETY_USA, 0x000500101004E100, "0EBCA1DFC0AB7A6A7FE8FB5EAF23179621B726A1"},
|
||||
{HEALTH_SAFETY_EUR, 0x000500101004E200, "DE46EC3E9B823ABA6CB0638D0C4CDEEF9C793BDD"}
|
||||
};
|
||||
|
||||
appInformation supportedApps[] = {
|
||||
{0x000500101004E000, "Health and Safety Information [JPN]", false, {'\0'}, "9D34DDD91604D781FDB0727AC75021833304964C", "0"},
|
||||
{0x000500101004E100, "Health and Safety Information [USA]", false, {'\0'}, "045734666A36C7EF0258A740855886EBDB20D59B", "0"},
|
||||
{0x000500101004E200, "Health and Safety Information [EUR]", false, {'\0'}, "130A76F8B36B36D43B88BBC74393D9AFD9CFD2A4", "F6EBF7BC8AE3AF3BB8A42E0CF3FDA051278AEB03"},
|
||||
};
|
||||
|
||||
|
||||
InstallerService::eResults InstallerService::checkCOS(const std::string &path, char *hash) {
|
||||
std::string cosFilePath = path + "/code/cos1.xml";
|
||||
DEBUG_FUNCTION_LINE("Loading %s", cosFilePath.c_str());
|
||||
|
||||
pugi::xml_document doc;
|
||||
pugi::xml_parse_result result = doc.load_file(cosFilePath.c_str());
|
||||
if (!result) {
|
||||
DEBUG_FUNCTION_LINE("failed to open %s : %s", cosFilePath.c_str(), result.description());
|
||||
return COS_XML_PARSING_FAILED;
|
||||
}
|
||||
|
||||
patchCOS(&doc);
|
||||
|
||||
std::stringstream ss;
|
||||
doc.save(ss, " ", pugi::format_default, pugi::encoding_utf8);
|
||||
|
||||
std::string newHash = Utils::calculateSHA1(ss.str().c_str(), ss.str().size());
|
||||
|
||||
if (std::string(hash) == newHash) {
|
||||
DEBUG_FUNCTION_LINE("Success! cos.xml is compatible");
|
||||
return SUCCESS;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Hash mismatch! cos.xml is NOT compatible");
|
||||
}
|
||||
|
||||
return COS_XML_HASH_MISMATCH;
|
||||
}
|
||||
|
||||
InstallerService::eResults InstallerService::checkSystemXML(const std::string &path, uint64_t titleId) {
|
||||
std::string inputFile = std::string(path + "/system.xml");
|
||||
|
||||
systemXMLInformation *data = NULL;
|
||||
int arrayLength = (sizeof(systemXMLHashInformation) / sizeof(*systemXMLHashInformation));
|
||||
for (int i = 0; i < arrayLength; i++) {
|
||||
if (systemXMLHashInformation[i].titleId == titleId) {
|
||||
data = &systemXMLHashInformation[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (data == NULL) {
|
||||
DEBUG_FUNCTION_LINE("system xml information were not found.");
|
||||
return SYSTEM_XML_INFORMATION_NOT_FOUND;
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE("Setting coldboot to %016llX", data->titleId);
|
||||
|
||||
|
||||
pugi::xml_document doc;
|
||||
pugi::xml_parse_result resultSystem = doc.load_file(inputFile.c_str());
|
||||
|
||||
if (!resultSystem) {
|
||||
DEBUG_FUNCTION_LINE("Error while parsing %s: %s", inputFile.c_str(), resultSystem.description());
|
||||
return SYSTEM_XML_PARSING_FAILED;
|
||||
}
|
||||
|
||||
char tmp[18];
|
||||
snprintf(tmp, 17, "%016llX", data->titleId);
|
||||
|
||||
doc.child("system").child("default_title_id").first_child().set_value(tmp);
|
||||
|
||||
std::stringstream ss;
|
||||
doc.save(ss, " ", pugi::format_default, pugi::encoding_utf8);
|
||||
|
||||
std::string newHash = Utils::calculateSHA1(ss.str().c_str(), ss.str().size());
|
||||
|
||||
if (std::string(data->hash) == newHash) {
|
||||
DEBUG_FUNCTION_LINE("Success! system.xml is compatible");
|
||||
return SUCCESS;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Hash mismatch! system.xml is NOT compatible");
|
||||
}
|
||||
return SYSTEM_XML_HASH_MISMATCH;
|
||||
}
|
||||
|
||||
InstallerService::eResults InstallerService::checkFST(const std::string &path, const char *fstHash) {
|
||||
std::string fstFilePath = path + "/code/title.fst";
|
||||
|
||||
uint8_t *fstData = nullptr;
|
||||
uint32_t fstDataSize = 0;
|
||||
|
||||
DEBUG_FUNCTION_LINE("Trying to load FST from %s", fstFilePath.c_str());
|
||||
if (FSUtils::LoadFileToMem(fstFilePath.c_str(), &fstData, &fstDataSize) < 0) {
|
||||
DEBUG_FUNCTION_LINE("Failed to load title.fst");
|
||||
return FAILED_TO_LOAD_FILE;
|
||||
}
|
||||
InstallerService::eResults res = patchFST(fstData, fstDataSize);
|
||||
if (res != SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string newHash = Utils::calculateSHA1((const char *) fstData, fstDataSize);
|
||||
|
||||
if (std::string(fstHash) == newHash) {
|
||||
DEBUG_FUNCTION_LINE("title.fst is compatible");
|
||||
return SUCCESS;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("title.fst is NOT compatible");
|
||||
return FST_HASH_MISMATCH;
|
||||
}
|
||||
}
|
||||
|
||||
bool InstallerService::patchCOS(pugi::xml_document *doc) {
|
||||
pugi::xml_node appEntry = doc->child("app");
|
||||
appEntry.child("argstr").first_child().set_value("safe.rpx");
|
||||
appEntry.child("avail_size").first_child().set_value("00000000");
|
||||
appEntry.child("codegen_size").first_child().set_value("02000000");
|
||||
appEntry.child("codegen_core").first_child().set_value("80000001");
|
||||
appEntry.child("max_size").first_child().set_value("40000000");
|
||||
appEntry.child("max_codesize").first_child().set_value("00800000");
|
||||
for (pugi::xml_node permission: appEntry.child("permissions").children()) {
|
||||
auto mask = permission.child("mask");
|
||||
mask.first_child().set_value("FFFFFFFFFFFFFFFF");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<appInformation> InstallerService::getInstalledAppInformation() {
|
||||
auto mcpHandle = (int32_t) MCP_Open();
|
||||
auto titleCount = (uint32_t) MCP_TitleCount(mcpHandle);
|
||||
auto *titleList = (MCPTitleListType *) memalign(32, sizeof(MCPTitleListType) * titleCount);
|
||||
|
||||
MCP_TitleListByAppType(mcpHandle, MCP_APP_TYPE_SYSTEM_APPS, &titleCount, titleList, sizeof(MCPTitleListType) * titleCount);
|
||||
|
||||
MCP_Close(mcpHandle);
|
||||
|
||||
DEBUG_FUNCTION_LINE("%d titles found on the WiiU", titleCount);
|
||||
bool success = false;
|
||||
|
||||
int arrayLength = (sizeof(supportedApps) / sizeof(*supportedApps));
|
||||
for (uint32_t i = 0; i < titleCount; ++i) {
|
||||
for (int j = 0; j < arrayLength; ++j) {
|
||||
if (titleList[i].titleId == supportedApps[j].titleId) {
|
||||
DEBUG_FUNCTION_LINE("%s is on the Wii U (%s) %d", supportedApps[j].appName, titleList[i].path, sizeof(supportedApps[j].path));
|
||||
supportedApps[j].onTheWiiU = true;
|
||||
strncpy(supportedApps[j].path, titleList[i].path, 255);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(titleList);
|
||||
|
||||
if (success) {
|
||||
success = false;
|
||||
for (int j = 0; j < arrayLength; ++j) {
|
||||
if (supportedApps[j].onTheWiiU) {
|
||||
std::string path(supportedApps[j].path);
|
||||
if (!StringTools::replace(path, "/vol/storage_mlc01", "storage_mlc_installer:")) {
|
||||
DEBUG_FUNCTION_LINE("Title is not on MLC. This is not expected. %s", path.c_str());
|
||||
return {};
|
||||
}
|
||||
strncpy(supportedApps[j].path, path.c_str(), 255);
|
||||
return supportedApps[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
InstallerService::eResults InstallerService::patchFST(uint8_t *fstData, uint32_t size) {
|
||||
auto *fstHeader = (FSTHeader *) fstData;
|
||||
if (strncmp(FSTHEADER_MAGIC, fstHeader->magic, 3) != 0) {
|
||||
DEBUG_FUNCTION_LINE("FST magic is wrong %s", fstHeader->magic);
|
||||
return InstallerService::FST_HEADER_MISMATCH;
|
||||
}
|
||||
|
||||
auto numberOfSections = fstHeader->numberOfSections;
|
||||
DEBUG_FUNCTION_LINE("Found %d sections", numberOfSections);
|
||||
auto *sections = (FSTSectionEntry *) (fstData + sizeof(FSTHeader));
|
||||
|
||||
auto usableSectionIndex = -1;
|
||||
|
||||
for (uint32_t i = 0; i < numberOfSections; i++) {
|
||||
if (sections[i].hashMode == 2) {
|
||||
usableSectionIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (usableSectionIndex < 0) {
|
||||
DEBUG_FUNCTION_LINE("Failed to find suitable section");
|
||||
return InstallerService::FST_NO_USABLE_SECTION_FOUND;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Section %d can be used as a base", usableSectionIndex);
|
||||
}
|
||||
|
||||
auto *rootEntry = (FSTNodeEntry *) (fstData + sizeof(FSTHeader) + numberOfSections * sizeof(FSTSectionEntry));
|
||||
auto numberOfNodeEntries = rootEntry->directory.lastEntryNumber;
|
||||
|
||||
char *stringTableOffset = (char *) ((uint32_t) rootEntry + (sizeof(FSTNodeEntry) * numberOfNodeEntries));
|
||||
|
||||
FSTNodeEntry *nodeEntries = rootEntry;
|
||||
for (uint32_t i = 0; i < numberOfNodeEntries; i++) {
|
||||
if (sections[nodeEntries[i].sectionNumber].hashMode != 2) {
|
||||
auto nameOffset = (*((uint32_t *) nodeEntries[i].nameOffset) & 0xFFFFFF00) >> 8;
|
||||
DEBUG_FUNCTION_LINE("Updating sectionNumber for %s (entry %d)", stringTableOffset + nameOffset, i);
|
||||
nodeEntries[i].sectionNumber = usableSectionIndex;
|
||||
}
|
||||
}
|
||||
return InstallerService::SUCCESS;
|
||||
}
|
||||
|
||||
std::string InstallerService::ErrorMessage(InstallerService::eResults results) {
|
||||
if (results == SUCCESS) {
|
||||
return "Success";
|
||||
} else if (results == NO_COMPATIBLE_APP_INSTALLED) {
|
||||
return "NO_COMPATIBLE_APP_INSTALLED";
|
||||
} else if (results == FAILED_TO_COPY_FILES) {
|
||||
return "FAILED_TO_COPY_FILES";
|
||||
} else if (results == FAILED_TO_CHECK_HASH_COPIED_FILES) {
|
||||
return "FAILED_TO_CHECK_HASH_COPIED_FILES";
|
||||
} else if (results == SYSTEM_XML_INFORMATION_NOT_FOUND) {
|
||||
return "SYSTEM_XML_INFORMATION_NOT_FOUND";
|
||||
} else if (results == SYSTEM_XML_PARSING_FAILED) {
|
||||
return "SYSTEM_XML_PARSING_FAILED";
|
||||
} else if (results == SYSTEM_XML_HASH_MISMATCH_RESTORE_FAILED) {
|
||||
return "SYSTEM_XML_HASH_MISMATCH_RESTORE_FAILED";
|
||||
} else if (results == SYSTEM_XML_HASH_MISMATCH) {
|
||||
return "SYSTEM_XML_HASH_MISMATCH";
|
||||
} else if (results == RPX_HASH_MISMATCH) {
|
||||
return "RPX_HASH_MISMATCH";
|
||||
} else if (results == RPX_HASH_MISMATCH_RESTORE_FAILED) {
|
||||
return "RPX_HASH_MISMATCH_RESTORE_FAILED";
|
||||
} else if (results == COS_XML_PARSING_FAILED) {
|
||||
return "COS_XML_PARSING_FAILED";
|
||||
} else if (results == COS_XML_HASH_MISMATCH) {
|
||||
return "COS_XML_HASH_MISMATCH";
|
||||
} else if (results == COS_XML_HASH_MISMATCH_RESTORE_FAILED) {
|
||||
return "COS_XML_HASH_MISMATCH_RESTORE_FAILED";
|
||||
} else if (results == MALLOC_FAILED) {
|
||||
return "MALLOC_FAILED";
|
||||
} else if (results == FST_HASH_MISMATCH) {
|
||||
return "FST_HASH_MISMATCH";
|
||||
} else if (results == FST_HASH_MISMATCH_RESTORE_FAILED) {
|
||||
return "FST_HASH_MISMATCH_RESTORE_FAILED";
|
||||
} else if (results == FST_HEADER_MISMATCH) {
|
||||
return "FST_HEADER_MISMATCH";
|
||||
} else if (results == FST_NO_USABLE_SECTION_FOUND) {
|
||||
return "FST_NO_USABLE_SECTION_FOUND";
|
||||
} else if (results == FAILED_TO_LOAD_FILE) {
|
||||
return "FAILED_TO_LOAD_FILE";
|
||||
} else {
|
||||
return "UNKNOWN ERROR";
|
||||
}
|
||||
|
||||
}
|
45
source/InstallerService.h
Normal file
45
source/InstallerService.h
Normal file
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/pugixml.hpp"
|
||||
#include "common/common.h"
|
||||
#include <optional>
|
||||
|
||||
class InstallerService {
|
||||
public:
|
||||
enum eResults {
|
||||
SUCCESS = 0,
|
||||
NO_COMPATIBLE_APP_INSTALLED = -1,
|
||||
FAILED_TO_COPY_FILES = -2,
|
||||
FAILED_TO_CHECK_HASH_COPIED_FILES = -3,
|
||||
SYSTEM_XML_INFORMATION_NOT_FOUND = -4,
|
||||
SYSTEM_XML_PARSING_FAILED = -5,
|
||||
SYSTEM_XML_HASH_MISMATCH_RESTORE_FAILED = -6,
|
||||
SYSTEM_XML_HASH_MISMATCH = -7,
|
||||
RPX_HASH_MISMATCH = -8,
|
||||
RPX_HASH_MISMATCH_RESTORE_FAILED = -9,
|
||||
COS_XML_PARSING_FAILED = -10,
|
||||
COS_XML_HASH_MISMATCH = -11,
|
||||
COS_XML_HASH_MISMATCH_RESTORE_FAILED = -12,
|
||||
MALLOC_FAILED = -13,
|
||||
FST_HASH_MISMATCH = -14,
|
||||
FST_HASH_MISMATCH_RESTORE_FAILED = -15,
|
||||
FST_HEADER_MISMATCH = -16,
|
||||
FST_NO_USABLE_SECTION_FOUND = -17,
|
||||
FAILED_TO_LOAD_FILE = -18,
|
||||
};
|
||||
|
||||
static eResults checkCOS(const std::string &path, char *hash);
|
||||
|
||||
static eResults checkSystemXML(const std::string &path, uint64_t titleId);
|
||||
|
||||
static eResults checkFST(const std::string &path, const char *fstHash);
|
||||
|
||||
static std::optional<appInformation> getInstalledAppInformation();
|
||||
|
||||
static std::string ErrorMessage(eResults results);
|
||||
|
||||
private:
|
||||
static eResults patchFST(uint8_t *data, uint32_t size);
|
||||
|
||||
static bool patchCOS(pugi::xml_document *doc);
|
||||
};
|
234
source/StringTools.cpp
Normal file
234
source/StringTools.cpp
Normal file
@ -0,0 +1,234 @@
|
||||
/***************************************************************************
|
||||
* 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 <vector>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include <strings.h>
|
||||
#include <wut_types.h>
|
||||
#include <stdio.h>
|
||||
#include "StringTools.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)) {
|
||||
int32_t 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;
|
||||
|
||||
int32_t 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;
|
||||
}
|
||||
|
||||
bool StringTools::findStringIC(const std::string &strHaystack, const std::string &strNeedle) {
|
||||
auto it = std::search(
|
||||
strHaystack.begin(), strHaystack.end(),
|
||||
strNeedle.begin(), strNeedle.end(),
|
||||
[](char ch1, char ch2) { return std::toupper(ch1) == std::toupper(ch2); }
|
||||
);
|
||||
return (it != strHaystack.end());
|
||||
}
|
||||
|
||||
bool StringTools::replace(std::string &str, const std::string &from, const std::string &to) {
|
||||
size_t start_pos = str.find(from);
|
||||
if (start_pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
str.replace(start_pos, from.length(), to);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool StringTools::strCompareIC(const std::string &str1, const std::string &str2) {
|
||||
return str1.size() == str2.size() && std::equal(str1.begin(), str1.end(), str2.begin(), [](auto a, auto b) { return std::tolower(a) == std::tolower(b); });
|
||||
}
|
95
source/StringTools.h
Normal file
95
source/StringTools.h
Normal file
@ -0,0 +1,95 @@
|
||||
/***************************************************************************
|
||||
* 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
|
||||
***************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <wut_types.h>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
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);
|
||||
|
||||
// https://stackoverflow.com/a/19839371
|
||||
static bool findStringIC(const std::string &strHaystack, const std::string &strNeedle);
|
||||
|
||||
// https://stackoverflow.com/a/3418285
|
||||
static bool replace(std::string& str, const std::string& from, const std::string& to);
|
||||
|
||||
static bool strCompareIC(const std::string &str1, const std::string &str2);
|
||||
};
|
@ -81,7 +81,7 @@ void WiiUScreen::drawLine(const char *msg) {
|
||||
}
|
||||
|
||||
|
||||
void WiiUScreen::flush() {
|
||||
void WiiUScreen::flipBuffers() {
|
||||
ScreenUtils::flipBuffers(CONSOLE_SCREEN_BOTH);
|
||||
}
|
||||
|
||||
|
@ -9,14 +9,19 @@
|
||||
#include <coreinit/memory.h>
|
||||
#include <coreinit/screen.h>
|
||||
#include <proc_ui/procui.h>
|
||||
|
||||
#include <cstring>
|
||||
#include "utils/logger.h"
|
||||
|
||||
#define NUM_LINES (16)
|
||||
#define LINE_LENGTH (128)
|
||||
#define CONSOLE_FRAME_HEAP_TAG (0x000DECAF)
|
||||
#define PRINTF_BUFFER_LENGTH 2048
|
||||
|
||||
#define DEBUG_CONSOLE_LOG(FMT, ARGS...)do { \
|
||||
DEBUG_FUNCTION_LINE(FMT, ## ARGS); \
|
||||
WiiUScreen::drawLinef(FMT, ## ARGS); \
|
||||
} while (0)
|
||||
|
||||
|
||||
class WiiUScreen {
|
||||
|
||||
@ -32,7 +37,7 @@ public:
|
||||
static void drawLinef(const char *fmt, ...);
|
||||
|
||||
static void drawLine(const char *fmt);
|
||||
static void flush();
|
||||
static void flipBuffers();
|
||||
|
||||
static void clearScreen();
|
||||
|
||||
|
37
source/common/common.h
Normal file
37
source/common/common.h
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define VERSION "v0.1"
|
||||
|
||||
enum SYSTEM_XML_DEFAULT_TITLE_ID {
|
||||
WII_U_MENU_EUR,
|
||||
WII_U_MENU_USA,
|
||||
WII_U_MENU_JAP,
|
||||
HEALTH_SAFETY_EUR,
|
||||
HEALTH_SAFETY_USA,
|
||||
HEALTH_SAFETY_JAP
|
||||
};
|
||||
|
||||
typedef struct systemXMLInformation {
|
||||
SYSTEM_XML_DEFAULT_TITLE_ID type;
|
||||
uint64_t titleId;
|
||||
char hash[41];
|
||||
} systemXMLInformation;
|
||||
|
||||
typedef struct compatApps {
|
||||
uint64_t titleId;
|
||||
const char *appName;
|
||||
bool onTheWiiU;
|
||||
char path[255];
|
||||
char fstHash[41];
|
||||
char cosHash[41];
|
||||
} appInformation;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
62
source/common/fst_structs.h
Normal file
62
source/common/fst_structs.h
Normal file
@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include <wut.h>
|
||||
|
||||
#define FSTHEADER_MAGIC "FST"
|
||||
|
||||
typedef struct WUT_PACKED FSTHeader {
|
||||
char magic[3];
|
||||
uint8_t version;
|
||||
uint32_t blockSize;
|
||||
uint32_t numberOfSections;
|
||||
uint8_t hashDisabled;
|
||||
WUT_PADDING_BYTES(32 - 13);
|
||||
} FSTHeader;
|
||||
WUT_CHECK_OFFSET(FSTHeader, 0x00, magic);
|
||||
WUT_CHECK_OFFSET(FSTHeader, 0x03, version);
|
||||
WUT_CHECK_OFFSET(FSTHeader, 0x04, blockSize);
|
||||
WUT_CHECK_OFFSET(FSTHeader, 0x08, numberOfSections);
|
||||
WUT_CHECK_OFFSET(FSTHeader, 0x0C, hashDisabled);
|
||||
WUT_CHECK_SIZE(FSTHeader, 0x20);
|
||||
|
||||
typedef struct WUT_PACKED FSTSectionEntry {
|
||||
uint32_t addressInVolumeBlocks;
|
||||
uint32_t sizeInVolumeBlocks;
|
||||
uint64_t ownerID;
|
||||
uint32_t groupID;
|
||||
uint8_t hashMode;
|
||||
WUT_PADDING_BYTES(32 - 21);
|
||||
} FSTSectionEntry;
|
||||
WUT_CHECK_OFFSET(FSTSectionEntry, 0x00, addressInVolumeBlocks);
|
||||
WUT_CHECK_OFFSET(FSTSectionEntry, 0x04, sizeInVolumeBlocks);
|
||||
WUT_CHECK_OFFSET(FSTSectionEntry, 0x08, ownerID);
|
||||
WUT_CHECK_OFFSET(FSTSectionEntry, 0x10, groupID);
|
||||
WUT_CHECK_OFFSET(FSTSectionEntry, 0x14, hashMode);
|
||||
WUT_CHECK_SIZE(FSTSectionEntry, 0x20);
|
||||
|
||||
typedef struct WUT_PACKED FSTNodeEntry {
|
||||
uint8_t type;
|
||||
char nameOffset[3]; // 24 bit int
|
||||
union {
|
||||
struct {
|
||||
uint32_t parentEntryNumber;
|
||||
uint32_t lastEntryNumber;
|
||||
} directory;
|
||||
struct {
|
||||
uint32_t addressInBlocks;
|
||||
uint32_t size;
|
||||
} file;
|
||||
};
|
||||
uint16_t permission;
|
||||
uint16_t sectionNumber;
|
||||
} FSTNodeEntry;
|
||||
WUT_CHECK_OFFSET(FSTNodeEntry, 0x00, type);
|
||||
WUT_CHECK_OFFSET(FSTNodeEntry, 0x01, nameOffset);
|
||||
WUT_CHECK_OFFSET(FSTNodeEntry, 0x04, directory.parentEntryNumber);
|
||||
WUT_CHECK_OFFSET(FSTNodeEntry, 0x08, directory.lastEntryNumber);
|
||||
WUT_CHECK_OFFSET(FSTNodeEntry, 0x04, file.addressInBlocks);
|
||||
WUT_CHECK_OFFSET(FSTNodeEntry, 0x08, file.size);
|
||||
WUT_CHECK_OFFSET(FSTNodeEntry, 0x0C, permission);
|
||||
WUT_CHECK_OFFSET(FSTNodeEntry, 0x0E, sectionNumber);
|
||||
WUT_CHECK_SIZE(FSTNodeEntry, 0x10);
|
||||
|
173
source/fs/CFile.cpp
Normal file
173
source/fs/CFile.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <strings.h>
|
||||
#include "CFile.hpp"
|
||||
|
||||
CFile::CFile() {
|
||||
iFd = -1;
|
||||
mem_file = NULL;
|
||||
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;
|
||||
}
|
||||
|
||||
int32_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;
|
||||
}
|
||||
|
||||
|
71
source/fs/CFile.hpp
Normal file
71
source/fs/CFile.hpp
Normal file
@ -0,0 +1,71 @@
|
||||
#ifndef CFILE_HPP_
|
||||
#define CFILE_HPP_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#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);
|
||||
|
||||
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);
|
||||
|
||||
int32_t write(const uint8_t *ptr, size_t size);
|
||||
|
||||
int32_t fwrite(const char *format, ...);
|
||||
|
||||
int32_t seek(long int offset, int32_t origin);
|
||||
|
||||
uint64_t tell() {
|
||||
return pos;
|
||||
};
|
||||
|
||||
uint64_t size() {
|
||||
return filesize;
|
||||
};
|
||||
|
||||
void rewind() {
|
||||
this->seek(0, SEEK_SET);
|
||||
};
|
||||
|
||||
protected:
|
||||
int32_t iFd;
|
||||
const uint8_t *mem_file;
|
||||
uint64_t filesize;
|
||||
uint64_t pos;
|
||||
};
|
||||
|
||||
#endif
|
174
source/fs/FSUtils.cpp
Normal file
174
source/fs/FSUtils.cpp
Normal file
@ -0,0 +1,174 @@
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include "FSUtils.h"
|
||||
#include "CFile.hpp"
|
||||
#include "utils/logger.h"
|
||||
|
||||
int32_t FSUtils::LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size) {
|
||||
//! always initialze input
|
||||
*inbuffer = NULL;
|
||||
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);
|
||||
|
||||
uint8_t *buffer = (uint8_t *) malloc(filesize);
|
||||
if (buffer == NULL) {
|
||||
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 = NULL;
|
||||
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::copyFile(const std::string &in, const std::string &out) {
|
||||
// Using C++ buffers is **really** slow. Copying in 1023 byte chunks.
|
||||
// Let's do it the old way.
|
||||
size_t size;
|
||||
|
||||
int source = open(in.c_str(), O_RDONLY, 0);
|
||||
int dest = open(out.c_str(), 0x602, 0644);
|
||||
if (source < 0) {
|
||||
return false;
|
||||
}
|
||||
if (dest < 0) {
|
||||
close(source);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto bufferSize = 1024 * 1024;
|
||||
char *buf = (char *) malloc(bufferSize);
|
||||
if (buf == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((size = read(source, buf, bufferSize)) > 0) {
|
||||
write(dest, buf, size);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
close(source);
|
||||
close(dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t FSUtils::saveBufferToFile(const char *path, void *buffer, uint32_t size) {
|
||||
CFile file(path, CFile::WriteOnly);
|
||||
if (!file.isOpen()) {
|
||||
return -1;
|
||||
}
|
||||
int32_t written = file.write((const uint8_t *) buffer, size);
|
||||
file.close();
|
||||
return written;
|
||||
}
|
||||
|
17
source/fs/FSUtils.h
Normal file
17
source/fs/FSUtils.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <wut_types.h>
|
||||
#include <string>
|
||||
|
||||
class FSUtils {
|
||||
public:
|
||||
static int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size);
|
||||
|
||||
static int32_t CreateSubfolder(const char *fullpath);
|
||||
|
||||
static int32_t CheckFile(const char *filepath);
|
||||
|
||||
static bool copyFile(const std::string &in, const std::string &out);
|
||||
|
||||
static int32_t saveBufferToFile(const char *path, void *buffer, uint32_t size);
|
||||
};
|
@ -1,60 +1,47 @@
|
||||
#include <coreinit/thread.h>
|
||||
#include <coreinit/time.h>
|
||||
#include <coreinit/debug.h>
|
||||
#include <nn/ac.h>
|
||||
|
||||
#include <whb/proc.h>
|
||||
#include <whb/log.h>
|
||||
#include <whb/log_udp.h>
|
||||
|
||||
#include <iosuhax.h>
|
||||
#include <iosuhax_devoptab.h>
|
||||
#include <string_view>
|
||||
#include "WiiUScreen.h"
|
||||
#include "logger.h"
|
||||
#include "utils/logger.h"
|
||||
#include "InstallerService.h"
|
||||
|
||||
#include "../build/safe_payload.h"
|
||||
#include "GameState.h"
|
||||
|
||||
constexpr bool strings_equal(char const *a, char const *b) {
|
||||
return std::string_view(a) == b;
|
||||
}
|
||||
|
||||
static_assert(strings_equal(RPX_HASH, "6ce36d8838cab58a0f90f381119b12aca009974b"), "Built with an untested safe.rpx! Remove this check if you really know what you're doing.");
|
||||
|
||||
void initIOSUHax();
|
||||
|
||||
void deInitIOSUHax();
|
||||
|
||||
int
|
||||
hello_thread() {
|
||||
int last_tm_sec = -1;
|
||||
uint32_t ip = 0;
|
||||
|
||||
WHBLogPrintf("Hello!");
|
||||
|
||||
if (!nn::ac::GetAssignedAddress(&ip)) {
|
||||
WHBLogPrintf("GetAssignedAddress failed!");
|
||||
}
|
||||
|
||||
WHBLogPrintf("My IP is: %u.%u.%u.%u",
|
||||
(ip >> 24) & 0xFF,
|
||||
(ip >> 16) & 0xFF,
|
||||
(ip >> 8) & 0xFF,
|
||||
(ip >> 0) & 0xFF);
|
||||
int hello_thread() {
|
||||
DEBUG_FUNCTION_LINE("Creating state");
|
||||
GameState state;
|
||||
|
||||
DEBUG_FUNCTION_LINE("Entering main loop");
|
||||
while (WHBProcIsRunning()) {
|
||||
OSCalendarTime tm;
|
||||
OSTicksToCalendarTime(OSGetTime(), &tm);
|
||||
|
||||
if (tm.tm_sec != last_tm_sec) {
|
||||
WiiUScreen::clearScreen();
|
||||
WiiUScreen::drawLine("Hello World from a std::thread!");
|
||||
WiiUScreen::drawLinef("%02d/%02d/%04d %02d:%02d:%02d I'm still here.",
|
||||
tm.tm_mday, tm.tm_mon + 1, tm.tm_year,
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
last_tm_sec = tm.tm_sec;
|
||||
WiiUScreen::flush();
|
||||
}
|
||||
|
||||
OSSleepTicks(OSMillisecondsToTicks(100));
|
||||
state.update();
|
||||
state.render();
|
||||
}
|
||||
|
||||
WHBLogPrintf("Exiting... good bye.");
|
||||
OSSleepTicks(OSMillisecondsToTicks(1000));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
WHBLogUdpInit();
|
||||
DEBUG_FUNCTION_LINE("Hello from Aroma Installer!");
|
||||
WHBProcInit();
|
||||
WiiUScreen::Init();
|
||||
|
||||
@ -75,7 +62,6 @@ bool sIosuhaxMount = false;
|
||||
|
||||
void initIOSUHax() {
|
||||
sIosuhaxMount = false;
|
||||
auto fsaFd = -1;
|
||||
int res = IOSUHAX_Open(nullptr);
|
||||
if (res < 0) {
|
||||
DEBUG_FUNCTION_LINE("IOSUHAX_open failed");
|
||||
@ -83,11 +69,11 @@ void initIOSUHax() {
|
||||
} else {
|
||||
sIosuhaxMount = true;
|
||||
sFSAFd = IOSUHAX_FSA_Open();
|
||||
if (fsaFd < 0) {
|
||||
if (sFSAFd < 0) {
|
||||
DEBUG_FUNCTION_LINE("IOSUHAX_FSA_Open failed");
|
||||
} else {
|
||||
mount_fs("storage_slc_installer", fsaFd, nullptr, "/vol/system");
|
||||
mount_fs("storage_mlc_installer", fsaFd, nullptr, "/vol/storage_mlc01");
|
||||
mount_fs("storage_slc_installer", sFSAFd, nullptr, "/vol/system");
|
||||
mount_fs("storage_mlc_installer", sFSAFd, nullptr, "/vol/storage_mlc01");
|
||||
}
|
||||
DEBUG_FUNCTION_LINE("IOSUHAX done");
|
||||
}
|
||||
|
196
source/utils/TinySHA1.hpp
Normal file
196
source/utils/TinySHA1.hpp
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
*
|
||||
* TinySHA1 - a header only implementation of the SHA1 algorithm in C++. Based
|
||||
* on the implementation in boost::uuid::details.
|
||||
*
|
||||
* SHA1 Wikipedia Page: http://en.wikipedia.org/wiki/SHA-1
|
||||
*
|
||||
* Copyright (c) 2012-22 SAURAV MOHAPATRA <mohaps@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#ifndef _TINY_SHA1_HPP_
|
||||
#define _TINY_SHA1_HPP_
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <stdint.h>
|
||||
namespace sha1
|
||||
{
|
||||
class SHA1
|
||||
{
|
||||
public:
|
||||
typedef uint32_t digest32_t[5];
|
||||
typedef uint8_t digest8_t[20];
|
||||
inline static uint32_t LeftRotate(uint32_t value, size_t count) {
|
||||
return (value << count) ^ (value >> (32-count));
|
||||
}
|
||||
SHA1(){ reset(); }
|
||||
virtual ~SHA1() {}
|
||||
SHA1(const SHA1& s) { *this = s; }
|
||||
const SHA1& operator = (const SHA1& s) {
|
||||
memcpy(m_digest, s.m_digest, 5 * sizeof(uint32_t));
|
||||
memcpy(m_block, s.m_block, 64);
|
||||
m_blockByteIndex = s.m_blockByteIndex;
|
||||
m_byteCount = s.m_byteCount;
|
||||
return *this;
|
||||
}
|
||||
SHA1& reset() {
|
||||
m_digest[0] = 0x67452301;
|
||||
m_digest[1] = 0xEFCDAB89;
|
||||
m_digest[2] = 0x98BADCFE;
|
||||
m_digest[3] = 0x10325476;
|
||||
m_digest[4] = 0xC3D2E1F0;
|
||||
m_blockByteIndex = 0;
|
||||
m_byteCount = 0;
|
||||
return *this;
|
||||
}
|
||||
SHA1& processByte(uint8_t octet) {
|
||||
this->m_block[this->m_blockByteIndex++] = octet;
|
||||
++this->m_byteCount;
|
||||
if(m_blockByteIndex == 64) {
|
||||
this->m_blockByteIndex = 0;
|
||||
processBlock();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
SHA1& processBlock(const void* const start, const void* const end) {
|
||||
const uint8_t* begin = static_cast<const uint8_t*>(start);
|
||||
const uint8_t* finish = static_cast<const uint8_t*>(end);
|
||||
while(begin != finish) {
|
||||
processByte(*begin);
|
||||
begin++;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
SHA1& processBytes(const void* const data, size_t len) {
|
||||
const uint8_t* block = static_cast<const uint8_t*>(data);
|
||||
processBlock(block, block + len);
|
||||
return *this;
|
||||
}
|
||||
const uint32_t* getDigest(digest32_t digest) {
|
||||
size_t bitCount = this->m_byteCount * 8;
|
||||
processByte(0x80);
|
||||
if (this->m_blockByteIndex > 56) {
|
||||
while (m_blockByteIndex != 0) {
|
||||
processByte(0);
|
||||
}
|
||||
while (m_blockByteIndex < 56) {
|
||||
processByte(0);
|
||||
}
|
||||
} else {
|
||||
while (m_blockByteIndex < 56) {
|
||||
processByte(0);
|
||||
}
|
||||
}
|
||||
processByte(0);
|
||||
processByte(0);
|
||||
processByte(0);
|
||||
processByte(0);
|
||||
processByte( static_cast<unsigned char>((bitCount>>24) & 0xFF));
|
||||
processByte( static_cast<unsigned char>((bitCount>>16) & 0xFF));
|
||||
processByte( static_cast<unsigned char>((bitCount>>8 ) & 0xFF));
|
||||
processByte( static_cast<unsigned char>((bitCount) & 0xFF));
|
||||
|
||||
memcpy(digest, m_digest, 5 * sizeof(uint32_t));
|
||||
return digest;
|
||||
}
|
||||
const uint8_t* getDigestBytes(digest8_t digest) {
|
||||
digest32_t d32;
|
||||
getDigest(d32);
|
||||
size_t di = 0;
|
||||
digest[di++] = ((d32[0] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[0] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[0] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[0]) & 0xFF);
|
||||
|
||||
digest[di++] = ((d32[1] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[1] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[1] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[1]) & 0xFF);
|
||||
|
||||
digest[di++] = ((d32[2] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[2] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[2] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[2]) & 0xFF);
|
||||
|
||||
digest[di++] = ((d32[3] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[3] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[3] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[3]) & 0xFF);
|
||||
|
||||
digest[di++] = ((d32[4] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[4] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[4] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[4]) & 0xFF);
|
||||
return digest;
|
||||
}
|
||||
|
||||
protected:
|
||||
void processBlock() {
|
||||
uint32_t w[80];
|
||||
for (size_t i = 0; i < 16; i++) {
|
||||
w[i] = (m_block[i*4 + 0] << 24);
|
||||
w[i] |= (m_block[i*4 + 1] << 16);
|
||||
w[i] |= (m_block[i*4 + 2] << 8);
|
||||
w[i] |= (m_block[i*4 + 3]);
|
||||
}
|
||||
for (size_t i = 16; i < 80; i++) {
|
||||
w[i] = LeftRotate((w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]), 1);
|
||||
}
|
||||
|
||||
uint32_t a = m_digest[0];
|
||||
uint32_t b = m_digest[1];
|
||||
uint32_t c = m_digest[2];
|
||||
uint32_t d = m_digest[3];
|
||||
uint32_t e = m_digest[4];
|
||||
|
||||
for (std::size_t i=0; i<80; ++i) {
|
||||
uint32_t f = 0;
|
||||
uint32_t k = 0;
|
||||
|
||||
if (i<20) {
|
||||
f = (b & c) | (~b & d);
|
||||
k = 0x5A827999;
|
||||
} else if (i<40) {
|
||||
f = b ^ c ^ d;
|
||||
k = 0x6ED9EBA1;
|
||||
} else if (i<60) {
|
||||
f = (b & c) | (b & d) | (c & d);
|
||||
k = 0x8F1BBCDC;
|
||||
} else {
|
||||
f = b ^ c ^ d;
|
||||
k = 0xCA62C1D6;
|
||||
}
|
||||
uint32_t temp = LeftRotate(a, 5) + f + e + k + w[i];
|
||||
e = d;
|
||||
d = c;
|
||||
c = LeftRotate(b, 30);
|
||||
b = a;
|
||||
a = temp;
|
||||
}
|
||||
|
||||
m_digest[0] += a;
|
||||
m_digest[1] += b;
|
||||
m_digest[2] += c;
|
||||
m_digest[3] += d;
|
||||
m_digest[4] += e;
|
||||
}
|
||||
private:
|
||||
digest32_t m_digest;
|
||||
uint8_t m_block[64];
|
||||
size_t m_blockByteIndex;
|
||||
size_t m_byteCount;
|
||||
};
|
||||
}
|
||||
#endif
|
@ -1,23 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <whb/log.h>
|
||||
|
||||
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE(FMT, ARGS...)do { \
|
||||
WHBLogPrintf("[%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \
|
||||
} while (0);
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...)do { \
|
||||
WHBLogWritef("[%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \
|
||||
} while (0);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
#include <whb/log.h>
|
||||
|
||||
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE(FMT, ARGS...)do { \
|
||||
WHBLogPrintf("[%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \
|
||||
} while (0);
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...)do { \
|
||||
WHBLogWritef("[%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \
|
||||
} while (0);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
74
source/utils/pugiconfig.hpp
Normal file
74
source/utils/pugiconfig.hpp
Normal file
@ -0,0 +1,74 @@
|
||||
/**
|
||||
* pugixml parser - version 1.10
|
||||
* --------------------------------------------------------
|
||||
* Copyright (C) 2006-2019, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
|
||||
* Report bugs and download new versions at https://pugixml.org/
|
||||
*
|
||||
* This library is distributed under the MIT License. See notice at the end
|
||||
* of this file.
|
||||
*
|
||||
* This work is based on the pugxml parser, which is:
|
||||
* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
|
||||
*/
|
||||
|
||||
#ifndef HEADER_PUGICONFIG_HPP
|
||||
#define HEADER_PUGICONFIG_HPP
|
||||
|
||||
// Uncomment this to enable wchar_t mode
|
||||
// #define PUGIXML_WCHAR_MODE
|
||||
|
||||
// Uncomment this to enable compact mode
|
||||
// #define PUGIXML_COMPACT
|
||||
|
||||
// Uncomment this to disable XPath
|
||||
// #define PUGIXML_NO_XPATH
|
||||
|
||||
// Uncomment this to disable STL
|
||||
// #define PUGIXML_NO_STL
|
||||
|
||||
// Uncomment this to disable exceptions
|
||||
#define PUGIXML_NO_EXCEPTIONS
|
||||
|
||||
// Set this to control attributes for public classes/functions, i.e.:
|
||||
// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL
|
||||
// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL
|
||||
// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall
|
||||
// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead
|
||||
|
||||
// Tune these constants to adjust memory-related behavior
|
||||
// #define PUGIXML_MEMORY_PAGE_SIZE 32768
|
||||
// #define PUGIXML_MEMORY_OUTPUT_STACK 10240
|
||||
// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096
|
||||
|
||||
// Uncomment this to switch to header-only version
|
||||
// #define PUGIXML_HEADER_ONLY
|
||||
|
||||
// Uncomment this to enable long long support
|
||||
// #define PUGIXML_HAS_LONG_LONG
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Copyright (c) 2006-2019 Arseny Kapoulkine
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
12865
source/utils/pugixml.cpp
Normal file
12865
source/utils/pugixml.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1477
source/utils/pugixml.hpp
Normal file
1477
source/utils/pugixml.hpp
Normal file
File diff suppressed because it is too large
Load Diff
64
source/utils/utils.cpp
Normal file
64
source/utils/utils.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <whb/log.h>
|
||||
#include <fs/FSUtils.h>
|
||||
#include "logger.h"
|
||||
#include "utils.h"
|
||||
#include "TinySHA1.hpp"
|
||||
|
||||
// https://gist.github.com/ccbrown/9722406
|
||||
void Utils::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string Utils::calculateSHA1(const char *buffer, size_t size) {
|
||||
sha1::SHA1 s;
|
||||
s.processBytes(buffer, size);
|
||||
uint32_t digest[5];
|
||||
s.getDigest(digest);
|
||||
char tmp[48];
|
||||
snprintf(tmp, 45, "%08X%08X%08X%08X%08X", digest[0], digest[1], digest[2], digest[3], digest[4]);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
std::string Utils::hashFile(const std::string &path) {
|
||||
uint8_t *data = NULL;
|
||||
uint32_t size = 0;
|
||||
FSUtils::LoadFileToMem(path.c_str(), &data, &size);
|
||||
if (data == NULL) {
|
||||
return calculateSHA1(NULL, 0);
|
||||
}
|
||||
std::string result = calculateSHA1(reinterpret_cast<const char *>(data), size);
|
||||
free(data);
|
||||
return result;
|
||||
}
|
45
source/utils/utils.h
Normal file
45
source/utils/utils.h
Normal file
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include <malloc.h>
|
||||
#include <string>
|
||||
|
||||
#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)))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
class Utils {
|
||||
public:
|
||||
static void dumpHex(const void *data, size_t size);
|
||||
|
||||
static std::string calculateSHA1(const char *buffer, size_t size);
|
||||
|
||||
static std::string hashFile(const std::string &path);
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user