First commit

This commit is contained in:
Maschell 2021-10-09 00:58:55 +02:00
commit 648c0d0fd7
106 changed files with 6857 additions and 0 deletions

66
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,66 @@
name: CI-Release
on:
push:
branches:
- main
jobs:
build-binary:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Checkout submodules using a PAT
run: |
git config --file .gitmodules --get-regexp url | while read url; do
git config --file=.gitmodules $(echo "$url" | sed -E "s/git@github.com:|https:\/\/github.com\//https:\/\/${{ secrets.CI_PAT }}:${{ secrets.CI_PAT }}@github.com\//")
done
git submodule sync
git submodule update --init --recursive
- name: build binary
run: |
docker build . -t builder
docker run --rm -v ${PWD}:/project builder make
- uses: actions/upload-artifact@master
with:
name: binary
path: "*.rpx"
deploy-binary:
needs: build-binary
runs-on: ubuntu-18.04
steps:
- name: Get environment variables
id: get_repository_name
run: |
echo REPOSITORY_NAME=$(echo "$GITHUB_REPOSITORY" | awk -F / '{print $2}' | sed -e "s/:refs//") >> $GITHUB_ENV
echo DATETIME=$(echo $(date '+%Y%m%d-%H%M%S')) >> $GITHUB_ENV
- uses: actions/download-artifact@master
with:
name: binary
path: wiiu
- name: zip artifact
run: zip -r ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip wiiu
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
release_name: Nightly-${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
draft: false
prerelease: true
body: |
Not a stable release:
${{ github.event.head_commit.message }}
- name: Upload Release Asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: ./${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip
asset_name: ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip
asset_content_type: application/unknown

24
.github/workflows/pr.yml vendored Normal file
View File

@ -0,0 +1,24 @@
name: CI-PR
on: [pull_request]
jobs:
build-binary:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Checkout submodules using a PAT
run: |
git config --file .gitmodules --get-regexp url | while read url; do
git config --file=.gitmodules $(echo "$url" | sed -E "s/git@github.com:|https:\/\/github.com\//https:\/\/${{ secrets.CI_PAT }}:${{ secrets.CI_PAT }}@github.com\//")
done
git submodule sync
git submodule update --init --recursive
- name: build binary
run: |
docker build . -t builder
docker run --rm -v ${PWD}:/project builder make
- uses: actions/upload-artifact@master
with:
name: binary
path: "*.rpx"

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
CMakeLists.txt
.idea/
build/
cmake-build-debug/
*.elf
*.rpx

6
Dockerfile Normal file
View File

@ -0,0 +1,6 @@
FROM wiiuenv/devkitppc:20210920
COPY --from=wiiuenv/libiosuhax:20211008 /artifacts $DEVKITPRO
COPY --from=wiiuenv/libntfs:20201210 /artifacts $DEVKITPRO
WORKDIR project

152
Makefile Normal file
View File

@ -0,0 +1,152 @@
#-------------------------------------------------------------------------------
.SUFFIXES:
#-------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
endif
TOPDIR ?= $(CURDIR)
include $(DEVKITPRO)/wut/share/wut_rules
#-------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
#-------------------------------------------------------------------------------
TARGET := wudump
BUILD := build
SOURCES := source \
source/fs \
source/input \
source/common \
source/utils \
source/utils/blocksize \
source/WUD \
source/WUD/content \
source/WUD/content/partitions \
source/WUD/content/partitions/volumes \
source/WUD/header \
source/WUD/entities/FST \
source/WUD/entities/FST/header \
source/WUD/entities/FST/nodeentry \
source/WUD/entities/FST/sectionentry \
source/WUD/entities/FST/stringtable \
source/WUD/entities/TMD
DATA := data
INCLUDES := include source
#-------------------------------------------------------------------------------
# options for code generation
#-------------------------------------------------------------------------------
CFLAGS := -g -Wall -O2 -ffunction-sections \
$(MACHDEP)
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
CXXFLAGS := $(CFLAGS) -std=gnu++20
ASFLAGS := -g $(ARCH)
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map)
LIBS := -lwut -lntfs -liosuhax
#-------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level
# containing include and lib
#-------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUT_ROOT)/usr
#-------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#-------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#-------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#-------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#-------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#-------------------------------------------------------------------------------
export LD := $(CC)
#-------------------------------------------------------------------------------
else
#-------------------------------------------------------------------------------
export LD := $(CXX)
#-------------------------------------------------------------------------------
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 HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean all
#-------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#-------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).rpx $(TARGET).elf
#-------------------------------------------------------------------------------
else
.PHONY: all
DEPENDS := $(OFILES:.o=.d)
#-------------------------------------------------------------------------------
# main targets
#-------------------------------------------------------------------------------
all : $(OUTPUT).rpx
$(OUTPUT).rpx : $(OUTPUT).elf
$(OUTPUT).elf : $(OFILES)
$(OFILES_SRC) : $(HFILES_BIN)
#-------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#-------------------------------------------------------------------------------
%.bin.o %_bin.h : %.bin
#-------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#-------------------------------------------------------------------------------
endif
#-------------------------------------------------------------------------------

27
README.md Normal file
View File

@ -0,0 +1,27 @@
# Wudump
RPX version of [wudump](https://github.com/FIX94/wudump).
Supports dumping as [WUX](https://gbatemp.net/threads/wii-u-image-wud-compression-tool.397901/) and WUD, but only to NTFS formatted USB drives and without dumping the `game.key`.
## Dependencies
- [wut](https://github.com/decaf-emu/wut)
- [libiosuhax](https://github.com/wiiu-env/libiosuhax)
- [libfat](https://github.com/wiiu-env/libfat)
- [libntfs](https://github.com/wiiu-env/libntfs)
## Building using the Dockerfile
It's possible to use a docker image for building. This way you don't need anything installed on your host system.
```
# Build docker image (only needed once)
docker build . -t wudump-builder
# make
docker run -it --rm -v ${PWD}:/project wudump-builder make
# make clean
docker run -it --rm -v ${PWD}:/project wudump-builder make clean
```

861
source/ApplicationState.cpp Normal file
View File

@ -0,0 +1,861 @@
#include "ApplicationState.h"
#include "utils/WiiUScreen.h"
#include "utils/ScreenUtils.h"
#include "common/common.h"
#include "utils/utils.h"
#include "utils/StringTools.h"
#include "utils/rijndael.h"
#include "fs/FSUtils.h"
#include <sysapp/launch.h>
#include <coreinit/ios.h>
#include <iosuhax.h>
#include <malloc.h>
#include <coreinit/memdefaultheap.h>
#include <cstdarg>
#include <ntfs.h>
#include <WUD/DiscReaderDiscDrive.h>
#include <whb/proc.h>
#include <coreinit/debug.h>
#include <WUD/content/partitions/WiiUGMPartition.h>
#include <WUD/header/WiiUDiscHeader.h>
#include <WUD/entities/TMD/Content.h>
#include <WUD/entities/TMD/TitleMetaData.h>
#include <WUD/NUSDataProviderWUD.h>
#include <WUD/NUSTitle.h>
extern ntfs_md *ntfs_mounts;
extern int ntfs_mount_count;
unsigned int swap_uint32(unsigned int val) {
val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF);
return (val << 16) | (val >> 16);
}
unsigned long long swap_uint64(unsigned long long val) {
val = ((val << 8) & 0xFF00FF00FF00FF00ULL) | ((val >> 8) & 0x00FF00FF00FF00FFULL);
val = ((val << 16) & 0xFFFF0000FFFF0000ULL) | ((val >> 16) & 0x0000FFFF0000FFFFULL);
return (val << 32) | (val >> 32);
}
/*
* Hash function used to create a hash of each sector
* The hashes are then compared to find duplicate sectors
*/
void calculateHash256(unsigned char *data, unsigned int length, unsigned char *hashOut) {
// cheap and simple hash implementation
// you can replace this part with your favorite hash method
memset(hashOut, 0x00, 32);
for (unsigned int i = 0; i < length; i++) {
hashOut[i % 32] ^= data[i];
hashOut[(i + 7) % 32] += data[i];
}
}
ApplicationState::ApplicationState() : log("fs:/vol/external01/wudump.log", CFile::WriteOnly) {
this->log.fwrite("Started wudump\n");
this->state = STATE_WELCOME_SCREEN;
}
void ApplicationState::printHeader() {
WiiUScreen::drawLine("Wudump");
WiiUScreen::drawLine("==================");
WiiUScreen::drawLine("");
}
void ApplicationState::render() {
WiiUScreen::clearScreen();
if (this->state == STATE_ERROR) {
WiiUScreen::drawLine();
WiiUScreen::drawLinef("Error: %s", ErrorMessage().c_str());
WiiUScreen::drawLinef("Description: %s", ErrorDescription().c_str());
WiiUScreen::drawLine();
WiiUScreen::drawLine("Press A to return to the Wii U Menu.");
} else if (this->state == STATE_WELCOME_SCREEN) {
WiiUScreen::drawLine("Welcome to Wudump");
WiiUScreen::drawLine("Press A to dump the currently inserted Disc");
WiiUScreen::drawLine("");
if (this->selectedOption == 0) {
WiiUScreen::drawLine("> Dump as WUX Dump as WUD Dump as .app Exit");
} else if (this->selectedOption == 1) {
WiiUScreen::drawLine(" Dump as WUX > Dump as WUD Dump as .app Exit");
} else if (this->selectedOption == 2) {
WiiUScreen::drawLine(" Dump as WUX Dump as WUD > Dump as .app Exit");
} else if (this->selectedOption == 3) {
WiiUScreen::drawLine(" Dump as WUX Dump as WUD Dump as .app > Exit");
}
} else if (this->state == STATE_CHOOSE_TARGET) {
printHeader();
WiiUScreen::drawLine("Please choose your target:");
std::vector<std::string> options;
int32_t targetCount = 0;
if (this->dumpFormat == DUMP_AS_APP) {
options.emplace_back("SD");
targetCount++;
}
for (int i = 0; i < ntfs_mount_count; i++) {
options.emplace_back(ntfs_mounts[i].name);
targetCount++;
}
std::string curLine = "";
if (this->selectedOption == 0) {
curLine = "> Back\t";
} else {
curLine = " Back\t";
}
if (targetCount == 0) {
WiiUScreen::drawLine("Please insert a NTFS formatted USB drive and restart wudump\n");
} else {
for (int32_t i = 0; i < targetCount; i++) {
if (this->selectedOption - 1 == i) {
curLine += "> " + options[i];
} else {
curLine += " " + options[i];
}
curLine += "\t";
}
}
WiiUScreen::drawLine(curLine.c_str());
} else if (this->state == STATE_OPEN_ODD1) {
WiiUScreen::drawLine("Open /dev/odd01");
} else if (this->state == STATE_READ_DISC_INFO) {
WiiUScreen::drawLine("Read disc information");
} else if (this->state == STATE_READ_DISC_INFO_DONE) {
WiiUScreen::drawLinef("Dumping: %s", this->discId);
} else if (this->state == STATE_DUMP_TICKET) {
WiiUScreen::drawLinef("Dumping game.key");
} else if (this->state == STATE_DUMP_DISC_START || this->state == STATE_DUMP_DISC || this->state == STATE_WAIT_USER_ERROR_CONFIRM) {
WiiUScreen::drawLinef("Dumping: %s", this->discId);
float percent = this->currentSector / (WUD_FILE_SIZE / READ_SECTOR_SIZE * 1.0f) * 100.0f;
WiiUScreen::drawLinef("Progress: %0.2f MiB / %5.2f MiB (%2.1f %%)", this->currentSector * (READ_SECTOR_SIZE / 1024.0f / 1024.0f), WUD_FILE_SIZE / 1024.0f / 1024.0f, percent);
if (doWUX) {
WiiUScreen::drawLinef("Written %0.2f MiB. Compression ratio 1:%0.2f", this->hashMap.size() * (READ_SECTOR_SIZE / 1024.0f / 1024.0f),
1.0f / (this->hashMap.size() / (float) this->currentSector));
}
if (this->readResult < 0 || this->oddFd < 0) {
WiiUScreen::drawLine();
if (this->oddFd < 0) {
WiiUScreen::drawLine("Failed to open disc, try again.");
} else {
WiiUScreen::drawLinef("Error: Failed to read sector - Error %d", this->readResult);
}
WiiUScreen::drawLine();
WiiUScreen::drawLine("Press A to skip this sector (will be replaced by 0's)");
WiiUScreen::drawLine("Press B to try again");
} else {
OSTime curTime = OSGetTime();
float remaining = (WUD_FILE_SIZE - (READ_SECTOR_SIZE * this->currentSector)) / 1024.0f / 1024.0f;
float curSpeed = READ_SECTOR_SIZE * ((this->readSectors / 1000.0f) / OSTicksToMilliseconds(curTime - startTime));
int32_t remainingSec = remaining / curSpeed;
int32_t minutes = (remainingSec / 60) % 60;
int32_t seconds = remainingSec % 60;
int32_t hours = remainingSec / 3600;
WiiUScreen::drawLinef("Speed: %.2f MiB/s ETA: %02dh %02dm %02ds", curSpeed, remaining, hours, minutes, seconds);
}
WiiUScreen::drawLine();
if (!this->skippedSectors.empty()) {
WiiUScreen::drawLinef("Skipped dumping %d sectors", this->skippedSectors.size());
}
} else if (this->state == STATE_DUMP_DISC_DONE) {
if (!flushWriteCache()) {
setError(ERROR_WRITE_FAILED);
}
WiiUScreen::drawLinef("Dumping done! Press A to continue");
} else if (this->state == STATE_DUMP_APP_FILES_DONE) {
WiiUScreen::drawLinef("Dumping done! Press A to continue");
}
printFooter();
WiiUScreen::flipBuffers();
}
void ApplicationState::update(Input *input) {
if (this->state == STATE_ERROR) {
OSEnableHomeButtonMenu(true);
if (entrySelected(input)) {
SYSLaunchMenu();
}
} else if (this->state == STATE_WELCOME_SCREEN) {
proccessMenuNavigation(input, 4);
if (entrySelected(input)) {
if (this->selectedOption == 0) {
this->retryCount = 10;
this->state = STATE_CHOOSE_TARGET;
this->dumpFormat = DUMP_AS_WUX;
} else if (this->selectedOption == 1) {
this->retryCount = 10;
this->state = STATE_CHOOSE_TARGET;
this->dumpFormat = DUMP_AS_WUD;
} else if (this->selectedOption == 2) {
this->retryCount = 10;
this->state = STATE_CHOOSE_TARGET;
this->dumpFormat = DUMP_AS_APP;
} else {
SYSLaunchMenu();
}
this->selectedOption = 0;
return;
}
} else if (this->state == STATE_CHOOSE_TARGET) {
WiiUScreen::drawLine("Please choose your target");
std::vector<std::string> options;
uint32_t targetCount = 0;
if (this->dumpFormat == DUMP_AS_APP) {
options.emplace_back("fs:/vol/external01/");
targetCount++;
}
if (ntfs_mount_count > 0) {
for (int i = 0; i < ntfs_mount_count; i++) {
options.emplace_back(std::string(ntfs_mounts[i].name) + ":/");
targetCount++;
}
}
proccessMenuNavigation(input, targetCount + 1);
if (entrySelected(input)) {
if (this->selectedOption == 0) {
this->state = STATE_WELCOME_SCREEN;
} else if (targetCount > 0) {
target = options[selectedOption - 1];
this->state = STATE_OPEN_ODD1;
}
this->selectedOption = 0;
}
} else if (this->state == STATE_OPEN_ODD1) {
if (this->readSectors > 0) {
auto ret = IOSUHAX_FSA_RawOpen(gFSAfd, "/dev/odd01", &(this->oddFd));
if (ret >= 0) {
// continue!
this->state = STATE_DUMP_DISC;
} else {
this->oddFd = -1;
this->state = STATE_WAIT_USER_ERROR_CONFIRM;
}
return;
}
DEBUG_FUNCTION_LINE("STATE_OPEN_ODD1");
if (this->retryCount-- <= 0) {
this->setError(ERROR_OPEN_ODD1);
return;
}
auto ret = IOSUHAX_FSA_RawOpen(gFSAfd, "/dev/odd01", &(this->oddFd));
if (ret >= 0) {
if (this->sectorBuf == nullptr) {
this->sectorBuf = (void *) memalign(0x100, this->sectorBufSize);
if (this->sectorBuf == nullptr) {
this->setError(ERROR_MALLOC_FAILED);
return;
}
}
DEBUG_FUNCTION_LINE("Opened /dev/odd01 %d", this->oddFd);
this->state = STATE_READ_DISC_INFO;
}
} else if (this->state == STATE_READ_DISC_INFO) {
DEBUG_FUNCTION_LINE("STATE_READ_DISC_INFO");
if (IOSUHAX_FSA_RawRead(gFSAfd, this->sectorBuf, READ_SECTOR_SIZE, 1, 0, this->oddFd) >= 0) {
this->discId[10] = '\0';
memcpy(this->discId, sectorBuf, 10);
if (this->discId[0] == 0) {
setError(ERROR_NO_DISC_ID);
return;
}
this->state = STATE_READ_DISC_INFO_DONE;
return;
}
this->setError(ERROR_READ_FIRST_SECTOR);
return;
} else if (this->state == STATE_READ_DISC_INFO_DONE) {
DEBUG_FUNCTION_LINE("STATE_READ_DISC_INFO_DONE");
this->state = STATE_DUMP_TICKET;
} else if (this->state == STATE_DUMP_TICKET) {
DEBUG_FUNCTION_LINE("STATE_DUMP_TICKET");
auto res = IOSUHAX_FSA_RawRead(gFSAfd, this->sectorBuf, READ_SECTOR_SIZE, 1, 3, this->oddFd);
uint8_t discKey[16];
bool hasDiscKey = false;
if (res >= 0) {
if (((uint32_t *) this->sectorBuf)[0] != 0xCCA6E67B) {
uint8_t iv[16];
memset(iv, 0, 16);
auto odm_handle = IOS_Open("/dev/odm", IOS_OPEN_READ);
if (odm_handle >= 0) {
uint32_t io_buffer[0x20 / 4];
// disc encryption key, only works with patched IOSU
io_buffer[0] = 3;
if (IOS_Ioctl(odm_handle, 0x06, io_buffer, 0x14, io_buffer, 0x20) == 0) {
memcpy(discKey, io_buffer, 16);
hasDiscKey = true;
}
IOS_Close(odm_handle);
}
}
}
if (hasDiscKey) {
if (!FSUtils::CreateSubfolder(StringTools::fmt("%swudump/%s", target.c_str(), discId))) {
setError(ERROR_WRITE_FAILED);
return;
}
if (!FSUtils::saveBufferToFile(StringTools::fmt("%swudump/%s/game.key", target.c_str(), discId), discKey, 16)) {
setError(ERROR_WRITE_FAILED);
return;
}
}
if (this->dumpFormat == DUMP_AS_WUX || this->dumpFormat == DUMP_AS_WUD) {
if (this->dumpFormat == DUMP_AS_WUX) {
this->doWUX = true;
}
this->state = STATE_DUMP_DISC_START;
} else {
this->state = STATE_DUMP_APP_FILES;
}
} else if (this->state == STATE_DUMP_APP_FILES) {
ApplicationState::dumpAppFiles();
if (this->state != STATE_ERROR) {
this->state = STATE_DUMP_APP_FILES_DONE;
}
} else if (this->state == STATE_DUMP_APP_FILES_DONE) {
if (entrySelected(input)) {
this->state = STATE_WELCOME_SCREEN;
if (this->oddFd >= 0) {
IOSUHAX_FSA_RawClose(gFSAfd, this->oddFd);
this->oddFd = -1;
}
this->currentSector = 0;
this->readSectors = 0;
}
} else if (this->state == STATE_DUMP_DISC_START) {
ApplicationState::clearWriteCache();
DEBUG_FUNCTION_LINE("STATE_DUMP_DISC_START");
if (!FSUtils::CreateSubfolder(StringTools::fmt("%swudump/%s", target.c_str(), discId))) {
setError(ERROR_WRITE_FAILED);
return;
}
this->fileHandle = new CFile(StringTools::fmt("%swudump/%s/game.%s", target.c_str(), discId, doWUX ? "wux" : "wud"), CFile::WriteOnly);
this->totalSectorCount = WUD_FILE_SIZE / SECTOR_SIZE;
if (!this->fileHandle->isOpen()) {
DEBUG_FUNCTION_LINE("Failed to open file");
this->setError(ERROR_FILE_OPEN_FAILED);
return;
}
if (doWUX) {
wuxHeader_t wuxHeader = {0};
wuxHeader.magic0 = WUX_MAGIC_0;
wuxHeader.magic1 = WUX_MAGIC_1;
wuxHeader.sectorSize = swap_uint32(SECTOR_SIZE);
wuxHeader.uncompressedSize = swap_uint64(WUD_FILE_SIZE);
wuxHeader.flags = 0;
DEBUG_FUNCTION_LINE("Write header");
this->fileHandle->write((uint8_t *) &wuxHeader, sizeof(wuxHeader_t));
this->sectorTableStart = this->fileHandle->tell();
this->sectorIndexTable = (void *) malloc(totalSectorCount * 4);
if (sectorIndexTable == nullptr) {
this->setError(ERROR_MALLOC_FAILED);
return;
}
memset(this->sectorIndexTable, 0, totalSectorCount * 4);
DEBUG_FUNCTION_LINE("Write empty sectorIndexTable");
this->fileHandle->write((uint8_t *) this->sectorIndexTable, totalSectorCount * 4);
DEBUG_FUNCTION_LINE("Get sector table end");
this->sectorTableEnd = this->fileHandle->tell();
uint64_t tableEnd = this->sectorTableEnd;
this->sectorTableEnd += SECTOR_SIZE - 1;
this->sectorTableEnd -= (this->sectorTableEnd % SECTOR_SIZE);
uint64_t padding = this->sectorTableEnd - tableEnd;
auto *paddingData = (uint8_t *) malloc(padding);
memset(paddingData, 0, padding);
this->fileHandle->write(reinterpret_cast<const uint8_t *>(paddingData), padding);
free(paddingData);
this->hashMap.clear();
}
this->writeBufferSize = READ_SECTOR_SIZE * WRITE_BUFFER_NUM_SECTORS;
this->writeBuffer = (void *) memalign(0x1000, this->writeBufferSize);
if (this->writeBuffer == nullptr) {
this->setError(ERROR_MALLOC_FAILED);
return;
}
this->writeBufferPos = 0;
this->startTime = OSGetTime();
this->state = STATE_DUMP_DISC;
this->currentSector = 0;
this->retryCount = 10;
this->selectedOption = 0;
this->readSectors = 0;
} else if (this->state == STATE_DUMP_DISC) {
//DEBUG_FUNCTION_LINE("STATE_DUMP_DISC");
int32_t numSectors = this->currentSector + READ_NUM_SECTORS > this->totalSectorCount ? this->totalSectorCount - this->currentSector : READ_NUM_SECTORS;
if ((this->readResult = IOSUHAX_FSA_RawRead(gFSAfd, sectorBuf, READ_SECTOR_SIZE, numSectors, this->currentSector, this->oddFd)) >= 0) {
if (!writeDataToFile(this->sectorBuf, numSectors)) {
this->setError(ERROR_WRITE_FAILED);
return;
}
//DEBUG_FUNCTION_LINE("Read done %lld %lld", this->currentSector, this->totalSectorCount);
this->retryCount = 10;
if (this->currentSector >= this->totalSectorCount) {
this->state = STATE_DUMP_DISC_DONE;
if (this->fileHandle->isOpen()) {
if (!this->flushWriteCache()) {
this->setError(ERROR_WRITE_FAILED);
return;
}
if (doWUX) {
this->writeSectorIndexTable();
}
this->fileHandle->close();
}
}
} else {
this->state = STATE_WAIT_USER_ERROR_CONFIRM;
if (this->oddFd >= 0) {
IOSUHAX_FSA_RawClose(gFSAfd, this->oddFd);
this->oddFd = -1;
}
return;
}
} else if (this->state == STATE_WAIT_USER_ERROR_CONFIRM) {
if (this->autoSkip) {
if (this->oddFd >= 0) {
IOSUHAX_FSA_RawClose(gFSAfd, this->oddFd);
this->oddFd = -1;
}
}
if (this->autoSkip || (input->data.buttons_d & Input::BUTTON_A)) {
this->log.fwrite("Skipped sector %d : 0x%ll016X-0x%ll016X, filled with 0's\n", this->currentSector, this->currentSector * READ_SECTOR_SIZE, (this->currentSector + 1) * READ_SECTOR_SIZE);
this->state = STATE_OPEN_ODD1;
this->skippedSectors.push_back(this->currentSector);
// We can't use seek because we may have cached values.
if (this->emptySector == nullptr) {
this->emptySector = memalign(0x100, READ_SECTOR_SIZE);
if (this->emptySector == nullptr) {
this->setError(ERROR_MALLOC_FAILED);
return;
}
}
if (!this->writeCached(reinterpret_cast<uint32_t>(emptySector), READ_SECTOR_SIZE)) {
this->setError(ERROR_WRITE_FAILED);
return;
}
this->currentSector += 1;
this->readResult = 0;
} else if (input->data.buttons_d & Input::BUTTON_B) {
this->state = STATE_OPEN_ODD1;
this->readResult = 0;
} else if (input->data.buttons_d & Input::BUTTON_Y) {
this->autoSkip = true;
}
} else if (this->state == STATE_DUMP_DISC_DONE) {
if (entrySelected(input)) {
if (this->oddFd >= 0) {
IOSUHAX_FSA_RawClose(gFSAfd, this->oddFd);
this->oddFd = -1;
}
this->state = STATE_WELCOME_SCREEN;
this->selectedOption = 0;
this->currentSector = 0;
this->readSectors = 0;
this->writtenSector = 0;
return;
}
}
}
std::string ApplicationState::ErrorMessage() {
if (this->error == ERROR_NONE) {
return "NONE";
} else if (this->error == ERROR_IOSUHAX_FAILED) {
return "ERROR_IOSUHAX_FAILED";
} else if (this->error == ERROR_MALLOC_FAILED) {
return "ERROR_MALLOC_FAILED";
} else if (this->error == ERROR_FILE_OPEN_FAILED) {
return "ERROR_FILE_OPEN_FAILED";
} else if (this->error == ERROR_NO_DISC_ID) {
return "ERROR_NO_DISC_ID";
}
DEBUG_FUNCTION_LINE("Error: %d", this->error);
return "UNKNOWN_ERROR";
}
std::string ApplicationState::ErrorDescription() {
if (this->error == ERROR_NONE) {
return "-";
} else if (this->error == ERROR_IOSUHAX_FAILED) {
return "Failed to init IOSUHAX.";
} else if (this->error == ERROR_MALLOC_FAILED) {
return "Failed to allocate data.";
} else if (this->error == ERROR_FILE_OPEN_FAILED) {
return "Failed to create file";
} else if (this->error == ERROR_NO_DISC_ID) {
return "Failed to get the disc id";
}
DEBUG_FUNCTION_LINE("Error: %d", this->error);
return "UNKNOWN_ERROR";
}
void ApplicationState::setError(eErrorState err) {
this->state = STATE_ERROR;
this->error = err;
//OSEnableHomeButtonMenu(true);
}
void ApplicationState::printFooter() {
ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_TV, 0, 27, "By Maschell");
ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_DRC, 0, 17, "By Maschell");
}
void ApplicationState::proccessMenuNavigation(Input *input, int maxOptionValue) {
if (input->data.buttons_d & Input::BUTTON_LEFT) {
this->selectedOption--;
} else if (input->data.buttons_d & Input::BUTTON_RIGHT) {
this->selectedOption++;
}
if (this->selectedOption < 0) {
this->selectedOption = maxOptionValue;
} else if (this->selectedOption >= maxOptionValue) {
this->selectedOption = 0;
}
}
bool ApplicationState::entrySelected(Input *input) {
return input->data.buttons_d & Input::BUTTON_A;
}
ApplicationState::~ApplicationState() {
this->log.close();
if (this->fileHandle->isOpen()) {
if (!this->flushWriteCache()) {
}
if (doWUX) {
this->writeSectorIndexTable();
}
this->fileHandle->close();
}
if (this->emptySector != nullptr) {
free(this->emptySector);
this->emptySector = nullptr;
}
if (this->writeBuffer != nullptr) {
free(this->writeBuffer);
this->writeBuffer = nullptr;
}
if (this->sectorIndexTable != nullptr) {
free(this->sectorIndexTable);
this->sectorIndexTable = nullptr;
}
if (this->sectorBuf != nullptr) {
free(this->sectorBuf);
this->sectorBuf = nullptr;
}
if (this->oddFd >= 0) {
IOSUHAX_FSA_RawClose(gFSAfd, this->oddFd);
this->oddFd = -1;
}
}
bool ApplicationState::writeDataToFile(void *buffer, int numberOfSectors) {
if (!doWUX) {
if (!writeCached(reinterpret_cast<uint32_t>(buffer), numberOfSectors * READ_SECTOR_SIZE)) {
return false;
}
this->currentSector += numberOfSectors;
this->readSectors += numberOfSectors;
} else {
char hashOut[32];
for (int i = 0; i < numberOfSectors; i++) {
uint32_t addr = ((uint32_t) buffer) + (i * READ_SECTOR_SIZE);
calculateHash256(reinterpret_cast<unsigned char *>(addr), READ_SECTOR_SIZE, reinterpret_cast<unsigned char *>(hashOut));
char tmp[34];
auto *test = (uint32_t *) hashOut;
snprintf(tmp, 33, "%08X%08X%08X%08X", test[0], test[1], test[2], test[3]);
std::string hash(tmp);
uint32_t *indexTable = (uint32_t *) this->sectorIndexTable;
auto it = hashMap.find(hash);
if (it != hashMap.end()) {
indexTable[this->currentSector] = swap_uint32(this->hashMap[hash]);
} else {
indexTable[this->currentSector] = swap_uint32(this->writtenSector);
hashMap[hash] = this->writtenSector;
if (this->fileHandle->isOpen()) {
if (!writeCached(addr, READ_SECTOR_SIZE)) {
return false;
}
}
this->writtenSector++;
}
this->currentSector++;
this->readSectors++;
}
}
return true;
}
bool ApplicationState::writeCached(uint32_t addr, uint32_t writeSize) {
// DEBUG_FUNCTION_LINE("Lest write %d bytes", writeSize);
if (writeSize == this->writeBufferSize) {
if (!this->flushWriteCache()) {
return false;
}
int32_t res = this->fileHandle->write(reinterpret_cast<const uint8_t *>(addr), writeSize);
return res >= 0;
}
uint32_t toWrite = writeSize;
if (toWrite == 0) {
return true;
}
uint32_t written = 0;
do {
uint32_t curWrite = toWrite;
if (this->writeBufferPos + curWrite > this->writeBufferSize) {
curWrite = this->writeBufferSize - this->writeBufferPos;
}
// DEBUG_FUNCTION_LINE("Copy from %08X into %08X, size %08X, %d",(addr + written),((uint32_t) this->writeBuffer) + this->writeBufferPos, curWrite, this->writeBufferPos/READ_SECTOR_SIZE);
OSBlockMove((void *) (((uint32_t) this->writeBuffer) + this->writeBufferPos), (void *) (addr + written), curWrite, 1);
this->writeBufferPos += curWrite;
if (this->writeBufferPos == this->writeBufferSize) {
if (!flushWriteCache()) {
return false;
}
}
toWrite -= curWrite;
written += curWrite;
} while (toWrite > 0);
return true;
}
bool ApplicationState::flushWriteCache() {
if (this->writeBufferPos > 0) {
int32_t res = this->fileHandle->write(static_cast<const uint8_t *>(this->writeBuffer), this->writeBufferPos);
if (res < 0) {
return false;
}
this->writeBufferPos = 0;
}
return true;
}
void ApplicationState::clearWriteCache() {
this->writeBufferPos = 0;
}
void ApplicationState::writeSectorIndexTable() {
if (this->fileHandle->isOpen() && doWUX) {
this->fileHandle->seek(this->sectorTableStart, SEEK_SET);
this->fileHandle->write((uint8_t *) this->sectorIndexTable, totalSectorCount * 4);
}
}
void ApplicationState::printDumpState(const char *fmt, ...) {
WiiUScreen::clearScreen();
ApplicationState::printHeader();
char *buf = (char *) MEMAllocFromDefaultHeapEx(PRINTF_BUFFER_LENGTH, 4);
va_list va;
if (!buf) {
return;
}
va_start(va, fmt);
vsnprintf(buf, PRINTF_BUFFER_LENGTH, fmt, va);
WiiUScreen::drawLine(buf);
MEMFreeToDefaultHeap(buf);
va_end(va);
ApplicationState::printFooter();
WiiUScreen::flipBuffers();
}
void ApplicationState::dumpAppFiles() {
uint8_t opt[0x400];
IOSUHAX_read_otp(opt, 0x400);
uint8_t cKey[0x10];
memcpy(cKey, opt + 0xE0, 0x10);
DEBUG_FUNCTION_LINE("Reading Partitions");
printDumpState("Reading Partitions...");
auto discReader = new DiscReaderDiscDrive();
if (!discReader->IsReady()) {
DEBUG_FUNCTION_LINE("!IsReady");
this->setError(ERROR_OPEN_ODD1);
delete discReader;
return;
}
DEBUG_FUNCTION_LINE("Read DiscHeader");
auto *discHeader = new WiiUDiscHeader(discReader, 0);
bool forceExit = false;
for (auto &partition: discHeader->wiiUContentsInformation->partitions->partitions) {
auto gmPartition = dynamic_cast<WiiUGMPartition *>(partition);
if (gmPartition != nullptr) {
auto *nusTitle = NUSTitle::loadTitleFromGMPartition(gmPartition, discReader, cKey);
if (nusTitle == nullptr) {
DEBUG_FUNCTION_LINE("nusTitle was null");
continue;
}
auto *dataProvider = nusTitle->dataProcessor->getDataProvider();
uint64_t partitionSize = 0;
uint64_t partitionSizeWritten = 0;
for (auto &content: nusTitle->tmd->contentList) {
partitionSize += ROUNDUP(content->encryptedFileSize, 16);
}
auto partitionDumpInfo = StringTools::strfmt("Partition: %s\n\tProgress: %.2f MiB / %.2f MiB\n", partition->getVolumeId().c_str(), partitionSizeWritten / 1024.0f / 1024.0f,
partitionSize / 1024.0f / 1024.0f);
printDumpState("%s", partitionDumpInfo.c_str());
char buffer[512];
snprintf(buffer, 500, "%swudump/%s/%s", target.c_str(), this->discId, gmPartition->getVolumeId().c_str());
FSUtils::CreateSubfolder(buffer);
uint8_t *wBuffer = nullptr;
uint32_t wBufferLen = 0;
if (dataProvider->getRawTMD(&wBuffer, &wBufferLen)) {
std::string fileName = std::string(buffer).append("/").append(WUD_TMD_FILENAME);
printDumpState("%s\nSaving %s", partitionDumpInfo.c_str(), WUD_TMD_FILENAME);
FSUtils::saveBufferToFile(fileName.c_str(), wBuffer, wBufferLen);
free(wBuffer);
}
if (dataProvider->getRawTicket(&wBuffer, &wBufferLen)) {
std::string fileName = std::string(buffer).append("/").append(WUD_TICKET_FILENAME);
printDumpState("%s\nSaving %s", partitionDumpInfo.c_str(), WUD_TICKET_FILENAME);
FSUtils::saveBufferToFile(fileName.c_str(), wBuffer, wBufferLen);
free(wBuffer);
}
if (dataProvider->getRawCert(&wBuffer, &wBufferLen)) {
std::string fileName = std::string(buffer).append("/").append(WUD_TICKET_FILENAME);
printDumpState("%s\nSaving %s", partitionDumpInfo.c_str(), WUD_CERT_FILENAME);
FSUtils::saveBufferToFile(fileName.c_str(), wBuffer, wBufferLen);
free(wBuffer);
}
auto contentCount = nusTitle->tmd->contentList.size();
auto contentI = 1;
for (auto &content: nusTitle->tmd->contentList) {
char bufApp[32];
snprintf(bufApp, 31, "%08X.app", content->ID);
std::string appFileName = std::string(buffer) + "/" + bufApp;
partitionDumpInfo = StringTools::strfmt("Partition: %s\n\tProgress: %.2f MiB / %.2f MiB\n", partition->getVolumeId().c_str(), partitionSizeWritten / 1024.0f / 1024.0f,
partitionSize / 1024.0f / 1024.0f);
auto contentDumpInfo = StringTools::strfmt("Saving %s (Content %02d/%02d)\n", bufApp, contentI, contentCount);
printDumpState("%s\n%s", partitionDumpInfo.c_str(), contentDumpInfo.c_str());
uint32_t bufferSize = READ_NUM_SECTORS * READ_SECTOR_SIZE * 2;
auto *readBuffer = (uint8_t *) malloc(bufferSize);
if (readBuffer == nullptr) {
DEBUG_FUNCTION_LINE("Failed to alloc buffer");
continue;
}
CFile file(appFileName, CFile::WriteOnly);
if (!file.isOpen()) {
free(readBuffer);
continue;
}
uint32_t readSoFar = 0;
uint64_t curOffset = 0;
uint32_t size = ROUNDUP(content->encryptedFileSize, 16);
OSTime startTimeApp = OSGetTime();
do {
if (!WHBProcIsRunning()) {
forceExit = true;
break;
}
startTimeApp = OSGetTime();
WiiUScreen::clearScreen();
uint32_t toRead = size - readSoFar;
if (toRead > bufferSize) {
toRead = bufferSize;
}
dataProvider->readRawContent(content, readBuffer, curOffset, toRead);
if (file.write((const uint8_t *) readBuffer, toRead) != (int32_t) toRead) {
DEBUG_FUNCTION_LINE("Failed to write");
break;
}
OSTime curTime = OSGetTime();
auto curSpeed = (float) toRead / (float) OSTicksToMilliseconds(curTime - startTimeApp);
readSoFar += toRead;
curOffset += toRead;
partitionSizeWritten += toRead;
partitionDumpInfo = StringTools::strfmt("Partition: %s\n\tProgress: %.2f MiB / %.2f MiB\n", partition->getVolumeId().c_str(), partitionSizeWritten / 1024.0f / 1024.0f,
partitionSize / 1024.0f / 1024.0f);
printDumpState("%s\n%s\tProgress: %.2f MiB / %.2f MiB (%0.2f%%)\n\tSpeed: %0.2f MiB/s", partitionDumpInfo.c_str(), contentDumpInfo.c_str(), readSoFar / 1024.0f / 1024.0f,
size / 1024.0f / 1024.0f, ((readSoFar * 1.0f) / size) * 100.0f, curSpeed / 1024.0f);
} while (readSoFar < size);
file.close();
if (forceExit) {
break;
}
uint8_t *h3Data = nullptr;
uint32_t h3Length = 0;
if (dataProvider->getContentH3Hash(content, &h3Data, &h3Length)) {
char bufh3[32];
snprintf(bufh3, 31, "%08X.h3", content->ID);
std::string h3FileName = std::string(buffer) + "/" + bufh3;
printDumpState("%s\n%s", partitionDumpInfo.c_str(), contentDumpInfo.c_str());
FSUtils::saveBufferToFile(h3FileName.c_str(), h3Data, h3Length);
}
contentI++;
}
delete nusTitle;
if (forceExit) {
exit(0);
break;
}
}
}
delete discHeader;
delete discReader;
}

138
source/ApplicationState.h Normal file
View File

@ -0,0 +1,138 @@
#pragma once
#include <map>
#include <string>
#include <optional>
#include <queue>
#include <coreinit/time.h>
#include "input/Input.h"
#include "fs/CFile.hpp"
#define SECTOR_SIZE 0x8000
#define READ_SECTOR_SIZE SECTOR_SIZE
#define READ_NUM_SECTORS 128
#define WRITE_BUFFER_NUM_SECTORS 128
#define WUD_FILE_SIZE 0x5D3A00000L
typedef struct {
unsigned int magic0;
unsigned int magic1;
unsigned int sectorSize;
unsigned long long uncompressedSize;
unsigned int flags;
} wuxHeader_t;
#define WUX_MAGIC_0 0x57555830
#define WUX_MAGIC_1 swap_uint32(0x1099d02e)
class ApplicationState {
public:
enum eDumpTargetFormat {
DUMP_AS_WUX,
DUMP_AS_WUD,
DUMP_AS_APP,
};
enum eErrorState {
ERROR_NONE,
ERROR_IOSUHAX_FAILED,
ERROR_OPEN_ODD1,
ERROR_READ_FIRST_SECTOR,
ERROR_FILE_OPEN_FAILED,
ERROR_MALLOC_FAILED,
ERROR_NO_DISC_ID,
ERROR_SECTOR_SIZE,
ERROR_MAGIC_NUMBER_WRONG,
ERROR_WRITE_FAILED,
};
enum eGameState {
STATE_ERROR,
STATE_WELCOME_SCREEN,
STATE_CHOOSE_TARGET,
STATE_OPEN_ODD1,
STATE_DUMP_APP_FILES,
STATE_DUMP_APP_FILES_DONE,
STATE_READ_DISC_INFO,
STATE_READ_DISC_INFO_DONE,
STATE_DUMP_TICKET,
STATE_DUMP_DISC_START,
STATE_DUMP_DISC_DONE,
STATE_WAIT_USER_ERROR_CONFIRM,
STATE_DUMP_DISC,
};
ApplicationState();
~ApplicationState();
void setError(eErrorState error);
void render();
void update(Input *input);
std::string ErrorMessage();
std::string ErrorDescription();
int selectedOption;
static void printFooter();
void proccessMenuNavigation(Input *input, int maxOptionValue);
static bool entrySelected(Input *input);
private:
static void printHeader();
CFile log;
eGameState state;
eDumpTargetFormat dumpFormat;
eErrorState error = ERROR_NONE;
std::string target = "fs:/vol/external01/";
int oddFd = -1;
int retryCount = 0;
void *sectorBuf = nullptr;
int sectorBufSize = READ_NUM_SECTORS * READ_SECTOR_SIZE;
char discId[11];
uint64_t currentSector = 0;
std::vector<uint64_t> skippedSectors;
int readResult = 0;
[[nodiscard]] bool writeDataToFile(void* buffer, int numberOfSection);
uint64_t totalSectorCount = 0;
std::map<std::string, int32_t> hashMap;
CFile *fileHandle;
OSTime startTime;
void *writeBuffer = nullptr;
uint32_t writeBufferPos = 0;
uint32_t writeBufferSize = 0;
[[nodiscard]] bool writeCached(uint32_t addr, uint32_t writeSize);
void clearWriteCache();
[[nodiscard]] bool flushWriteCache();
uint32_t readSectors = 0;
uint64_t sectorTableStart = 0;
void *sectorIndexTable = nullptr;
uint64_t sectorTableEnd = 0;
void writeSectorIndexTable();
void *emptySector = nullptr;
bool doWUX = false;
uint32_t writtenSector = 0;
bool autoSkip = false;
void dumpAppFiles();
static void printDumpState(const char *fmt, ...);
};

View File

@ -0,0 +1,60 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "DefaultNUSDataProcessor.h"
bool DefaultNUSDataProcessor::readPlainDecryptedContent(Content *pContent, uint8_t **data, uint32_t *length) {
if (pContent == nullptr || data == nullptr || length == nullptr) {
return false;
}
if ((pContent->type & 0x0002) == 0x0002) {
DEBUG_FUNCTION_LINE("Hashed content not supported yet");
return false;
}
*length = ROUNDUP(pContent->encryptedFileSize, 16);
*data = (uint8_t *) malloc(*length);
if (*data == nullptr) {
return false;
}
auto *inData = (uint8_t *) malloc(*length);
if (!dataProvider->readRawContent(pContent, inData, 0, *length)) {
free(*data);
free(inData);
return false;
}
uint8_t IV[16];
memset(IV, 0, 16);
uint16_t content_index = pContent->index;
memcpy(IV, &content_index, 2);
nusDecryption->decryptData(IV, inData, *data, *length);
free(inData);
return true;
}
NUSDataProvider *DefaultNUSDataProcessor::getDataProvider() {
return dataProvider;
}
DefaultNUSDataProcessor::DefaultNUSDataProcessor(NUSDataProvider *pDataProvider, NUSDecryption *pNUSDecryption) {
dataProvider = pDataProvider;
nusDecryption = pNUSDecryption;
}

View File

@ -0,0 +1,35 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <utils/utils.h>
#include "NUSDataProcessor.h"
class DefaultNUSDataProcessor : public NUSDataProcessor {
public:
DefaultNUSDataProcessor(NUSDataProvider *pDataProvider, NUSDecryption *pNUSDecryption);
~DefaultNUSDataProcessor() override = default;
bool readPlainDecryptedContent(Content *pContent, uint8_t **data, uint32_t *length) override;
NUSDataProvider* getDataProvider() override;
private:
NUSDataProvider *dataProvider;
NUSDecryption *nusDecryption;
};

177
source/WUD/DiscReader.cpp Normal file
View File

@ -0,0 +1,177 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <WUD/content/WiiUDiscContentsHeader.h>
#include <ApplicationState.h>
#include <utils/logger.h>
#include <utils/rijndael.h>
#include <coreinit/debug.h>
#include "DiscReader.h"
bool DiscReader::readDecryptedChunk(uint64_t readOffset, uint8_t *out_buffer, uint8_t *key, uint8_t *IV) const {
int CHUNK_SIZE = 0x10000;
uint32_t sectorOffset = readOffset / READ_SECTOR_SIZE;
auto *encryptedBuffer = (uint8_t *) malloc(CHUNK_SIZE);
if (encryptedBuffer == nullptr) {
DEBUG_FUNCTION_LINE("Failed to alloc buffer");
return false;
}
bool result = false;
if (readEncryptedSector(encryptedBuffer, 2, sectorOffset)) {
aes_set_key((uint8_t *) key);
aes_decrypt((uint8_t *) IV, (uint8_t *) encryptedBuffer, out_buffer, CHUNK_SIZE);
// Update IV
memcpy(IV, &encryptedBuffer[CHUNK_SIZE - 16], 16);
result = true;
}
free(encryptedBuffer);
return result;
}
bool DiscReader::readDecrypted(uint8_t *out_buffer, uint64_t clusterOffset, uint64_t fileOffset, uint32_t size, uint8_t *key, uint8_t *IV, bool useFixedIV) const {
uint8_t backupIV[0x10];
memset(backupIV, 0, 16);
uint8_t *usedIV = backupIV;
if (useFixedIV) {
usedIV = IV;
if (IV == nullptr) {
usedIV = backupIV;
}
}
int BLOCK_SIZE = 0x10000;
uint32_t usedSize = size;
uint64_t usedFileOffset = fileOffset;
auto *buffer = (uint8_t *) malloc(BLOCK_SIZE);
if (buffer == nullptr) {
return false;
}
uint32_t maxCopySize;
uint32_t copySize;
uint64_t readOffset;
uint32_t totalread = 0;
bool result = true;
do {
uint64_t totalOffset = (clusterOffset + usedFileOffset);
uint64_t blockNumber = (totalOffset / BLOCK_SIZE);
uint64_t blockOffset = (totalOffset % BLOCK_SIZE);
readOffset = (blockNumber * BLOCK_SIZE);
if (!useFixedIV) {
memset(usedIV, 0, 16);
uint64_t ivTemp = usedFileOffset >> 16;
memcpy(usedIV + 8, &ivTemp, 8);
}
if (!readDecryptedChunk(readOffset, buffer, key, usedIV)) {
result = false;
break;
}
maxCopySize = BLOCK_SIZE - blockOffset;
copySize = (usedSize > maxCopySize) ? maxCopySize : usedSize;
memcpy(out_buffer + totalread, buffer + blockOffset, copySize);
totalread += copySize;
// update counters
usedSize -= copySize;
usedFileOffset += copySize;
} while (totalread < size);
free(buffer);
return result;
}
bool DiscReader::readEncryptedAligned(uint8_t *buf, uint64_t offset_in_sector, uint32_t size) {
auto full_block_count = size / SECTOR_SIZE;
if (full_block_count > 0) {
if (!readEncryptedSector(buf, full_block_count, offset_in_sector)) {
return false;
}
}
auto remainingSize = size - (full_block_count * SECTOR_SIZE);
if (remainingSize > 0) {
auto newOffset = offset_in_sector + full_block_count;
if (!readEncryptedSector(sector_buf, 1, newOffset)) {
return false;
}
memcpy(buf + (full_block_count * SECTOR_SIZE), sector_buf, remainingSize);
}
return true;
}
bool DiscReader::readEncrypted(uint8_t *buf, uint64_t offset, uint32_t size) {
if (size == 0) {
return true;
}
uint32_t missingFromPrevSector = offset % SECTOR_SIZE;
auto curOffset = offset;
uint32_t offsetInBuf = 0;
uint32_t totalRead = 0;
if (missingFromPrevSector > 0) {
auto offset_in_sectors = offset / SECTOR_SIZE;
if (!readEncryptedSector(sector_buf, 1, offset_in_sectors)) {
return false;
}
uint32_t toCopy = SECTOR_SIZE - missingFromPrevSector;
if (toCopy > size) {
toCopy = size;
}
memcpy(buf, sector_buf + missingFromPrevSector, toCopy);
totalRead += toCopy;
curOffset += missingFromPrevSector;
offsetInBuf += missingFromPrevSector;
}
if (totalRead >= size) {
return true;
}
if (curOffset % SECTOR_SIZE == 0) {
if (!readEncryptedAligned(buf + offsetInBuf, offset / SECTOR_SIZE, size)) {
return false;
}
} else {
OSFatal("Failed to read encrypted");
}
return true;
}
DiscReader::DiscReader() {
this->sector_buf = (uint8_t *) malloc(READ_SECTOR_SIZE);
}
DiscReader::~DiscReader() {
free(this->sector_buf);
}

42
source/WUD/DiscReader.h Normal file
View File

@ -0,0 +1,42 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
class DiscReader {
public:
DiscReader();
virtual ~DiscReader();
virtual bool IsReady() = 0;
virtual bool readEncryptedSector(uint8_t *buffer, uint32_t block_cnt, uint64_t offset_in_sector) const = 0;
bool readEncryptedAligned(uint8_t *buf, uint64_t offset_in_sector, uint32_t size);
bool readDecryptedChunk(uint64_t readOffset, uint8_t *out_buffer, uint8_t *key, uint8_t *IV) const;
bool readDecrypted(uint8_t *out_buffer, uint64_t clusterOffset, uint64_t fileOffset, uint32_t size, uint8_t *key, uint8_t *IV, bool useFixedIV) const;
virtual bool readEncrypted(uint8_t *buf, uint64_t offset, uint32_t size);
uint8_t discKey[16]{};
bool hasDiscKey = false;
private:
uint8_t *sector_buf;
};

View File

@ -0,0 +1,97 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <WUD/content/WiiUDiscContentsHeader.h>
#include <common/common.h>
#include <ApplicationState.h>
#include <iosuhax.h>
#include <utils/rijndael.h>
#include <utils/logger.h>
#include "DiscReaderDiscDrive.h"
DiscReaderDiscDrive::DiscReaderDiscDrive() : DiscReader() {
auto *sector_buf = (uint8_t *) malloc(READ_SECTOR_SIZE);
if (sector_buf == nullptr) {
return;
}
auto ret = IOSUHAX_FSA_RawOpen(gFSAfd, "/dev/odd01", &device_handle);
if (ret < 0) {
return;
}
auto res = IOSUHAX_FSA_RawRead(gFSAfd, sector_buf, READ_SECTOR_SIZE, 1, 3, device_handle);
if (res >= 0) {
if (((uint32_t *) sector_buf)[0] != WiiUDiscContentsHeader::MAGIC) {
uint8_t iv[16];
memset(iv, 0, 16);
auto discKeyRes = IOSUHAX_ODM_GetDiscKey(discKey);
if (discKeyRes >= 0) {
hasDiscKey = true;
auto sector_buf_decrypted = (uint8_t *) malloc(READ_SECTOR_SIZE);
if (sector_buf_decrypted != nullptr) {
aes_set_key((uint8_t *) discKey);
aes_decrypt((uint8_t *) iv, (uint8_t *) sector_buf, (uint8_t *) &sector_buf_decrypted[0], READ_SECTOR_SIZE);
if (((uint32_t *) sector_buf_decrypted)[0] == WiiUDiscContentsHeader::MAGIC) {
DEBUG_FUNCTION_LINE("Key was correct");
this->init_done = true;
}
free(sector_buf_decrypted);
}
}
} else {
this->init_done = true;
}
}
free(sector_buf);
}
bool DiscReaderDiscDrive::readEncryptedSector(uint8_t *buffer, uint32_t block_cnt, uint64_t offset_in_sectors) const {
if (IOSUHAX_FSA_RawRead(gFSAfd, buffer, READ_SECTOR_SIZE, block_cnt, offset_in_sectors, device_handle) < 0) {
DEBUG_FUNCTION_LINE("Failed to read from Disc");
return false;
}
return true;
}
bool DiscReaderDiscDrive::IsReady() {
return init_done;
}
DiscReaderDiscDrive::~DiscReaderDiscDrive() {
if (device_handle != -1) {
IOSUHAX_FSA_RawOpen(gFSAfd, "/dev/odd01", &device_handle);
}
}
bool DiscReaderDiscDrive::readEncrypted(uint8_t *buf, uint64_t offset, uint32_t size) {
if (size == 0) {
return true;
}
if ((offset & 0x7FFF) != 0 || (size & 0x7FFF) != 0) {
return DiscReader::readEncrypted(buf, offset, size);
}
uint32_t block_cnt = size >> 15;
uint32_t offset_in_sectors = offset >> 15;
if (IOSUHAX_FSA_RawRead(gFSAfd, buf, 0x8000, block_cnt, offset_in_sectors, device_handle) < 0) {
DEBUG_FUNCTION_LINE("Failed to read from Disc");
return false;
}
return true;
}

View File

@ -0,0 +1,34 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
#include "DiscReader.h"
class DiscReaderDiscDrive : public DiscReader{
public:
DiscReaderDiscDrive();
~DiscReaderDiscDrive() override;
bool readEncryptedSector(uint8_t *buffer, uint32_t block_cnt, uint64_t offset_in_sector) const override;
bool IsReady() override;
bool readEncrypted(uint8_t *buf, uint64_t offset, uint32_t size) override;
private:
bool init_done = false;
int32_t device_handle = -1;
};

View File

@ -0,0 +1,16 @@
#pragma once
#include "NUSDataProvider.h"
#include "NUSDecryption.h"
class NUSDataProcessor {
protected:
NUSDataProcessor() = default;
public:
virtual ~NUSDataProcessor() = default;
virtual NUSDataProvider *getDataProvider() = 0;
virtual bool readPlainDecryptedContent(Content *pContent, uint8_t **data, uint32_t *length) = 0;
};

View File

@ -0,0 +1,41 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
#include <WUD/entities/TMD/Content.h>
#include <WUD/entities/FST/FST.h>
class NUSDataProvider {
public:
virtual ~NUSDataProvider() = default;
virtual bool readRawContent(Content *content, uint8_t *buffer, uint64_t offset, uint32_t size) = 0;
virtual bool getContentH3Hash(Content *content, uint8_t **data, uint32_t *size) = 0;
virtual bool getRawTMD(uint8_t **data, uint32_t *size) = 0;
virtual bool getRawTicket(uint8_t **data, uint32_t *size) = 0;
virtual bool getRawCert(uint8_t **data, uint32_t *size) = 0;
virtual void setFST(FST *fst) {
}
};

View File

@ -0,0 +1,114 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "NUSDataProviderWUD.h"
NUSDataProviderWUD::NUSDataProviderWUD(WiiUGMPartition *pGamePartition, DiscReader *pDiscReader) {
gamePartition = pGamePartition;
discReader = pDiscReader;
}
NUSDataProviderWUD::~NUSDataProviderWUD() {
delete fst;
}
bool NUSDataProviderWUD::readRawContent(Content *content, uint8_t *buffer, uint64_t offset, uint32_t size) {
if (buffer == nullptr) {
DEBUG_FUNCTION_LINE();
return false;
}
auto offsetInWUD = getOffsetInWUD(content) + offset;
return discReader->readEncrypted(buffer, offsetInWUD, size);
}
bool NUSDataProviderWUD::getContentH3Hash(Content *content, uint8_t **data, uint32_t *size) {
if (content == nullptr || data == nullptr || size == nullptr) {
DEBUG_FUNCTION_LINE();
return false;
}
auto cur = gamePartition->getVolumes().begin()->second->h3HashArrayList[content->index];
if (cur == nullptr || cur->size == 0) {
DEBUG_FUNCTION_LINE();
return false;
}
*data = (uint8_t *) malloc(cur->size);
*size = cur->size;
memcpy(*data, cur->data, *size);
return true;
}
void NUSDataProviderWUD::setFST(FST *pFST) {
// We need to set the correct blocksizes
auto blockSize = gamePartition->getVolumes().begin()->second->blockSize;
for (const auto &e: pFST->sectionEntries->getSections()) {
e->address = AddressInVolumeBlocks(blockSize, e->address.value);
e->size = SizeInVolumeBlocks(blockSize, e->size.value);
}
fst = pFST;
}
bool NUSDataProviderWUD::getRawCert(uint8_t **data, uint32_t *size) {
if (data == nullptr || size == nullptr) {
return false;
}
*data = (uint8_t *) malloc(gamePartition->certLen);
if (*data == nullptr) {
return false;
}
*size = gamePartition->certLen;
memcpy(*data, gamePartition->rawCert, gamePartition->certLen);
return true;
}
bool NUSDataProviderWUD::getRawTicket(uint8_t **data, uint32_t *size) {
if (data == nullptr || size == nullptr) {
return false;
}
*data = (uint8_t *) malloc(gamePartition->tikLen);
if (*data == nullptr) {
return false;
}
*size = gamePartition->tikLen;
memcpy(*data, gamePartition->rawTicket, gamePartition->tikLen);
return true;
}
bool NUSDataProviderWUD::getRawTMD(uint8_t **data, uint32_t *size) {
if (data == nullptr || size == nullptr) {
DEBUG_FUNCTION_LINE("input was null");
return false;
}
*data = (uint8_t *) malloc(gamePartition->TMDLen);
if (*data == nullptr) {
DEBUG_FUNCTION_LINE("Failed to alloc memory");
return false;
}
*size = gamePartition->TMDLen;
memcpy(*data, gamePartition->rawTMD, gamePartition->TMDLen);
return true;
}
uint64_t NUSDataProviderWUD::getOffsetInWUD(Content *content) const {
if (content->index == 0) { // Index 0 is the FST which is at the beginning of the partition;
auto *vh = gamePartition->getVolumes().begin()->second;
return gamePartition->getSectionOffsetOnDefaultPartition() + vh->FSTAddress.getAddressInBytes();
}
auto *info = FSTUtils::getSectionEntryForIndex(fst, content->index);
if (info == nullptr) {
OSFatal("Failed to get section for Content");
}
return gamePartition->getSectionOffsetOnDefaultPartition() + info->address.getAddressInBytes();
}

View File

@ -0,0 +1,50 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <WUD/content/partitions/WiiUGMPartition.h>
#include "NUSDataProvider.h"
#include "DiscReader.h"
#include <utils/FSTUtils.h>
#include <coreinit/debug.h>
class NUSDataProviderWUD : public NUSDataProvider {
public:
NUSDataProviderWUD(WiiUGMPartition *pGamePartition, DiscReader *pDiscReader);
~NUSDataProviderWUD() override;
bool readRawContent(Content *content, uint8_t *buffer, uint64_t offset, uint32_t size) override;
bool getContentH3Hash(Content *content, uint8_t **data, uint32_t *size) override;
void setFST(FST *pFST) override;
bool getRawCert(uint8_t **data, uint32_t *size) override;
bool getRawTicket(uint8_t **data, uint32_t *size) override;
bool getRawTMD(uint8_t **data, uint32_t *size) override;
FST *fst{};
WiiUGMPartition *gamePartition;
DiscReader *discReader;
private:
uint64_t getOffsetInWUD(Content *content) const;
};

View File

@ -0,0 +1,26 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "NUSDecryption.h"
void NUSDecryption::decryptData(uint8_t *IV, uint8_t *inData, uint8_t *outData, uint32_t size) const {
aes_set_key(ticket->ticketKeyDec);
aes_decrypt(IV, inData, outData, size);
}
NUSDecryption::NUSDecryption(Ticket *pTicket) {
ticket = pTicket;
}

View File

@ -0,0 +1,28 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include "Ticket.h"
class NUSDecryption {
public:
explicit NUSDecryption(Ticket *pTicket);
void decryptData(uint8_t *IV, uint8_t *inData, uint8_t *outData, uint32_t size) const ;
Ticket *ticket;
};

83
source/WUD/NUSTitle.cpp Normal file
View File

@ -0,0 +1,83 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "NUSTitle.h"
NUSTitle *NUSTitle::loadTitle(NUSDataProvider *dataProvider, uint8_t *commonKey) {
uint8_t *data = nullptr;
uint32_t dataLen = 0;
if (!dataProvider->getRawTMD(&data, &dataLen)) {
DEBUG_FUNCTION_LINE("Failed to read TMD");
delete dataProvider;
return nullptr;
}
auto *tmd = new TitleMetaData(data);
free(data);
if (!dataProvider->getRawTicket(&data, &dataLen)) {
DEBUG_FUNCTION_LINE("Failed to read ticket");
delete tmd;
delete dataProvider;
return nullptr;
}
auto *ticket = new Ticket(data, commonKey);
free(data);
auto *decryption = new NUSDecryption(ticket);
auto *dpp = new DefaultNUSDataProcessor(dataProvider, decryption);
// If we have more than one content, the index 0 is the FST.
Content *fstContent = tmd->getContentByIndex(0);
if (!dpp->readPlainDecryptedContent(fstContent, &data, &dataLen)) {
DEBUG_FUNCTION_LINE("Failed to read decrypted content");
delete dataProvider;
delete dpp;
delete decryption;
delete ticket;
delete tmd;
return nullptr;
}
FST *fst = new FST(data, dataLen, 0, VolumeBlockSize(1));
// The dataprovider may need the FST to calculate the offset of a content
// on the partition.
dataProvider->setFST(fst);
return new NUSTitle(tmd, dpp, dataProvider, decryption, ticket, fst);
}
NUSTitle::NUSTitle(TitleMetaData *pTMD, NUSDataProcessor *pProcessor, NUSDataProvider *pDataProvider, NUSDecryption *pDecryption, Ticket *pTicket, FST *pFST) {
tmd = pTMD;
dataProcessor = pProcessor;
ticket = pTicket;
fst = pFST;
decryption = pDecryption;
dataProvider = pDataProvider;
}
NUSTitle::~NUSTitle() {
delete dataProvider;
delete dataProcessor;
delete decryption;
delete ticket;
delete tmd;
}
NUSTitle *NUSTitle::loadTitleFromGMPartition(WiiUGMPartition *pPartition, DiscReaderDiscDrive *pDrive, uint8_t *commonKey) {
return loadTitle(new NUSDataProviderWUD(pPartition, pDrive), commonKey);
}

48
source/WUD/NUSTitle.h Normal file
View File

@ -0,0 +1,48 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <WUD/NUSDataProvider.h>
#include <WUD/entities/TMD/TitleMetaData.h>
#include <WUD/content/partitions/WiiUGMPartition.h>
#include "Ticket.h"
#include "NUSDataProcessor.h"
#include "NUSDecryption.h"
#include "DefaultNUSDataProcessor.h"
#include "DiscReaderDiscDrive.h"
#include "NUSDataProviderWUD.h"
class NUSTitle {
public:
~NUSTitle();
NUSDataProcessor *dataProcessor;
TitleMetaData *tmd;
Ticket *ticket;
FST *fst;
NUSDecryption *decryption;
NUSDataProvider *dataProvider;
static NUSTitle *loadTitleFromGMPartition(WiiUGMPartition *pPartition, DiscReaderDiscDrive *pDrive, uint8_t commonKey[16]);
private:
static NUSTitle *loadTitle(NUSDataProvider *dataProvider, uint8_t commonKey[16]);
NUSTitle(TitleMetaData *pTMD, NUSDataProcessor *pProcessor, NUSDataProvider *pDataProvider, NUSDecryption *pDecryption, Ticket *pTicket, FST *pFST);
};

33
source/WUD/Ticket.cpp Normal file
View File

@ -0,0 +1,33 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "Ticket.h"
Ticket::Ticket(uint8_t *data, uint8_t *commonKey) {
uint8_t *tikKeyEnc = data + 0x1BF;
uint8_t *title_id = data + 0x1DC;
uint8_t IV[0x10];
int k;
for (k = 0; k < 8; k++) {
IV[k] = title_id[k];
IV[k + 8] = 0x00;
}
aes_set_key(commonKey);
aes_decrypt(IV, tikKeyEnc, ticketKeyDec, 16);
memcpy(ticketKeyEnc, tikKeyEnc, 16);
}

29
source/WUD/Ticket.h Normal file
View File

@ -0,0 +1,29 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
#include <utils/rijndael.h>
#include <cstring>
class Ticket {
public:
Ticket(uint8_t *data, uint8_t commonKey[16]);
uint8_t ticketKeyEnc[16]{};
uint8_t ticketKeyDec[16]{};
};

View File

@ -0,0 +1,37 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <coreinit/debug.h>
#include "WiiUContentsInformation.h"
uint32_t WiiUContentsInformation::LENGTH = 32768;
WiiUContentsInformation::WiiUContentsInformation(DiscReader *reader, uint32_t offset) {
uint32_t curOffset = offset;
discContentHeader = new WiiUDiscContentsHeader(reader, curOffset);
curOffset += WiiUDiscContentsHeader::LENGTH;
partitions = new WiiUPartitions(reader, curOffset, discContentHeader->numberOfPartition, discContentHeader->blockSize);
curOffset += WiiUPartitions::LENGTH;
if (curOffset - offset != LENGTH) {
OSFatal("Length mismatch");
}
}
WiiUContentsInformation::~WiiUContentsInformation() {
delete partitions;
delete discContentHeader;
}

View File

@ -0,0 +1,35 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include "../DiscReader.h"
#include "WiiUDiscContentsHeader.h"
#include "partitions/WiiUPartitions.h"
class WiiUContentsInformation {
public:
WiiUContentsInformation(DiscReader *reader, uint32_t offset);
~WiiUContentsInformation();
WiiUDiscContentsHeader *discContentHeader;
WiiUPartitions *partitions;
static uint32_t LENGTH;
};

View File

@ -0,0 +1,44 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <utils/blocksize/DiscBlockSize.h>
#include <coreinit/debug.h>
#include <cstdlib>
#include "WiiUDiscContentsHeader.h"
uint32_t WiiUDiscContentsHeader::LENGTH = 2048;
uint32_t WiiUDiscContentsHeader::MAGIC = 0xCCA6E67B;
WiiUDiscContentsHeader::WiiUDiscContentsHeader(DiscReader *reader, uint32_t offset) {
auto *buffer = (uint8_t *) malloc(LENGTH);
if (!reader->hasDiscKey) {
if(!reader->readEncrypted(buffer, offset, LENGTH)){
OSFatal("WiiUDiscContentsHeader: Failed to read encrypted");
}
} else {
if(!reader->readDecrypted(buffer, offset, 0, LENGTH, reader->discKey, nullptr, true)){
OSFatal("WiiUDiscContentsHeader: Failed to read decrypted");
}
}
if (((uint32_t *) buffer)[0] != MAGIC) {
OSFatal("WiiUDiscContentsHeader MAGIC mismatch.");
}
blockSize = DiscBlockSize(((uint32_t *) buffer)[1]);
memcpy(tocHash, &buffer[8], 20);
numberOfPartition = ((uint32_t *) buffer)[7];
free(buffer);
}

View File

@ -0,0 +1,36 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <WUD/DiscReader.h>
#include <utils/blocksize/DiscBlockSize.h>
class WiiUDiscContentsHeader {
public:
WiiUDiscContentsHeader(DiscReader *reader, uint32_t offset);
~WiiUDiscContentsHeader() = default;
DiscBlockSize blockSize{};
uint8_t tocHash[20]{};
uint32_t numberOfPartition;
static uint32_t LENGTH;
static uint32_t MAGIC;
};

View File

@ -0,0 +1,43 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "WiiUDataPartition.h"
WiiUDataPartition::~WiiUDataPartition() {
delete basePartition;
delete fst;
}
WiiUDataPartition::WiiUDataPartition(WiiUPartition *partition, FST *pFST) {
basePartition = partition;
fst = pFST;
}
std::string WiiUDataPartition::getVolumeId() const &{
return basePartition->getVolumeId();
}
std::map<AddressInDiscBlocks, VolumeHeader *> WiiUDataPartition::getVolumes() const &{
return basePartition->getVolumes();
}
uint16_t WiiUDataPartition::getFileSystemDescriptor() const {
return basePartition->getFileSystemDescriptor();
}
uint64_t WiiUDataPartition::getSectionOffsetOnDefaultPartition() {
return basePartition->getSectionOffsetOnDefaultPartition();
}

View File

@ -0,0 +1,46 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
#include <cstdlib>
#include <WUD/entities/FST/FST.h>
#include <utils/blocksize/AddressInDiscBlocks.h>
#include "WiiUPartition.h"
class WiiUDataPartition : public WiiUPartition {
public:
WiiUDataPartition(WiiUPartition *partition, FST *pFST);
~WiiUDataPartition() override;
[[nodiscard]] std::string getVolumeId() const & override;
[[nodiscard]] std::map<AddressInDiscBlocks, VolumeHeader *> getVolumes() const & override;
[[nodiscard]] uint16_t getFileSystemDescriptor() const override;
[[nodiscard]] uint64_t getSectionOffsetOnDefaultPartition() override;
FST *fst{};
private:
WiiUPartition *basePartition;
};

View File

@ -0,0 +1,50 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "WiiUGMPartition.h"
WiiUGMPartition::~WiiUGMPartition() {
free(rawCert);
free(rawTMD);
free(rawTicket);
delete basePartition;
}
WiiUGMPartition::WiiUGMPartition(WiiUPartition *partition, uint8_t *pRawTIK, uint32_t pTikLen, uint8_t *pRawTMD, uint32_t pTMDLen, uint8_t *pRawCert, uint32_t pCertLen) {
basePartition = partition;
rawCert = pRawCert;
rawTMD = pRawTMD;
rawTicket = pRawTIK;
tikLen = pTikLen;
TMDLen = pTMDLen;
certLen = pCertLen;
}
std::string WiiUGMPartition::getVolumeId() const &{
return basePartition->getVolumeId();
}
std::map<AddressInDiscBlocks, VolumeHeader *> WiiUGMPartition::getVolumes() const &{
return basePartition->getVolumes();
}
uint16_t WiiUGMPartition::getFileSystemDescriptor() const {
return basePartition->getFileSystemDescriptor();
}
uint64_t WiiUGMPartition::getSectionOffsetOnDefaultPartition() {
return basePartition->getSectionOffsetOnDefaultPartition();
}

View File

@ -0,0 +1,47 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
#include <cstdlib>
#include "WiiUPartition.h"
class WiiUGMPartition : public WiiUPartition {
public:
WiiUGMPartition(WiiUPartition *partition, uint8_t *pRawTIK, uint32_t pTikLen, uint8_t *pRawTMD, uint32_t pTMDLen, uint8_t *pRawCert, uint32_t pCertLen);
~WiiUGMPartition() override;
[[nodiscard]] std::string getVolumeId() const & override;
[[nodiscard]] std::map<AddressInDiscBlocks, VolumeHeader *> getVolumes() const & override;
[[nodiscard]] uint16_t getFileSystemDescriptor() const override;
[[nodiscard]] uint64_t getSectionOffsetOnDefaultPartition() override;
uint8_t *rawTicket;
uint8_t *rawTMD;
uint8_t *rawCert;
uint32_t tikLen;
uint32_t TMDLen;
uint32_t certLen;
private:
WiiUPartition *basePartition;
};

View File

@ -0,0 +1,79 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <coreinit/debug.h>
#include "WiiUPartition.h"
uint32_t WiiUPartition::LENGTH = 128;
WiiUPartition::WiiUPartition() = default;
WiiUPartition::~WiiUPartition() {
for (auto const&[key, val]: volumes) {
delete val;
}
volumes.clear();
}
WiiUPartition::WiiUPartition(DiscReader *reader, uint32_t offset, const DiscBlockSize &blockSize) {
auto buffer = (uint8_t *) malloc(LENGTH);
if (buffer == nullptr) {
OSFatal("WiiUPartition: alloc buffer failed");
}
if (!reader->hasDiscKey) {
if (!reader->readEncrypted(buffer, offset, LENGTH)) {
OSFatal("WiiUPartition: Failed to read encrypted");
}
} else {
auto bufferBigger = (uint8_t *) malloc(LENGTH + 0x10);
if (bufferBigger == nullptr) {
OSFatal("WiiUPartition: alloc bufferBigger failed");
}
if (!reader->readDecrypted(bufferBigger, offset - 0x10, 0, LENGTH + 0x10, reader->discKey, nullptr, true)) {
OSFatal("WiiUPartition: Failed to read encrypted");
}
memcpy(buffer, bufferBigger + 0x10, LENGTH);
free(bufferBigger);
}
char name[32];
memset(name, 0, sizeof(name));
memcpy(name, buffer, 31);
volumeId = name;
uint8_t num = buffer[31];
for (int i = 0; i < num; i++) {
auto address = *((uint32_t *) &buffer[32 + (i * 4)]);
AddressInDiscBlocks discLbaAddress = AddressInDiscBlocks(blockSize, address);
auto vh = new VolumeHeader(reader, discLbaAddress.getAddressInBytes());
volumes[discLbaAddress] = vh;
}
fileSystemDescriptor = ((uint16_t *) &buffer[64])[0];
free(buffer);
}
uint64_t WiiUPartition::getSectionOffsetOnDefaultPartition() {
if (volumes.size() != 1) {
OSFatal("We have more or less than 1 volume header.");
}
return volumes.begin()->first.getAddressInBytes();
}

View File

@ -0,0 +1,51 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <map>
#include <utils/blocksize/DiscBlockSize.h>
#include <utils/blocksize/AddressInDiscBlocks.h>
#include "volumes/VolumeHeader.h"
class WiiUPartition {
public:
WiiUPartition();
explicit WiiUPartition(DiscReader *reader, uint32_t offset, const DiscBlockSize &blockSize);
virtual uint64_t getSectionOffsetOnDefaultPartition();
virtual ~WiiUPartition();
[[nodiscard]] virtual std::string getVolumeId() const &{
return volumeId;
}
[[nodiscard]] virtual std::map<AddressInDiscBlocks, VolumeHeader *> getVolumes() const&{
return volumes;
}
[[nodiscard]] virtual uint16_t getFileSystemDescriptor() const{
return fileSystemDescriptor;
}
private:
std::string volumeId;
std::map<AddressInDiscBlocks, VolumeHeader *> volumes;
uint16_t fileSystemDescriptor{};
static uint32_t LENGTH;
};

View File

@ -0,0 +1,181 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <utils/FSTUtils.h>
#include <coreinit/debug.h>
#include "WiiUPartitions.h"
#include "WiiUGMPartition.h"
#include "WiiUDataPartition.h"
uint32_t WiiUPartitions::LENGTH = 30720;
WiiUPartitions::WiiUPartitions(DiscReader *reader, uint32_t offset, uint32_t numberOfPartitions, const DiscBlockSize &blockSize) {
std::vector<WiiUPartition *> tmp;
tmp.reserve(numberOfPartitions);
for (uint32_t i = 0; i < numberOfPartitions; i++) {
tmp.push_back(new WiiUPartition(reader, offset + (i * 128), blockSize));
}
WiiUPartition *SIPartition = nullptr;
for (auto &partition: tmp) {
if (partition->getVolumeId().starts_with("SI")) {
SIPartition = partition;
}
}
if (SIPartition != nullptr) {
for (auto const&[key, val]: SIPartition->getVolumes()) {
auto volumeAddress = key;
auto volumeAddressInBytes = volumeAddress.getAddressInBytes();
auto volumeHeader = val;
auto fst = (uint8_t *) malloc(volumeHeader->FSTSize);
if (fst == nullptr) {
OSFatal("WiiUPartitions: Failed to alloc FST buffer");
}
if (!reader->hasDiscKey) {
if (!reader->readEncrypted(fst, volumeAddressInBytes + volumeHeader->FSTAddress.getAddressInBytes(),
volumeHeader->FSTSize)) {
OSFatal("WiiUPartitions: Failed to read encrypted");
}
} else {
if (!reader->readDecrypted(fst, volumeAddressInBytes + volumeHeader->FSTAddress.getAddressInBytes(), 0, volumeHeader->FSTSize,
reader->discKey, nullptr, true)) {
OSFatal("WiiUPartitions: Failed to read decrypted");
}
}
FST *siFST = new FST(fst, volumeHeader->FSTSize, 0, volumeHeader->blockSize);
free(fst);
for (auto &child: siFST->getRootEntry()->getDirChildren()) {
uint8_t *tikRaw = nullptr;
uint32_t tikRawLen = 0;
std::string tikFilePath = std::string(child->getFullPath() + '/' + WUD_TICKET_FILENAME);
if (!getFSTEntryAsByte(&tikRaw, &tikRawLen, tikFilePath, siFST, volumeAddress, reader)) {
OSFatal("tikRaw");
}
uint8_t *tmdRaw = nullptr;
uint32_t tmdRawLen = 0;
std::string tmdFilePath = std::string(child->getFullPath() + '/' + WUD_TMD_FILENAME);
if (!getFSTEntryAsByte(&tmdRaw, &tmdRawLen, tmdFilePath, siFST, volumeAddress, reader)) {
OSFatal("tmdRaw");
}
uint8_t *certRaw = nullptr;
uint32_t certRawLen = 0;
std::string certFilePath = std::string(child->getFullPath() + '/' + WUD_CERT_FILENAME);
if (!getFSTEntryAsByte(&certRaw, &certRawLen, certFilePath, siFST, volumeAddress, reader)) {
OSFatal("certRaw");
}
char partitionNameRaw[0x12];
memset(partitionNameRaw, 0, 0x12);
snprintf(partitionNameRaw, 0x11, "%016llX", *((uint64_t *) &tikRaw[0x1DC]));
std::string partitionName = std::string("GM") + partitionNameRaw;
WiiUPartition *curPartition = nullptr;
for (auto &partition: tmp) {
if (partition->getVolumeId().starts_with(partitionName)) {
curPartition = partition;
}
}
if (curPartition == nullptr) {
OSFatal("Failed to get partition");
}
auto *gmPartition = new WiiUGMPartition(curPartition, tikRaw, tikRawLen, tmdRaw, tmdRawLen, certRaw, certRawLen);
partitions.push_back(gmPartition);
}
delete siFST;
}
}
for (auto &partition: tmp) {
if (partition->getVolumeId().starts_with("GM")) {
continue;
}
if (partition->getVolumes().size() != 1) {
OSFatal("We can't handle more or less than one partion address yet.");
}
auto volumeAddress = partition->getVolumes().begin()->first;
auto vh = partition->getVolumes().begin()->second;
auto *rawFST = (uint8_t *) malloc(vh->FSTSize);
if (rawFST == nullptr) {
OSFatal("Failed to alloc rawFST");
}
if (!reader->hasDiscKey) {
if (!reader->readEncrypted(rawFST, volumeAddress.getAddressInBytes() + vh->FSTAddress.getAddressInBytes(), vh->FSTSize)) {
OSFatal("WiiUPartition: Failed to read encrypted");
}
} else {
if (!reader->readDecrypted(rawFST, volumeAddress.getAddressInBytes() + vh->FSTAddress.getAddressInBytes(), 0, vh->FSTSize,
reader->discKey, nullptr, true)) {
OSFatal("WiiUPartition: Failed to read encrypted");
}
}
FST *fst = new FST(rawFST, vh->FSTSize, 0, vh->blockSize);
free(rawFST);
partitions.push_back(new WiiUDataPartition(partition, fst));
}
}
WiiUPartitions::~WiiUPartitions() {
for (auto &partition: partitions) {
delete partition;
}
}
bool WiiUPartitions::getFSTEntryAsByte(uint8_t **buffer_out, uint32_t *outSize, std::string &filePath, FST *fst, const AddressInDiscBlocks &volumeAddress, DiscReader *discReader) {
NodeEntry *entry = FSTUtils::getFSTEntryByFullPath(fst->nodeEntries->rootEntry, filePath);
auto asFileEntry = dynamic_cast<FileEntry *>(entry);
if (asFileEntry == nullptr) {
return false;
}
SectionEntry *info = asFileEntry->getSectionEntry();
if (info == nullptr) {
OSFatal("WiiUPartitions::getFSTEntryAsByte, section info was null");
}
uint64_t sectionOffsetOnDisc = volumeAddress.getAddressInBytes() + info->address.getAddressInBytes();
auto *buffer = (uint8_t *) malloc(asFileEntry->getSize());
if (buffer == nullptr) {
return false;
}
*buffer_out = buffer;
*outSize = asFileEntry->getSize();
if (!discReader->hasDiscKey) {
return discReader->readEncrypted(buffer, sectionOffsetOnDisc + asFileEntry->getOffset(), asFileEntry->getSize());
}
// Calculating the IV
uint8_t IV[16];
memset(IV, 0, 16);
uint64_t ivTemp = asFileEntry->getOffset() >> 16;
memcpy(IV + 8, &ivTemp, 8);
return discReader->readDecrypted(buffer, sectionOffsetOnDisc, asFileEntry->getOffset(), asFileEntry->getSize(), discReader->discKey, IV, false);
}

View File

@ -0,0 +1,42 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
#include <utils/blocksize/DiscBlockSize.h>
#include <utils/blocksize/AddressInDiscBlocks.h>
#include <WUD/entities/FST/FST.h>
#include <WUD/DiscReader.h>
#include "WiiUPartition.h"
#define WUD_TMD_FILENAME "title.tmd"
#define WUD_TICKET_FILENAME "title.tik"
#define WUD_CERT_FILENAME "title.cert"
class WiiUPartitions {
public:
static bool getFSTEntryAsByte(uint8_t **buffer_out, uint32_t *outSize, std::string &filePath, FST *fst, const AddressInDiscBlocks& volumeAddress, DiscReader* discReader);
WiiUPartitions(DiscReader *reader, uint32_t offset, uint32_t numberOfPartitions, const DiscBlockSize& blockSize);
~WiiUPartitions();
std::vector<WiiUPartition *> partitions;
static uint32_t LENGTH;
};

View File

@ -0,0 +1,37 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "H3HashArray.h"
#include <cstring>
#include <coreinit/debug.h>
H3HashArray::H3HashArray(uint8_t *pData, uint32_t pSize) {
size = pSize;
data = nullptr;
if (pSize > 0) {
data = (uint8_t *) malloc(pSize);
if (data == nullptr) {
OSFatal("H3HashArray: Failed to alloc");
}
memcpy(data, pData, pSize);
}
}
H3HashArray::~H3HashArray() {
if (data) {
free(data);
}
}

View File

@ -0,0 +1,31 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
#include <malloc.h>
class H3HashArray {
public:
H3HashArray(uint8_t *pData, uint32_t pSize);
~H3HashArray();
uint8_t *data = nullptr;
uint8_t size;
};

View File

@ -0,0 +1,94 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "VolumeHeader.h"
#include <utils/utils.h>
#include <coreinit/debug.h>
uint32_t VolumeHeader::MAGIC = 0xCC93A4F5;
VolumeHeader::VolumeHeader(DiscReader *reader, uint64_t offset) {
auto buffer = (uint8_t *) malloc(64);
if (buffer == nullptr) {
OSFatal("VolumeHeader: failed to alloc buffer");
}
if (!reader->readEncrypted(buffer, offset, 64)) {
OSFatal("VolumeHeader: failed to read");
}
auto *bufferUint = (uint32_t *) buffer;
if (bufferUint[0] != MAGIC) {
OSFatal("VolumeHeader MAGIC mismatch.");
}
blockSize = VolumeBlockSize(bufferUint[1]);
volumeSize = SizeInVolumeBlocks(blockSize, bufferUint[2]);
h3HashArrayListSize = bufferUint[3];
numberOfH3HashArray = bufferUint[4];
FSTSize = bufferUint[5];
FSTAddress = AddressInVolumeBlocks(blockSize, bufferUint[6]);
FSTHashMode = buffer[36];
encryptType = buffer[37];
majorVersion = buffer[38];
minorVersion = buffer[39];
expiringMajorVersion = buffer[40];
free(buffer);
auto bufferH3 = (uint8_t *) malloc(ROUNDUP(h3HashArrayListSize,16));
if (bufferH3 == nullptr) {
OSFatal("VolumeHeader: failed to alloc h3 buffer");
}
if (!reader->readEncrypted(bufferH3,offset + 64, ROUNDUP(h3HashArrayListSize,16))) {
OSFatal("VolumeHeader: failed to read h3");
}
h3HashArrayList = getH3HashArray(bufferH3, numberOfH3HashArray, h3HashArrayListSize);
free(bufferH3);
}
std::vector<H3HashArray *> VolumeHeader::getH3HashArray(uint8_t *h3Data, uint32_t pNumberOfH3HashArray, uint32_t pH3HashArrayListSize) {
std::vector<H3HashArray *> arrayList;
if(pNumberOfH3HashArray == 0){
return arrayList;
}
for (uint32_t i = 1; i < pNumberOfH3HashArray; i++) {
auto *offsetPtr = (uint32_t *) &h3Data[i * 4];
uint32_t curOffset = offsetPtr[0];
uint32_t curEnd = pH3HashArrayListSize;
if (i < pNumberOfH3HashArray - 1) {
// If it's not the last element, the end of our .h3 is the start of the next .h3
curEnd = offsetPtr[1];
}
arrayList.push_back(new H3HashArray(h3Data + curOffset, curEnd - curOffset));
}
return arrayList;
}
VolumeHeader::~VolumeHeader() {
for (auto &h3: h3HashArrayList) {
delete h3;
}
}

View File

@ -0,0 +1,50 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <vector>
#include <cstdint>
#include <WUD/DiscReader.h>
#include <utils/blocksize/VolumeBlockSize.h>
#include <utils/blocksize/AddressInVolumeBlocks.h>
#include <utils/blocksize/SizeInVolumeBlocks.h>
#include "H3HashArray.h"
class VolumeHeader {
public:
static std::vector<H3HashArray *> getH3HashArray(uint8_t *h3Data, uint32_t numberOfH3HashArray, uint32_t h3HashArrayListSize);
VolumeHeader(DiscReader *reader, uint64_t offset);
~VolumeHeader();
static uint32_t MAGIC;
VolumeBlockSize blockSize;
SizeInVolumeBlocks volumeSize;
uint32_t FSTSize;
AddressInVolumeBlocks FSTAddress;
uint8_t FSTHashMode;
uint8_t encryptType;
uint8_t majorVersion;
uint8_t minorVersion;
uint8_t expiringMajorVersion;
std::vector<H3HashArray *> h3HashArrayList;
uint32_t h3HashArrayListSize;
uint32_t numberOfH3HashArray;
};

View File

@ -0,0 +1,47 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "FST.h"
FST::FST(uint8_t *data, uint32_t fstSize, uint32_t offset, const VolumeBlockSize &blockSize) {
uint32_t curOffset = offset;
header = new FSTHeader(data + curOffset);
curOffset += header->LENGTH;
sectionEntries = new SectionEntries(data + curOffset, header->numberOfSections, blockSize);
curOffset += sectionEntries->getSizeInBytes();
uint32_t lastEntryNumber = RootEntry::parseLastEntryNumber(data, curOffset);
auto stringTableOffset = curOffset + (lastEntryNumber * 16);
stringTable = StringTable::parseData(data, fstSize - stringTableOffset, stringTableOffset, lastEntryNumber);
nodeEntries = NodeEntries::parseData(data, curOffset, sectionEntries, stringTable, header->blockSize);
}
FST::~FST() {
delete nodeEntries;
delete stringTable;
delete sectionEntries;
delete header;
}
RootEntry *FST::getRootEntry() const {
return nodeEntries->rootEntry;
}

View File

@ -0,0 +1,39 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
#include <WUD/entities/FST/header/FSTHeader.h>
#include <WUD/entities/FST/sectionentry/SectionEntries.h>
#include <WUD/entities/FST/stringtable/StringTable.h>
#include <WUD/entities/FST/nodeentry/NodeEntries.h>
#include <WUD/entities/FST/nodeentry/RootEntry.h>
class FST {
public:
FST(uint8_t *data, uint32_t fstSize, uint32_t offset, const VolumeBlockSize& blockSize);
~FST();
FSTHeader *header;
SectionEntries *sectionEntries;
StringTable *stringTable;
NodeEntries *nodeEntries;
[[nodiscard]] RootEntry * getRootEntry() const;
};

View File

@ -0,0 +1,30 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <utils/blocksize/SectionBlockSize.h>
#include <coreinit/debug.h>
#include "FSTHeader.h"
FSTHeader::FSTHeader(uint8_t *data) {
auto *dataAsUint = (uint32_t *) data;
if ((dataAsUint[0] & 0xFFFFFF00) != 0x46535400) {
OSFatal("FST Header magic was wrong");
}
FSTVersion = data[3];
blockSize = SectionBlockSize(dataAsUint[1]);
numberOfSections = dataAsUint[2];
hashDisabled = data[12];
}

View File

@ -0,0 +1,35 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
#include <utils/blocksize/SectionBlockSize.h>
class FSTHeader {
public:
explicit FSTHeader(uint8_t *data) ;
~FSTHeader()= default;
uint8_t FSTVersion;
SectionBlockSize blockSize;
uint8_t hashDisabled;
uint32_t numberOfSections;
uint32_t LENGTH = 32;
};

View File

@ -0,0 +1,82 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <coreinit/debug.h>
#include "DirectoryEntry.h"
DirectoryEntry *DirectoryEntry::parseData(const uint8_t *data, NodeEntryParam param, SectionEntries *sectionEntries, StringTable *stringTable) {
auto *directoryEntry = new DirectoryEntry();
directoryEntry->entryNumber = param.entryNumber;
directoryEntry->parent = param.parent;
directoryEntry->entryType = param.type;
directoryEntry->nameString = stringTable->getStringEntry(param.uint24);
if (directoryEntry->nameString == nullptr) {
OSFatal("Failed to find string for offset");
}
directoryEntry->parentEntryNumber = ((uint32_t *) &data[4])[0];
directoryEntry->lastEntryNumber = ((uint32_t *) &data[8])[0];
directoryEntry->permission = param.permission;
if (param.sectionNumber > sectionEntries->size()) {
OSFatal("section number does not match");
}
directoryEntry->sectionEntry = sectionEntries->getSection(param.sectionNumber);
return directoryEntry;
}
DirectoryEntry::~DirectoryEntry() {
for (auto &child: children) {
delete child;
}
}
std::vector<DirectoryEntry *> DirectoryEntry::getDirChildren() const {
std::vector<DirectoryEntry *> res;
for (auto &cur: children) {
if (cur->isDirectory()) {
res.push_back(dynamic_cast<DirectoryEntry *>(cur));
}
}
return res;
}
std::vector<FileEntry *> DirectoryEntry::getFileChildren() const {
std::vector<FileEntry *> res;
for (auto &cur: children) {
if (cur->isFile()) {
res.push_back(dynamic_cast<FileEntry *>(cur));
}
}
return res;
}
std::vector<NodeEntry *> DirectoryEntry::getChildren() const {
return children;
}
void DirectoryEntry::printPathRecursive() {
DEBUG_FUNCTION_LINE("%s", getFullPath().c_str());
for (auto &child: children) {
child->printPathRecursive();
}
}
void DirectoryEntry::addChild(NodeEntry *entry) {
children.push_back(entry);
}

View File

@ -0,0 +1,46 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <WUD/entities/FST/sectionentry/SectionEntries.h>
#include <WUD/entities/FST/stringtable/StringTable.h>
#include "NodeEntryParam.h"
#include "NodeEntry.h"
#include "FileEntry.h"
class DirectoryEntry : public NodeEntry {
public:
~DirectoryEntry() override;
static DirectoryEntry *parseData(const uint8_t *data, NodeEntryParam param, SectionEntries *sectionEntries, StringTable *stringTable);
uint32_t parentEntryNumber{};
uint32_t lastEntryNumber{};
std::vector<NodeEntry *> children;
void addChild(NodeEntry *entry);
[[nodiscard]] std::vector<DirectoryEntry *> getDirChildren() const;
[[nodiscard]] std::vector<FileEntry *> getFileChildren() const;
[[nodiscard]] std::vector<NodeEntry *> getChildren() const;
void printPathRecursive() override;
};

View File

@ -0,0 +1,56 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "FileEntry.h"
#include <WUD/entities/FST/stringtable/StringTable.h>
#include <coreinit/debug.h>
#include <utility>
FileEntry::FileEntry(SectionAddress address) : address(std::move(address)) {
}
NodeEntry *FileEntry::parseData(uint8_t *data, NodeEntryParam param, SectionEntries *sectionEntries, StringTable *stringTable, const SectionBlockSize &blockSize) {
auto *entry = new FileEntry(SectionAddress(blockSize, ((uint32_t *) &data[4])[0]));
entry->entryNumber = param.entryNumber;
entry->parent = param.parent;
entry->entryType = param.type;
entry->nameString = stringTable->getStringEntry(param.uint24);
if (entry->nameString == nullptr) {
OSFatal("Failed to find string for offset");
}
entry->size = ((uint32_t *) &data[8])[0];
entry->permission = param.permission;
entry->sectionEntry = sectionEntries->getSection(param.sectionNumber);
return entry;
}
SectionEntry *FileEntry::getSectionEntry() {
return sectionEntry;
}
uint64_t FileEntry::getOffset() const {
return address.getAddressInBytes();
}
uint32_t FileEntry::getSize() const {
return size;
}

View File

@ -0,0 +1,41 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <utility>
#include <utils/blocksize/SectionAddress.h>
#include "NodeEntry.h"
class FileEntry : public NodeEntry {
public:
explicit FileEntry(SectionAddress address);
static NodeEntry *parseData(uint8_t *data, NodeEntryParam param, SectionEntries *sectionEntries, StringTable *stringTable, const SectionBlockSize &blockSize);
~FileEntry() override = default;
SectionEntry *getSectionEntry();
[[nodiscard]] uint64_t getOffset() const;
[[nodiscard]] uint32_t getSize() const;
private:
SectionAddress address;
uint32_t size{};
};

View File

@ -0,0 +1,57 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <coreinit/debug.h>
#include "NodeEntries.h"
NodeEntries::NodeEntries(RootEntry *pEntry) {
rootEntry = pEntry;
}
NodeEntries::~NodeEntries() {
delete rootEntry;
}
NodeEntry *NodeEntries::DeserializeImpl(uint8_t *data, uint32_t offset, DirectoryEntry *parent, uint32_t entryNumber, SectionEntries *sectionEntries, StringTable *stringTable,
const SectionBlockSize &blockSize) {
NodeEntry *nodeEntry = NodeEntry::AutoDeserialize(data, offset, parent, entryNumber, sectionEntries, stringTable, blockSize);
auto asDirEntry = dynamic_cast<DirectoryEntry *>(nodeEntry);
if (asDirEntry != nullptr) {
uint32_t curEntryNumber = asDirEntry->entryNumber + 1;
while (curEntryNumber < asDirEntry->lastEntryNumber) {
NodeEntry *entry = NodeEntries::DeserializeImpl(data, offset + (curEntryNumber - asDirEntry->entryNumber) * NodeEntry::LENGTH,
asDirEntry, curEntryNumber, sectionEntries, stringTable, blockSize);
asDirEntry->addChild(entry);
auto *childAsDir = dynamic_cast<DirectoryEntry *>(entry);
if (childAsDir != nullptr) {
curEntryNumber = childAsDir->lastEntryNumber;
} else {
curEntryNumber++;
}
}
}
return nodeEntry;
}
NodeEntries *NodeEntries::parseData(unsigned char *data, uint32_t offset, SectionEntries *sectionEntries, StringTable *stringTable, const SectionBlockSize &blockSize) {
NodeEntry *rootEntry = NodeEntries::DeserializeImpl(data, offset, (DirectoryEntry *) nullptr, 0, sectionEntries, stringTable, blockSize);
auto rootEntryCasted = dynamic_cast<RootEntry *>(rootEntry);
if (rootEntryCasted != nullptr) {
return new NodeEntries(rootEntryCasted);
}
OSFatal("Failed to parse Root");
return nullptr;
}

View File

@ -0,0 +1,40 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <WUD/entities/FST/stringtable/StringTable.h>
#include <utils/blocksize/SectionBlockSize.h>
#include <WUD/entities/FST/sectionentry/SectionEntries.h>
#include "DirectoryEntry.h"
#include "RootEntry.h"
#include "NodeEntry.h"
#include "NodeEntries.h"
class NodeEntries {
public:
explicit NodeEntries(RootEntry *pEntry);
~NodeEntries();
static NodeEntry *
DeserializeImpl(unsigned char *data, uint32_t offset, DirectoryEntry *parent, uint32_t entryNumber, SectionEntries *sectionEntries, StringTable *stringTable, const SectionBlockSize &blockSize);
static NodeEntries *parseData(unsigned char *data, uint32_t offset, SectionEntries *sectionEntries, StringTable *stringTable, const SectionBlockSize &blockSize);
RootEntry *rootEntry;
};

View File

@ -0,0 +1,83 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <utils/blocksize/SectionBlockSize.h>
#include <WUD/entities/FST/stringtable/StringTable.h>
#include <WUD/entities/FST/sectionentry/SectionEntries.h>
#include <coreinit/debug.h>
#include "NodeEntry.h"
#include "DirectoryEntry.h"
#include "RootEntry.h"
uint32_t NodeEntry::LENGTH = 16;
NodeEntry *NodeEntry::AutoDeserialize(uint8_t *data, uint32_t offset, DirectoryEntry *pParent, uint32_t eEntryNumber, SectionEntries *sectionEntries,
StringTable *stringTable, const SectionBlockSize &blockSize) {
uint8_t *curEntryData = &data[offset];
NodeEntryParam param{};
param.permission = ((uint16_t *) &curEntryData[12])[0];
param.sectionNumber = ((uint16_t *) &curEntryData[14])[0];
param.entryNumber = eEntryNumber;
param.parent = pParent;
param.type = curEntryData[0];
param.uint24 = ((uint32_t *) curEntryData)[0] & 0x00FFFFFF;
if ((param.type & ENTRY_TYPE_Directory) == ENTRY_TYPE_Directory && param.uint24 == 0) { // Root
return (NodeEntry *) RootEntry::parseData(curEntryData, param, sectionEntries, stringTable);
} else if ((param.type & ENTRY_TYPE_Directory) == ENTRY_TYPE_Directory) {
return (NodeEntry *) DirectoryEntry::parseData(curEntryData, param, sectionEntries, stringTable);
} else if ((param.type & ENTRY_TYPE_File) == ENTRY_TYPE_File) {
return (NodeEntry *) FileEntry::parseData(curEntryData, param, sectionEntries, stringTable, blockSize);
}
OSFatal("FST Unknown Node Type");
return nullptr;
}
std::string NodeEntry::getName() const &{
if (nameString != nullptr) {
return nameString->toString();
}
return "ERROR";
}
std::string NodeEntry::getFullPathInternal() const &{
if (parent != nullptr) {
return parent->getFullPathInternal().append("/").append(getName());
}
return getName();
}
std::string NodeEntry::getFullPath() const &{
return getFullPathInternal();
}
std::string NodeEntry::getPath() const &{
if (parent != nullptr) {
return parent->getFullPath().append("/");
}
return "/";
}
bool NodeEntry::isDirectory() const {
return (entryType & ENTRY_TYPE_Directory) == ENTRY_TYPE_Directory;
}
bool NodeEntry::isFile() const {
return (entryType & ENTRY_TYPE_File) == ENTRY_TYPE_File;
}

View File

@ -0,0 +1,65 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
#include <utils/blocksize/SectionBlockSize.h>
#include <WUD/entities/FST/stringtable/StringEntry.h>
#include <WUD/entities/FST/sectionentry/SectionEntry.h>
#include <WUD/entities/FST/sectionentry/SectionEntries.h>
#include <utils/logger.h>
#include "NodeEntryParam.h"
#define ENTRY_TYPE_File 0
#define ENTRY_TYPE_Directory 1
#define ENTRY_TYPE_Link 0x80
class DirectoryEntry;
class NodeEntry {
public:
uint16_t permission{};
StringEntry *nameString{};
SectionEntry *sectionEntry{};
DirectoryEntry *parent{};
uint8_t entryType{};
uint32_t entryNumber{};
static NodeEntry *AutoDeserialize(uint8_t *data, uint32_t offset, DirectoryEntry *pParent, uint32_t eEntryNumber, SectionEntries *sectionEntries,
StringTable *stringTable, const SectionBlockSize& blockSize);
virtual ~NodeEntry()= default;
virtual void printPathRecursive() {
DEBUG_FUNCTION_LINE("%s", getFullPath().c_str());
}
[[nodiscard]] std::string getFullPath() const&;
[[nodiscard]] std::string getPath() const&;
[[nodiscard]] std::string getName() const&;
[[nodiscard]] bool isDirectory() const;
[[nodiscard]] bool isFile() const;
static uint32_t LENGTH;
private:
[[nodiscard]] std::string getFullPathInternal() const &;
};

View File

@ -0,0 +1,30 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
class DirectoryEntry;
class NodeEntryParam {
public:
uint16_t sectionNumber;
uint32_t entryNumber;
DirectoryEntry* parent;
uint16_t permission;
uint8_t type;
uint32_t uint24;
};

View File

@ -0,0 +1,45 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <coreinit/debug.h>
#include "RootEntry.h"
RootEntry::RootEntry(DirectoryEntry *input) {
if ((input->entryType & ENTRY_TYPE_Directory) != ENTRY_TYPE_Directory || input->entryNumber != 0) {
OSFatal("Input is no root entry.");
}
entryNumber = input->entryNumber;
parent = input->parent;
nameString = input->nameString;
if(nameString == nullptr){
OSFatal("nameString was null");
}
entryType = input->entryType;
parentEntryNumber = input->parentEntryNumber;
lastEntryNumber = input->lastEntryNumber;
permission = input->permission;
sectionEntry = input->sectionEntry;
}
uint32_t RootEntry::parseLastEntryNumber(uint8_t *data, uint32_t offset) {
return ((uint32_t *) &data[8 + offset])[0];
}
RootEntry *RootEntry::parseData(uint8_t *data, NodeEntryParam param, SectionEntries *sectionEntries, StringTable *stringTable) {
return new RootEntry(DirectoryEntry::parseData(data, param, sectionEntries, stringTable));
}

View File

@ -0,0 +1,36 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
#include <WUD/entities/FST/stringtable/StringTable.h>
#include <utils/blocksize/SectionBlockSize.h>
#include <WUD/entities/FST/sectionentry/SectionEntries.h>
#include "DirectoryEntry.h"
class RootEntry : public DirectoryEntry {
explicit RootEntry(DirectoryEntry *input);
public:
~RootEntry() override = default;
static RootEntry *parseData(uint8_t *data, NodeEntryParam param, SectionEntries *sectionEntries, StringTable *stringTable);
static uint32_t parseLastEntryNumber(uint8_t *data, uint32_t offset);
};

View File

@ -0,0 +1,40 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "SectionEntries.h"
SectionEntries::SectionEntries(uint8_t *data, uint32_t numberOfSections, const VolumeBlockSize &pBlockSize) {
for (uint32_t i = 0; i < numberOfSections; i++) {
list.push_back(new SectionEntry(data + (i * 32), i, pBlockSize));
}
}
SectionEntry *SectionEntries::getSection(uint16_t sectionNumber) const {
for (auto const &e: list) {
if (e->sectionNumber == sectionNumber) {
return e;
}
}
return nullptr;
}
uint32_t SectionEntries::getSizeInBytes() const {
return list.size() * 32;
}
uint32_t SectionEntries::size() const {
return list.size();
}

View File

@ -0,0 +1,41 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
#include <vector>
#include <utils/blocksize/VolumeBlockSize.h>
#include "SectionEntry.h"
class SectionEntries {
public:
SectionEntries(uint8_t *data, uint32_t numberOfSections, const VolumeBlockSize &pBlockSize);
[[nodiscard]] uint32_t getSizeInBytes() const;
[[nodiscard]] uint32_t size() const;
[[nodiscard]] SectionEntry *getSection(uint16_t sectionNumber) const;
[[nodiscard]] std::vector<SectionEntry *> getSections() const &{
return list;
}
private:
std::vector<SectionEntry *> list;
};

View File

@ -0,0 +1,32 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "SectionEntry.h"
SectionEntry::SectionEntry(uint8_t *data, uint32_t pSectionNumber, const VolumeBlockSize& pBlockSize) {
auto *dataAsUint = (uint32_t *) data;
address = AddressInVolumeBlocks(pBlockSize, dataAsUint[0]);
size = SizeInVolumeBlocks(pBlockSize, dataAsUint[1]);
ownerID = ((uint64_t *) (&data[8]))[0];
groupID = ((uint64_t *) (&data[16]))[0];
hashMode = data[20];
char buff[32];
snprintf(buff, sizeof(buff), "Section: %d", pSectionNumber);
name = std::string(buff);
sectionNumber = pSectionNumber;
}

View File

@ -0,0 +1,37 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
#include <string>
#include <utils/blocksize/AddressInVolumeBlocks.h>
#include <utils/blocksize/SizeInVolumeBlocks.h>
class SectionEntry {
public:
SectionEntry(uint8_t *data, uint32_t pSectionNumber, const VolumeBlockSize &pBlockSize);
~SectionEntry() = default;
AddressInVolumeBlocks address;
SizeInVolumeBlocks size;
uint8_t hashMode;
uint64_t ownerID;
uint64_t groupID;
std::string name;
uint32_t sectionNumber;
};

View File

@ -0,0 +1,27 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "StringEntry.h"
#include "StringTable.h"
std::string StringEntry::toString() const{
return stringTable->getByAddress(offset);
}
StringEntry::StringEntry(StringTable *pTable, uint32_t pOffset) {
stringTable = pTable;
offset = pOffset;
}

View File

@ -0,0 +1,33 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
#include <string>
class StringTable;
class StringEntry {
public:
StringEntry(StringTable *pTable, uint32_t pOffset);
[[nodiscard]] std::string toString() const;
StringTable *stringTable;
uint32_t offset;
};

View File

@ -0,0 +1,71 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <cstring>
#include <coreinit/debug.h>
#include "StringTable.h"
StringTable *StringTable::parseData(uint8_t *data, uint32_t dataLength, uint32_t offset, uint32_t stringCount) {
auto *stringTable = new StringTable();
uint32_t curOffset = 0;
uint32_t i;
for (i = 0; curOffset < dataLength && i < stringCount; ++curOffset) {
if (data[offset + curOffset] == (uint8_t) 0) {
++i;
}
}
if (i < stringCount) {
OSFatal("stringtable is broken");
}
uint32_t curLength = 0;
for (i = 0; i < stringCount; ++i) {
curOffset = offset + curLength;
stringTable->stringMap[curLength] = new StringEntry(stringTable, curLength);
stringTable->strings[curLength] = (char *) &data[curOffset];
curLength += strlen((char *) &data[curOffset]) + 1;
}
return stringTable;
}
std::string StringTable::getByAddress(uint32_t address) {
return strings[address];
}
StringEntry *StringTable::getStringEntry(uint32_t address) {
return stringMap[address];
}
uint32_t StringTable::getSize() {
uint32_t capacity = 1; // root entry
for (auto &cur: strings) {
capacity += cur.second.length() + 1;
}
return capacity;
}
StringEntry *StringTable::getEntry(std::string &str) {
for (auto &cur: strings) {
if (cur.second == str) {
return stringMap[cur.first];
}
}
return nullptr;
}

View File

@ -0,0 +1,47 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <string>
#include <map>
#include "StringEntry.h"
class StringTable {
public:
~StringTable() {
for (auto &cur: stringMap) {
delete cur.second;
}
stringMap.clear();
strings.clear();
}
static StringTable *parseData(uint8_t *data, uint32_t dataLength, uint32_t offset, uint32_t stringCount);
std::string getByAddress(uint32_t address);
StringEntry *getStringEntry(uint32_t address);
uint32_t getSize();
StringEntry *getEntry(std::string &str);
private:
std::map<uint32_t, StringEntry *> stringMap;
std::map<uint32_t, std::string> strings;
};

View File

@ -0,0 +1,28 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <cstring>
#include "Content.h"
uint32_t Content::LENGTH = 0x30;
Content::Content(uint8_t *data) {
ID = ((uint32_t *) &data[0x00])[0];
index = ((uint16_t *) &data[0x04])[0];
type = ((uint16_t *) &data[0x06])[0];
encryptedFileSize = ((uint64_t *) &data[0x08])[0];
memcpy(hash, &data[0x10], 0x14);
}

View File

@ -0,0 +1,32 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
class Content {
public:
static uint32_t LENGTH;
explicit Content(uint8_t *data);
uint16_t index;
uint32_t ID;
uint16_t type;
uint64_t encryptedFileSize;
uint8_t hash[0x14]{};
};

View File

@ -0,0 +1,42 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "TitleMetaData.h"
TitleMetaData::TitleMetaData(uint8_t *data) {
contentCount = ((uint16_t *) &data[0x1DE])[0];
// Get Contents
for (uint16_t i = 0; i < contentCount; i++) {
auto curOffset = 0xB04 + (i * Content::LENGTH);
auto *c = new Content((uint8_t *) &data[curOffset]);
contentList.push_back(c);
}
}
TitleMetaData::~TitleMetaData() {
for (auto &content: contentList) {
delete content;
}
}
Content* TitleMetaData::getContentByIndex(uint16_t i) {
for (auto &content: contentList) {
if(content->index == i){
return content;
}
}
return nullptr;
}

View File

@ -0,0 +1,35 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
#include <vector>
#include "Content.h"
class TitleMetaData {
public:
explicit TitleMetaData(uint8_t *data);
~TitleMetaData();
std::vector<Content *> contentList;
Content* getContentByIndex(uint16_t index);
private:
uint16_t contentCount;
};

View File

@ -0,0 +1,40 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "WiiUDiscHeader.h"
#include <coreinit/debug.h>
uint32_t WiiUDiscHeader::LENGTH = 131072L;
WiiUDiscHeader::WiiUDiscHeader(DiscReader *reader, uint32_t offset) {
uint32_t curOffset = offset;
manufactorDiscID = new WiiUManufactorDiscID(reader, 0);
curOffset += WiiUManufactorDiscID::LENGTH;
discId = new WiiUDiscID(reader, curOffset);
curOffset += WiiUDiscID::LENGTH;
wiiUContentsInformation = new WiiUContentsInformation(reader, curOffset);
curOffset += WiiUContentsInformation::LENGTH;
if (curOffset - offset != LENGTH) {
OSFatal("Length mismatch");
}
}
WiiUDiscHeader::~WiiUDiscHeader() {
delete manufactorDiscID;
delete discId;
delete wiiUContentsInformation;
}

View File

@ -0,0 +1,37 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
#include <WUD/DiscReader.h>
#include <WUD/content/WiiUContentsInformation.h>
#include "WiiUManufactorDiscID.h"
#include "WiiUDiscID.h"
class WiiUDiscHeader {
public:
static uint32_t LENGTH;
WiiUDiscHeader(DiscReader *reader, uint32_t offset);
WiiUManufactorDiscID *manufactorDiscID = nullptr;
WiiUDiscID *discId = nullptr;
WiiUContentsInformation *wiiUContentsInformation = nullptr;
~WiiUDiscHeader();
};

View File

@ -0,0 +1,43 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "WiiUDiscID.h"
#include <coreinit/debug.h>
uint32_t WiiUDiscID::LENGTH = 32768;
uint32_t WiiUDiscID::MAGIC = 0xCC549EB9;
WiiUDiscID::WiiUDiscID(DiscReader *reader, uint32_t offset) {
auto data = (uint8_t *) malloc(LENGTH);
if (data == nullptr) {
OSFatal("Failed to alloc for WiiUDiscID");
}
if (!reader->readEncrypted(data, offset, LENGTH)) {
OSFatal("Failed to read data");
}
if (((uint32_t *) data)[0] != MAGIC) {
OSFatal("MAGIC FAIL");
}
majorVersion = data[5];
minorVersion = data[6];
footprint = std::string((char *) &data[32]);
free(data);
}

View File

@ -0,0 +1,32 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <string>
#include <WUD/DiscReader.h>
class WiiUDiscID {
public:
WiiUDiscID(DiscReader *reader, uint32_t offset);
static uint32_t LENGTH;
static uint32_t MAGIC;
uint8_t majorVersion;
uint8_t minorVersion;
std::string footprint;
};

View File

@ -0,0 +1,26 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "WiiUManufactorDiscID.h"
#include <coreinit/debug.h>
uint32_t WiiUManufactorDiscID::LENGTH = 65536;
WiiUManufactorDiscID::WiiUManufactorDiscID(DiscReader *reader, uint32_t offset) {
if(!reader->readEncrypted(data, offset, LENGTH)){
OSFatal("WiiUManufactorDiscID: read failed");
}
}

View File

@ -0,0 +1,30 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
#include <WUD/DiscReader.h>
class WiiUManufactorDiscID {
public:
WiiUManufactorDiscID(DiscReader *reader, uint32_t offset);
static uint32_t LENGTH;
private:
uint8_t data[65536]{};
};

3
source/common/common.cpp Normal file
View File

@ -0,0 +1,3 @@
#include "common.h"
int32_t gFSAfd = -1;

5
source/common/common.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include <cstdint>
extern int32_t gFSAfd;

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 = nullptr;
if (size)
*size = 0;
int32_t iFd = open(filepath, O_RDONLY);
if (iFd < 0)
return -1;
uint32_t filesize = lseek(iFd, 0, SEEK_END);
lseek(iFd, 0, SEEK_SET);
auto *buffer = (uint8_t *) malloc(filesize);
if (buffer == nullptr) {
close(iFd);
return -2;
}
uint32_t blocksize = 0x4000;
uint32_t done = 0;
int32_t readBytes = 0;
while (done < filesize) {
if (done + blocksize > filesize) {
blocksize = filesize - done;
}
readBytes = read(iFd, buffer + done, blocksize);
if (readBytes <= 0)
break;
done += readBytes;
}
close(iFd);
if (done != filesize) {
free(buffer);
buffer = nullptr;
return -3;
}
*inbuffer = buffer;
//! sign is optional input
if (size) {
*size = filesize;
}
return filesize;
}
int32_t FSUtils::CheckFile(const char *filepath) {
if (!filepath)
return 0;
struct stat filestat;
char dirnoslash[strlen(filepath) + 2];
snprintf(dirnoslash, sizeof(dirnoslash), "%s", filepath);
while (dirnoslash[strlen(dirnoslash) - 1] == '/')
dirnoslash[strlen(dirnoslash) - 1] = '\0';
char *notRoot = strrchr(dirnoslash, '/');
if (!notRoot) {
strcat(dirnoslash, "/");
}
if (stat(dirnoslash, &filestat) == 0)
return 1;
return 0;
}
int32_t FSUtils::CreateSubfolder(const char *fullpath) {
if (!fullpath)
return 0;
int32_t result = 0;
char dirnoslash[strlen(fullpath) + 1];
strcpy(dirnoslash, fullpath);
int32_t pos = strlen(dirnoslash) - 1;
while (dirnoslash[pos] == '/') {
dirnoslash[pos] = '\0';
pos--;
}
if (CheckFile(dirnoslash)) {
return 1;
} else {
char parentpath[strlen(dirnoslash) + 2];
strcpy(parentpath, dirnoslash);
char *ptr = strrchr(parentpath, '/');
if (!ptr) {
//!Device root directory (must be with '/')
strcat(parentpath, "/");
struct stat filestat;
if (stat(parentpath, &filestat) == 0)
return 1;
return 0;
}
ptr++;
ptr[0] = '\0';
result = CreateSubfolder(parentpath);
}
if (!result)
return 0;
if (mkdir(dirnoslash, 0777) == -1) {
return 0;
}
return 1;
}
bool FSUtils::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);
};

60
source/input/Input.h Normal file
View File

@ -0,0 +1,60 @@
#pragma once
#include <cstring>
#include <cstdint>
class Input {
public:
//!Constructor
Input() = default;
//!Destructor
virtual ~Input() = default;
enum eButtons {
BUTTON_NONE = 0x0000,
VPAD_TOUCH = 0x80000000,
BUTTON_Z = 0x20000,
BUTTON_C = 0x10000,
BUTTON_A = 0x8000,
BUTTON_B = 0x4000,
BUTTON_X = 0x2000,
BUTTON_Y = 0x1000,
BUTTON_1 = BUTTON_Y,
BUTTON_2 = BUTTON_X,
BUTTON_LEFT = 0x0800,
BUTTON_RIGHT = 0x0400,
BUTTON_UP = 0x0200,
BUTTON_DOWN = 0x0100,
BUTTON_ZL = 0x0080,
BUTTON_ZR = 0x0040,
BUTTON_L = 0x0020,
BUTTON_R = 0x0010,
BUTTON_PLUS = 0x0008,
BUTTON_MINUS = 0x0004,
BUTTON_HOME = 0x0002,
BUTTON_SYNC = 0x0001,
STICK_R_LEFT = 0x04000000,
STICK_R_RIGHT = 0x02000000,
STICK_R_UP = 0x01000000,
STICK_R_DOWN = 0x00800000,
STICK_L_LEFT = 0x40000000,
STICK_L_RIGHT = 0x20000000,
STICK_L_UP = 0x10000000,
STICK_L_DOWN = 0x08000000
};
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{};
};

59
source/input/VPADInput.h Normal file
View File

@ -0,0 +1,59 @@
#pragma once
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <vpad/input.h>
#include "Input.h"
class VPadInput : public Input {
public:
//!Constructor
VPadInput() {
memset(&vpad, 0, sizeof(vpad));
}
//!Destructor
~VPadInput() override {}
bool update(int32_t width, int32_t height) {
lastData = data;
VPADReadError vpadError = VPAD_READ_NO_SAMPLES;
VPADRead(VPAD_CHAN_0, &vpad, 1, &vpadError);
if (vpadError == VPAD_READ_SUCCESS) {
data.buttons_r = vpad.release;
data.buttons_h = vpad.hold;
data.buttons_d = vpad.trigger;
data.validPointer = !vpad.tpNormal.validity;
data.touched = vpad.tpNormal.touched;
VPADGetTPCalibratedPoint(VPAD_CHAN_0, &tpCalib, &vpad.tpFiltered1);
//! calculate the screen offsets
data.x = -(width >> 1) + (int32_t) (((float) tpCalib.x / 1280.0f) * (float) width);
data.y = -(height >> 1) + (int32_t) (float) height - (((float) tpCalib.y / 720.0f) * (float) height);
return true;
}
return false;
}
private:
VPADStatus vpad{};
VPADTouchData tpCalib{};
};

108
source/main.cpp Normal file
View File

@ -0,0 +1,108 @@
#include <whb/proc.h>
#include <whb/log.h>
#include <whb/log_udp.h>
#include <thread>
#include <iosuhax.h>
#include <ntfs.h>
#include "utils/logger.h"
#include "utils/WiiUScreen.h"
#include "input/VPADInput.h"
#include "ApplicationState.h"
#include "common/common.h"
#include "utils/utils.h"
void initIOSUHax();
void deInitIOSUHax();
void main_loop();
bool sIosuhaxMount = false;
ntfs_md *ntfs_mounts = nullptr;
int ntfs_mount_count = 0;
int main(int argc, char **argv) {
WHBLogUdpInit();
DEBUG_FUNCTION_LINE("Hello from wudump!");
WHBProcInit();
WiiUScreen::Init();
initIOSUHax();
//DEBUG_FUNCTION_LINE("init fat");
//fatInitDefault();
ntfs_mount_count = ntfsMountAll((ntfs_md **) &ntfs_mounts, NTFS_DEFAULT | NTFS_RECOVER);
for (int i = 0; i < ntfs_mount_count; i++) {
DEBUG_FUNCTION_LINE("%s:", ntfs_mounts[i].name);
}
main_loop();
if (ntfs_mounts != nullptr) {
int i = 0;
for (i = 0; i < ntfs_mount_count; i++) {
ntfsUnmount(ntfs_mounts[i].name, true);
}
free(ntfs_mounts);
}
deInitIOSUHax();
WiiUScreen::DeInit();
WHBProcShutdown();
return 0;
}
void main_loop() {
DEBUG_FUNCTION_LINE("Creating state");
ApplicationState state;
VPadInput input;
DEBUG_FUNCTION_LINE();
if (gFSAfd < 0 || !sIosuhaxMount) {
DEBUG_FUNCTION_LINE();
state.setError(ApplicationState::eErrorState::ERROR_IOSUHAX_FAILED);
}
DEBUG_FUNCTION_LINE("Entering main loop");
while (WHBProcIsRunning()) {
input.update(1280, 720);
state.update(&input);
state.render();
}
exit(0);
}
void initIOSUHax() {
sIosuhaxMount = false;
int res = IOSUHAX_Open(nullptr);
if (res < 0) {
DEBUG_FUNCTION_LINE("IOSUHAX_open failed");
} else {
sIosuhaxMount = true;
gFSAfd = IOSUHAX_FSA_Open();
if (gFSAfd < 0) {
DEBUG_FUNCTION_LINE("IOSUHAX_FSA_Open failed");
} else {
}
DEBUG_FUNCTION_LINE("IOSUHAX done");
}
}
void deInitIOSUHax() {
if (sIosuhaxMount) {
if (gFSAfd >= 0) {
IOSUHAX_FSA_Close(gFSAfd);
}
IOSUHAX_Close();
}
}

61
source/utils/FSTUtils.cpp Normal file
View File

@ -0,0 +1,61 @@
#include "FSTUtils.h"
#include "logger.h"
#include <filesystem>
NodeEntry *FSTUtils::getFSTEntryByFullPath(DirectoryEntry *root, std::string &givenFullPath) {
std::string fullPath = givenFullPath;
if (strncmp(fullPath.c_str(), "/", 1) != 0) {
fullPath = "/" + fullPath;
}
DirectoryEntry *pathOpt = root;
std::filesystem::path asPath = fullPath;
std::string dirPath = asPath.parent_path().string();
if (dirPath != "/") {
pathOpt = getFileEntryDir(root, dirPath);
}
if (pathOpt == nullptr) {
return nullptr;
}
for (auto &child: pathOpt->getChildren()) {
if (child->getFullPath() == fullPath) {
return child;
}
}
return nullptr;
}
DirectoryEntry *FSTUtils::getFileEntryDir(DirectoryEntry *curEntry, std::string &string) {
// We add the "/" at the end so we don't get false results when using the "startWith" function.
if (!string.ends_with("/")) {
string += "/";
}
for (auto &curChild: curEntry->getDirChildren()) {
std::string compareTo = curChild->getFullPath();
if (!compareTo.ends_with("/")) {
compareTo += "/";
}
if (string.starts_with(compareTo)) {
if (string == compareTo) {
return curChild;
}
return getFileEntryDir(curChild, string);
}
}
return nullptr;
}
SectionEntry *FSTUtils::getSectionEntryForIndex(FST *pFst, uint16_t index) {
if (pFst == nullptr || pFst->sectionEntries == nullptr) {
return nullptr;
}
for (const auto &entry: pFst->sectionEntries->getSections()) {
if (entry->sectionNumber == index) {
return entry;
}
}
return nullptr;
}

16
source/utils/FSTUtils.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include <string>
#include <WUD/entities/FST/nodeentry/NodeEntry.h>
#include <WUD/entities/FST/nodeentry/DirectoryEntry.h>
#include <WUD/entities/FST/FST.h>
class FSTUtils{
public:
static NodeEntry *getFSTEntryByFullPath(DirectoryEntry *root, std::string &givenFullPath);
static DirectoryEntry *getFileEntryDir(DirectoryEntry *curEntry, std::string &string);
static SectionEntry *getSectionEntryForIndex(FST *pFst, uint16_t index);
};

View File

@ -0,0 +1,48 @@
/****************************************************************************
* Copyright (C) 2018 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <coreinit/screen.h>
#include "ScreenUtils.h"
void ScreenUtils::printTextOnScreen(ConsoleScreenID screen, int x, int y, const char *msg) {
if (!msg) {
return;
}
if (screen != CONSOLE_SCREEN_DRC) { // Draw TV if it's not DRC exclusive.
OSScreenPutFontEx(SCREEN_TV, x, y, msg);
}
if (screen != CONSOLE_SCREEN_TV) { // Draw DRC if it's not TV exclusive.
OSScreenPutFontEx(SCREEN_DRC, x, y, msg);
}
}
void ScreenUtils::OSScreenClear(ConsoleScreenID screen, uint32_t color) {
if (screen != CONSOLE_SCREEN_DRC) { // Clear TV if it's not DRC exclusive.
OSScreenClearBufferEx(SCREEN_TV, color);
}
if (screen != CONSOLE_SCREEN_TV) { // Clear DRC if it's not TV exclusive.
OSScreenClearBufferEx(SCREEN_DRC, color);
}
}
void ScreenUtils::flipBuffers(ConsoleScreenID screen) {
if (screen != CONSOLE_SCREEN_DRC) { // Flip TV buffer if it's not DRC exclusive.
OSScreenFlipBuffersEx(SCREEN_TV);
}
if (screen != CONSOLE_SCREEN_TV) { // Flip DRC buffer if it's not TV exclusive.
OSScreenFlipBuffersEx(SCREEN_DRC);
}
}

View File

@ -0,0 +1,55 @@
/****************************************************************************
* Copyright (C) 2018-2020 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
//! Defines the ID of a display usable with OSScreen.
typedef enum ConsoleScreenID {
//! Represents the TV connected to the system.
CONSOLE_SCREEN_TV = 0,
//! Represents the screen in the DRC (gamepad).
CONSOLE_SCREEN_DRC = 1,
//! Represents both screens
CONSOLE_SCREEN_BOTH = 2,
} ConsoleScreenID;
class ScreenUtils {
public:
/**
Clears the screen for the given screens
\param screen defines on which screens should be printed
\param x defines the x position (character position) where the text should be printed
\param y defines on which line the text should be printed
\param msg C string that contains the text to be printed.
**/
static void printTextOnScreen(ConsoleScreenID screen, int x, int y, const char *msg);
/**
Clears the screen for the given screens
\param screen defines which screens should be cleared
**/
static void OSScreenClear(ConsoleScreenID screen, uint32_t i);
/**
Flips the buffer for the given screens
\param screen defines which screens should be flipped.
**/
static void flipBuffers(ConsoleScreenID screen);
private:
ScreenUtils() = default;
~ScreenUtils() = default;
};

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

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

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

