This commit is contained in:
Maschell 2020-10-15 20:14:00 +02:00
parent c5bcadc8c4
commit 1091833da2
27 changed files with 16175 additions and 68 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "payload"]
path = payload
url = https://github.com/wiiu-env/PayloadFromRPX

View File

@ -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

@ -0,0 +1 @@
Subproject commit 4cc24eda59805aa5d9eda6c7af1262966001efec

103
source/GameState.cpp Normal file
View 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
View 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
View File

@ -0,0 +1,5 @@
//
// Created by Maschell on 15.10.2020.
//
#include "Input.h"

27
source/Input.h Normal file
View 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
View 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
View 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
View 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
View 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);
};

View File

@ -81,7 +81,7 @@ void WiiUScreen::drawLine(const char *msg) {
}
void WiiUScreen::flush() {
void WiiUScreen::flipBuffers() {
ScreenUtils::flipBuffers(CONSOLE_SCREEN_BOTH);
}

View File

@ -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
View 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

View 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
View 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
View 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
View 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
View 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);
};

View File

@ -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
View 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

View File

@ -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

View 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

File diff suppressed because it is too large Load Diff

1477
source/utils/pugixml.hpp Normal file

File diff suppressed because it is too large Load Diff

64
source/utils/utils.cpp Normal file
View 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
View 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);
};