@ -0,0 +1,94 @@
#include "WiiUScreen.h"
#include "ScreenUtils.h"
#include <coreinit/memdefaultheap.h>
#include <cstdarg>
#include <cstdio>
void *WiiUScreen::sBufferTV = nullptr;
void *WiiUScreen::sBufferDRC = nullptr;
uint32_t WiiUScreen::sBufferSizeTV = 0;
uint32_t WiiUScreen::sBufferSizeDRC = 0;
bool WiiUScreen::sConsoleHasForeground = true;
uint32_t WiiUScreen::consoleColor = 0x041F60FF;
uint32_t WiiUScreen::consoleCursorY = 0;
uint32_t WiiUScreen::ProcCallbackAcquired(void *context) {
MEMHeapHandle heap = MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM1);
if (sBufferSizeTV) {
sBufferTV = MEMAllocFromFrmHeapEx(heap, sBufferSizeTV, 4);
}
if (sBufferSizeDRC) {
sBufferDRC = MEMAllocFromFrmHeapEx(heap, sBufferSizeDRC, 4);
}
sConsoleHasForeground = true;
OSScreenSetBufferEx(SCREEN_TV, sBufferTV);
OSScreenSetBufferEx(SCREEN_DRC, sBufferDRC);
return 0;
}
uint32_t WiiUScreen::ProcCallbackReleased(void *context) {
MEMHeapHandle heap = MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM1);
MEMFreeByStateToFrmHeap(heap, CONSOLE_FRAME_HEAP_TAG);
sConsoleHasForeground = FALSE;
return 0;
}
bool WiiUScreen::Init() {
OSScreenInit();
sBufferSizeTV = OSScreenGetBufferSizeEx(SCREEN_TV);
sBufferSizeDRC = OSScreenGetBufferSizeEx(SCREEN_DRC);
WiiUScreen::ProcCallbackAcquired(nullptr);
OSScreenEnableEx(SCREEN_TV, 1);
OSScreenEnableEx(SCREEN_DRC, 1);
ScreenUtils::OSScreenClear(CONSOLE_SCREEN_BOTH, WiiUScreen::consoleColor);
ProcUIRegisterCallback(PROCUI_CALLBACK_ACQUIRE, WiiUScreen::ProcCallbackAcquired, nullptr, 100);
ProcUIRegisterCallback(PROCUI_CALLBACK_RELEASE, WiiUScreen::ProcCallbackReleased, nullptr, 100);
return true;
}
void WiiUScreen::DeInit() {
if (sConsoleHasForeground) {
OSScreenShutdown();
WiiUScreen::ProcCallbackReleased(nullptr);
}
}
void WiiUScreen::drawLinef(const char *fmt, ...) {
char *buf = (char *) MEMAllocFromDefaultHeapEx(PRINTF_BUFFER_LENGTH, 4);
va_list va;
if (!buf) {
return;
}
va_start(va, fmt);
vsnprintf(buf, PRINTF_BUFFER_LENGTH, fmt, va);
WiiUScreen::drawLine(buf);
MEMFreeToDefaultHeap(buf);
va_end(va);
}
void WiiUScreen::drawLine() {
WiiUScreen::drawLine("");
}
void WiiUScreen::drawLine(const char *msg) {
ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_BOTH, 0, consoleCursorY++, msg);
}
void WiiUScreen::flipBuffers() {
ScreenUtils::flipBuffers(CONSOLE_SCREEN_BOTH);
}
void WiiUScreen::clearScreen() {
ScreenUtils::OSScreenClear(CONSOLE_SCREEN_BOTH, WiiUScreen::consoleColor);
consoleCursorY = 0;
}

53
source/utils/WiiUScreen.h Normal file
View File

@ -0,0 +1,53 @@
#pragma once
#include <whb/log.h>
#include <whb/log_console.h>
#include <coreinit/memheap.h>
#include <coreinit/cache.h>
#include <coreinit/memfrmheap.h>
#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 {
public:
static uint32_t ProcCallbackAcquired(void *context);
static uint32_t ProcCallbackReleased(void *context);
static bool Init();
static void DeInit();
static void drawLinef(const char *fmt, ...);
static void drawLine(const char *fmt);
static void drawLine();
static void flipBuffers();
static void clearScreen();
private:
static void *sBufferTV, *sBufferDRC;
static uint32_t sBufferSizeTV, sBufferSizeDRC;
static bool sConsoleHasForeground;
static uint32_t consoleColor;
static uint32_t consoleCursorY;
};

View File

@ -0,0 +1,36 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
#include "BlockSize.h"
class AddressInBlocks {
public:
explicit AddressInBlocks(const BlockSize &blockSize, uint32_t pValue) : blockSize(blockSize) {
value = pValue;
}
AddressInBlocks() = default;
[[nodiscard]] virtual uint64_t getAddressInBytes() const {
return (uint64_t) value * blockSize.blockSize;
}
BlockSize blockSize;
uint32_t value{};
};

View File

@ -0,0 +1,41 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
#include "AddressInBlocks.h"
#include "DiscBlockSize.h"
#include <functional>
#include <iostream>
class AddressInDiscBlocks : public AddressInBlocks {
public:
AddressInDiscBlocks(const DiscBlockSize &blockSize, uint32_t value) : AddressInBlocks(blockSize, value) {
}
};
namespace std {
template<>
struct less<AddressInDiscBlocks> {
bool operator()(const AddressInDiscBlocks &lhs, const AddressInDiscBlocks &rhs) const {
return lhs.getAddressInBytes() < rhs.getAddressInBytes();
}
};
}

View File

@ -0,0 +1,28 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include "VolumeBlockSize.h"
#include "AddressInBlocks.h"
class AddressInVolumeBlocks : public AddressInBlocks {
public:
AddressInVolumeBlocks() = default;
AddressInVolumeBlocks(const VolumeBlockSize &pBlockSize, uint32_t pValue) : AddressInBlocks(pBlockSize, pValue) {
}
};

View File

@ -0,0 +1,30 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
class BlockSize {
public:
BlockSize() = default;
explicit BlockSize(uint32_t blockSize) {
this->blockSize = blockSize;
}
uint32_t blockSize {};
};

View File

@ -0,0 +1,29 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include "utils/logger.h"
#include "BlockSize.h"
class DiscBlockSize : public BlockSize {
public:
DiscBlockSize() = default;
explicit DiscBlockSize(uint32_t blockSize) : BlockSize(blockSize) {
}
};

View File

@ -0,0 +1,27 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include "AddressInBlocks.h"
#include "SectionBlockSize.h"
class SectionAddress : public AddressInBlocks {
public:
SectionAddress(const SectionBlockSize &pBlockSize, uint32_t pValue) : AddressInBlocks(pBlockSize, pValue) {
}
};

View File

@ -0,0 +1,29 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
#include "BlockSize.h"
class SectionBlockSize : public BlockSize {
public:
SectionBlockSize() = default;
explicit SectionBlockSize(uint32_t pBlockSize) : BlockSize(pBlockSize) {
}
};

View File

@ -0,0 +1,37 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <iostream>
#include <type_traits>
#include "BlockSize.h"
class SizeInBlocks {
public:
SizeInBlocks() = default;
explicit SizeInBlocks(const BlockSize &blockSize, uint32_t pValue) : blockSize(blockSize) {
value = pValue;
}
virtual uint64_t getSizeInBytes() {
return (uint64_t) value * blockSize.blockSize;
}
BlockSize blockSize;
uint64_t value{};
};

View File

@ -0,0 +1,14 @@
#pragma once
#include "VolumeBlockSize.h"
#include "SizeInBlocks.h"
class SizeInVolumeBlocks : public SizeInBlocks {
public:
SizeInVolumeBlocks() = default;
SizeInVolumeBlocks(const VolumeBlockSize &blockSize, uint32_t value) : SizeInBlocks(blockSize, value) {
}
};

Some files were not shown because too many files have changed in this diff Show More