mirror of
https://github.com/wiiu-env/wudd.git
synced 2024-11-26 03:34:18 +01:00
First commit
This commit is contained in:
commit
648c0d0fd7
66
.github/workflows/ci.yml
vendored
Normal file
66
.github/workflows/ci.yml
vendored
Normal 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
24
.github/workflows/pr.yml
vendored
Normal 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
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
CMakeLists.txt
|
||||||
|
.idea/
|
||||||
|
build/
|
||||||
|
cmake-build-debug/
|
||||||
|
*.elf
|
||||||
|
*.rpx
|
6
Dockerfile
Normal file
6
Dockerfile
Normal 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
152
Makefile
Normal 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
27
README.md
Normal 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
861
source/ApplicationState.cpp
Normal 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
138
source/ApplicationState.h
Normal 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, ...);
|
||||||
|
};
|
60
source/WUD/DefaultNUSDataProcessor.cpp
Normal file
60
source/WUD/DefaultNUSDataProcessor.cpp
Normal 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;
|
||||||
|
}
|
35
source/WUD/DefaultNUSDataProcessor.h
Normal file
35
source/WUD/DefaultNUSDataProcessor.h
Normal 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
177
source/WUD/DiscReader.cpp
Normal 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
42
source/WUD/DiscReader.h
Normal 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;
|
||||||
|
};
|
97
source/WUD/DiscReaderDiscDrive.cpp
Normal file
97
source/WUD/DiscReaderDiscDrive.cpp
Normal 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 *) §or_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;
|
||||||
|
}
|
34
source/WUD/DiscReaderDiscDrive.h
Normal file
34
source/WUD/DiscReaderDiscDrive.h
Normal 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;
|
||||||
|
};
|
16
source/WUD/NUSDataProcessor.h
Normal file
16
source/WUD/NUSDataProcessor.h
Normal 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;
|
||||||
|
};
|
41
source/WUD/NUSDataProvider.h
Normal file
41
source/WUD/NUSDataProvider.h
Normal 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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
114
source/WUD/NUSDataProviderWUD.cpp
Normal file
114
source/WUD/NUSDataProviderWUD.cpp
Normal 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();
|
||||||
|
}
|
50
source/WUD/NUSDataProviderWUD.h
Normal file
50
source/WUD/NUSDataProviderWUD.h
Normal 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;
|
||||||
|
};
|
26
source/WUD/NUSDecryption.cpp
Normal file
26
source/WUD/NUSDecryption.cpp
Normal 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;
|
||||||
|
}
|
28
source/WUD/NUSDecryption.h
Normal file
28
source/WUD/NUSDecryption.h
Normal 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
83
source/WUD/NUSTitle.cpp
Normal 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
48
source/WUD/NUSTitle.h
Normal 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
33
source/WUD/Ticket.cpp
Normal 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
29
source/WUD/Ticket.h
Normal 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]{};
|
||||||
|
};
|
37
source/WUD/content/WiiUContentsInformation.cpp
Normal file
37
source/WUD/content/WiiUContentsInformation.cpp
Normal 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;
|
||||||
|
}
|
35
source/WUD/content/WiiUContentsInformation.h
Normal file
35
source/WUD/content/WiiUContentsInformation.h
Normal 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;
|
||||||
|
};
|
44
source/WUD/content/WiiUDiscContentsHeader.cpp
Normal file
44
source/WUD/content/WiiUDiscContentsHeader.cpp
Normal 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);
|
||||||
|
}
|
36
source/WUD/content/WiiUDiscContentsHeader.h
Normal file
36
source/WUD/content/WiiUDiscContentsHeader.h
Normal 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;
|
||||||
|
};
|
43
source/WUD/content/partitions/WiiUDataPartition.cpp
Normal file
43
source/WUD/content/partitions/WiiUDataPartition.cpp
Normal 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();
|
||||||
|
}
|
46
source/WUD/content/partitions/WiiUDataPartition.h
Normal file
46
source/WUD/content/partitions/WiiUDataPartition.h
Normal 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;
|
||||||
|
};
|
||||||
|
|
50
source/WUD/content/partitions/WiiUGMPartition.cpp
Normal file
50
source/WUD/content/partitions/WiiUGMPartition.cpp
Normal 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();
|
||||||
|
}
|
47
source/WUD/content/partitions/WiiUGMPartition.h
Normal file
47
source/WUD/content/partitions/WiiUGMPartition.h
Normal 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;
|
||||||
|
};
|
||||||
|
|
79
source/WUD/content/partitions/WiiUPartition.cpp
Normal file
79
source/WUD/content/partitions/WiiUPartition.cpp
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
51
source/WUD/content/partitions/WiiUPartition.h
Normal file
51
source/WUD/content/partitions/WiiUPartition.h
Normal 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;
|
||||||
|
};
|
181
source/WUD/content/partitions/WiiUPartitions.cpp
Normal file
181
source/WUD/content/partitions/WiiUPartitions.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
|
42
source/WUD/content/partitions/WiiUPartitions.h
Normal file
42
source/WUD/content/partitions/WiiUPartitions.h
Normal 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;
|
||||||
|
|
||||||
|
};
|
37
source/WUD/content/partitions/volumes/H3HashArray.cpp
Normal file
37
source/WUD/content/partitions/volumes/H3HashArray.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
31
source/WUD/content/partitions/volumes/H3HashArray.h
Normal file
31
source/WUD/content/partitions/volumes/H3HashArray.h
Normal 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;
|
||||||
|
};
|
94
source/WUD/content/partitions/volumes/VolumeHeader.cpp
Normal file
94
source/WUD/content/partitions/volumes/VolumeHeader.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
50
source/WUD/content/partitions/volumes/VolumeHeader.h
Normal file
50
source/WUD/content/partitions/volumes/VolumeHeader.h
Normal 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;
|
||||||
|
};
|
47
source/WUD/entities/FST/FST.cpp
Normal file
47
source/WUD/entities/FST/FST.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
|
39
source/WUD/entities/FST/FST.h
Normal file
39
source/WUD/entities/FST/FST.h
Normal 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;
|
||||||
|
};
|
30
source/WUD/entities/FST/header/FSTHeader.cpp
Normal file
30
source/WUD/entities/FST/header/FSTHeader.cpp
Normal 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];
|
||||||
|
}
|
35
source/WUD/entities/FST/header/FSTHeader.h
Normal file
35
source/WUD/entities/FST/header/FSTHeader.h
Normal 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;
|
||||||
|
|
||||||
|
};
|
82
source/WUD/entities/FST/nodeentry/DirectoryEntry.cpp
Normal file
82
source/WUD/entities/FST/nodeentry/DirectoryEntry.cpp
Normal 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);
|
||||||
|
}
|
46
source/WUD/entities/FST/nodeentry/DirectoryEntry.h
Normal file
46
source/WUD/entities/FST/nodeentry/DirectoryEntry.h
Normal 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;
|
||||||
|
};
|
56
source/WUD/entities/FST/nodeentry/FileEntry.cpp
Normal file
56
source/WUD/entities/FST/nodeentry/FileEntry.cpp
Normal 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;
|
||||||
|
}
|
41
source/WUD/entities/FST/nodeentry/FileEntry.h
Normal file
41
source/WUD/entities/FST/nodeentry/FileEntry.h
Normal 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{};
|
||||||
|
};
|
57
source/WUD/entities/FST/nodeentry/NodeEntries.cpp
Normal file
57
source/WUD/entities/FST/nodeentry/NodeEntries.cpp
Normal 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;
|
||||||
|
}
|
40
source/WUD/entities/FST/nodeentry/NodeEntries.h
Normal file
40
source/WUD/entities/FST/nodeentry/NodeEntries.h
Normal 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;
|
||||||
|
};
|
83
source/WUD/entities/FST/nodeentry/NodeEntry.cpp
Normal file
83
source/WUD/entities/FST/nodeentry/NodeEntry.cpp
Normal 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;
|
||||||
|
}
|
65
source/WUD/entities/FST/nodeentry/NodeEntry.h
Normal file
65
source/WUD/entities/FST/nodeentry/NodeEntry.h
Normal 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 &;
|
||||||
|
};
|
30
source/WUD/entities/FST/nodeentry/NodeEntryParam.h
Normal file
30
source/WUD/entities/FST/nodeentry/NodeEntryParam.h
Normal 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;
|
||||||
|
};
|
45
source/WUD/entities/FST/nodeentry/RootEntry.cpp
Normal file
45
source/WUD/entities/FST/nodeentry/RootEntry.cpp
Normal 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));
|
||||||
|
}
|
36
source/WUD/entities/FST/nodeentry/RootEntry.h
Normal file
36
source/WUD/entities/FST/nodeentry/RootEntry.h
Normal 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);
|
||||||
|
};
|
40
source/WUD/entities/FST/sectionentry/SectionEntries.cpp
Normal file
40
source/WUD/entities/FST/sectionentry/SectionEntries.cpp
Normal 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();
|
||||||
|
}
|
41
source/WUD/entities/FST/sectionentry/SectionEntries.h
Normal file
41
source/WUD/entities/FST/sectionentry/SectionEntries.h
Normal 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;
|
||||||
|
};
|
32
source/WUD/entities/FST/sectionentry/SectionEntry.cpp
Normal file
32
source/WUD/entities/FST/sectionentry/SectionEntry.cpp
Normal 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;
|
||||||
|
}
|
37
source/WUD/entities/FST/sectionentry/SectionEntry.h
Normal file
37
source/WUD/entities/FST/sectionentry/SectionEntry.h
Normal 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;
|
||||||
|
};
|
27
source/WUD/entities/FST/stringtable/StringEntry.cpp
Normal file
27
source/WUD/entities/FST/stringtable/StringEntry.cpp
Normal 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;
|
||||||
|
}
|
33
source/WUD/entities/FST/stringtable/StringEntry.h
Normal file
33
source/WUD/entities/FST/stringtable/StringEntry.h
Normal 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;
|
||||||
|
};
|
71
source/WUD/entities/FST/stringtable/StringTable.cpp
Normal file
71
source/WUD/entities/FST/stringtable/StringTable.cpp
Normal 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;
|
||||||
|
}
|
47
source/WUD/entities/FST/stringtable/StringTable.h
Normal file
47
source/WUD/entities/FST/stringtable/StringTable.h
Normal 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;
|
||||||
|
};
|
28
source/WUD/entities/TMD/Content.cpp
Normal file
28
source/WUD/entities/TMD/Content.cpp
Normal 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);
|
||||||
|
}
|
32
source/WUD/entities/TMD/Content.h
Normal file
32
source/WUD/entities/TMD/Content.h
Normal 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]{};
|
||||||
|
};
|
42
source/WUD/entities/TMD/TitleMetaData.cpp
Normal file
42
source/WUD/entities/TMD/TitleMetaData.cpp
Normal 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;
|
||||||
|
}
|
35
source/WUD/entities/TMD/TitleMetaData.h
Normal file
35
source/WUD/entities/TMD/TitleMetaData.h
Normal 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;
|
||||||
|
};
|
40
source/WUD/header/WiiUDiscHeader.cpp
Normal file
40
source/WUD/header/WiiUDiscHeader.cpp
Normal 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;
|
||||||
|
}
|
37
source/WUD/header/WiiUDiscHeader.h
Normal file
37
source/WUD/header/WiiUDiscHeader.h
Normal 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();
|
||||||
|
};
|
43
source/WUD/header/WiiUDiscID.cpp
Normal file
43
source/WUD/header/WiiUDiscID.cpp
Normal 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);
|
||||||
|
}
|
32
source/WUD/header/WiiUDiscID.h
Normal file
32
source/WUD/header/WiiUDiscID.h
Normal 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;
|
||||||
|
};
|
26
source/WUD/header/WiiUManufactorDiscID.cpp
Normal file
26
source/WUD/header/WiiUManufactorDiscID.cpp
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
30
source/WUD/header/WiiUManufactorDiscID.h
Normal file
30
source/WUD/header/WiiUManufactorDiscID.h
Normal 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
3
source/common/common.cpp
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
int32_t gFSAfd = -1;
|
5
source/common/common.h
Normal file
5
source/common/common.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
extern int32_t gFSAfd;
|
173
source/fs/CFile.cpp
Normal file
173
source/fs/CFile.cpp
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include "CFile.hpp"
|
||||||
|
|
||||||
|
CFile::CFile() {
|
||||||
|
iFd = -1;
|
||||||
|
mem_file = NULL;
|
||||||
|
filesize = 0;
|
||||||
|
pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFile::CFile(const std::string &filepath, eOpenTypes mode) {
|
||||||
|
iFd = -1;
|
||||||
|
this->open(filepath, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFile::CFile(const uint8_t *mem, int32_t size) {
|
||||||
|
iFd = -1;
|
||||||
|
this->open(mem, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFile::~CFile() {
|
||||||
|
this->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t CFile::open(const std::string &filepath, eOpenTypes mode) {
|
||||||
|
this->close();
|
||||||
|
int32_t openMode = 0;
|
||||||
|
|
||||||
|
// This depend on the devoptab implementation.
|
||||||
|
// see https://github.com/devkitPro/wut/blob/master/libraries/wutdevoptab/devoptab_fs_open.c#L21 fpr reference
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
default:
|
||||||
|
case ReadOnly: // file must exist
|
||||||
|
openMode = O_RDONLY;
|
||||||
|
break;
|
||||||
|
case WriteOnly: // file will be created / zerod
|
||||||
|
openMode = O_TRUNC | O_CREAT | O_WRONLY;
|
||||||
|
break;
|
||||||
|
case ReadWrite: // file must exist
|
||||||
|
openMode = O_RDWR;
|
||||||
|
break;
|
||||||
|
case Append: // append to file, file will be created if missing. write only
|
||||||
|
openMode = O_CREAT | O_APPEND | O_WRONLY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Using fopen works only on the first launch as expected
|
||||||
|
//! on the second launch it causes issues because we don't overwrite
|
||||||
|
//! the .data sections which is needed for a normal application to re-init
|
||||||
|
//! this will be added with launching as RPX
|
||||||
|
iFd = ::open(filepath.c_str(), openMode);
|
||||||
|
if (iFd < 0)
|
||||||
|
return iFd;
|
||||||
|
|
||||||
|
|
||||||
|
filesize = ::lseek(iFd, 0, SEEK_END);
|
||||||
|
::lseek(iFd, 0, SEEK_SET);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t CFile::open(const uint8_t *mem, int32_t size) {
|
||||||
|
this->close();
|
||||||
|
|
||||||
|
mem_file = mem;
|
||||||
|
filesize = size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFile::close() {
|
||||||
|
if (iFd >= 0)
|
||||||
|
::close(iFd);
|
||||||
|
|
||||||
|
iFd = -1;
|
||||||
|
mem_file = NULL;
|
||||||
|
filesize = 0;
|
||||||
|
pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t CFile::read(uint8_t *ptr, size_t size) {
|
||||||
|
if (iFd >= 0) {
|
||||||
|
int32_t ret = ::read(iFd, ptr, size);
|
||||||
|
if (ret > 0)
|
||||||
|
pos += ret;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t readsize = size;
|
||||||
|
|
||||||
|
if (readsize > (int64_t) (filesize - pos))
|
||||||
|
readsize = filesize - pos;
|
||||||
|
|
||||||
|
if (readsize <= 0)
|
||||||
|
return readsize;
|
||||||
|
|
||||||
|
if (mem_file != NULL) {
|
||||||
|
memcpy(ptr, mem_file + pos, readsize);
|
||||||
|
pos += readsize;
|
||||||
|
return readsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t CFile::write(const uint8_t *ptr, size_t size) {
|
||||||
|
if (iFd >= 0) {
|
||||||
|
size_t done = 0;
|
||||||
|
while (done < size) {
|
||||||
|
int32_t ret = ::write(iFd, ptr, size - done);
|
||||||
|
if (ret <= 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ptr += ret;
|
||||||
|
done += ret;
|
||||||
|
pos += ret;
|
||||||
|
}
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t CFile::seek(long int offset, int32_t origin) {
|
||||||
|
int32_t ret = 0;
|
||||||
|
int64_t newPos = pos;
|
||||||
|
|
||||||
|
if (origin == SEEK_SET) {
|
||||||
|
newPos = offset;
|
||||||
|
} else if (origin == SEEK_CUR) {
|
||||||
|
newPos += offset;
|
||||||
|
} else if (origin == SEEK_END) {
|
||||||
|
newPos = filesize + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newPos < 0) {
|
||||||
|
pos = 0;
|
||||||
|
} else {
|
||||||
|
pos = newPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iFd >= 0)
|
||||||
|
ret = ::lseek(iFd, pos, SEEK_SET);
|
||||||
|
|
||||||
|
if (mem_file != NULL) {
|
||||||
|
if (pos > filesize) {
|
||||||
|
pos = filesize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t CFile::fwrite(const char *format, ...) {
|
||||||
|
char tmp[512];
|
||||||
|
tmp[0] = 0;
|
||||||
|
int32_t result = -1;
|
||||||
|
|
||||||
|
va_list va;
|
||||||
|
va_start(va, format);
|
||||||
|
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||||
|
result = this->write((uint8_t *) tmp, strlen(tmp));
|
||||||
|
}
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
71
source/fs/CFile.hpp
Normal file
71
source/fs/CFile.hpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#ifndef CFILE_HPP_
|
||||||
|
#define CFILE_HPP_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <wut_types.h>
|
||||||
|
|
||||||
|
class CFile {
|
||||||
|
public:
|
||||||
|
enum eOpenTypes {
|
||||||
|
ReadOnly,
|
||||||
|
WriteOnly,
|
||||||
|
ReadWrite,
|
||||||
|
Append
|
||||||
|
};
|
||||||
|
|
||||||
|
CFile();
|
||||||
|
|
||||||
|
CFile(const std::string &filepath, eOpenTypes mode);
|
||||||
|
|
||||||
|
CFile(const uint8_t *memory, int32_t memsize);
|
||||||
|
|
||||||
|
virtual ~CFile();
|
||||||
|
|
||||||
|
int32_t open(const std::string &filepath, eOpenTypes mode);
|
||||||
|
|
||||||
|
int32_t open(const uint8_t *memory, int32_t memsize);
|
||||||
|
|
||||||
|
BOOL isOpen() const {
|
||||||
|
if (iFd >= 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (mem_file)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void close();
|
||||||
|
|
||||||
|
int32_t read(uint8_t *ptr, size_t size);
|
||||||
|
|
||||||
|
int32_t write(const uint8_t *ptr, size_t size);
|
||||||
|
|
||||||
|
int32_t fwrite(const char *format, ...);
|
||||||
|
|
||||||
|
int32_t seek(long int offset, int32_t origin);
|
||||||
|
|
||||||
|
uint64_t tell() {
|
||||||
|
return pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint64_t size() {
|
||||||
|
return filesize;
|
||||||
|
};
|
||||||
|
|
||||||
|
void rewind() {
|
||||||
|
this->seek(0, SEEK_SET);
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int32_t iFd;
|
||||||
|
const uint8_t *mem_file;
|
||||||
|
uint64_t filesize;
|
||||||
|
uint64_t pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
174
source/fs/FSUtils.cpp
Normal file
174
source/fs/FSUtils.cpp
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
#include <malloc.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include "FSUtils.h"
|
||||||
|
#include "CFile.hpp"
|
||||||
|
#include "utils/logger.h"
|
||||||
|
|
||||||
|
int32_t FSUtils::LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size) {
|
||||||
|
//! always initialze input
|
||||||
|
*inbuffer = 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
17
source/fs/FSUtils.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <wut_types.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class FSUtils {
|
||||||
|
public:
|
||||||
|
static int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size);
|
||||||
|
|
||||||
|
static int32_t CreateSubfolder(const char *fullpath);
|
||||||
|
|
||||||
|
static int32_t CheckFile(const char *filepath);
|
||||||
|
|
||||||
|
static bool copyFile(const std::string &in, const std::string &out);
|
||||||
|
|
||||||
|
static int32_t saveBufferToFile(const char *path, void *buffer, uint32_t size);
|
||||||
|
};
|
60
source/input/Input.h
Normal file
60
source/input/Input.h
Normal 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
59
source/input/VPADInput.h
Normal 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
108
source/main.cpp
Normal 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
61
source/utils/FSTUtils.cpp
Normal 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
16
source/utils/FSTUtils.h
Normal 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);
|
||||||
|
};
|
||||||
|
|
48
source/utils/ScreenUtils.cpp
Normal file
48
source/utils/ScreenUtils.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
55
source/utils/ScreenUtils.h
Normal file
55
source/utils/ScreenUtils.h
Normal 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;
|
||||||
|
};
|
234
source/utils/StringTools.cpp
Normal file
234
source/utils/StringTools.cpp
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2010
|
||||||
|
* by Dimok
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any
|
||||||
|
* damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any
|
||||||
|
* purpose, including commercial applications, and to alter it and
|
||||||
|
* redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you
|
||||||
|
* must not claim that you wrote the original software. If you use
|
||||||
|
* this software in a product, an acknowledgment in the product
|
||||||
|
* documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and
|
||||||
|
* must not be misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* for WiiXplorer 2010
|
||||||
|
***************************************************************************/
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <wut_types.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "StringTools.h"
|
||||||
|
|
||||||
|
|
||||||
|
BOOL StringTools::EndsWith(const std::string &a, const std::string &b) {
|
||||||
|
if (b.size() > a.size())
|
||||||
|
return false;
|
||||||
|
return std::equal(a.begin() + a.size() - b.size(), a.end(), b.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *StringTools::byte_to_binary(int32_t x) {
|
||||||
|
static char b[9];
|
||||||
|
b[0] = '\0';
|
||||||
|
|
||||||
|
int32_t z;
|
||||||
|
for (z = 128; z > 0; z >>= 1) {
|
||||||
|
strcat(b, ((x & z) == z) ? "1" : "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string StringTools::removeCharFromString(std::string &input, char toBeRemoved) {
|
||||||
|
std::string output = input;
|
||||||
|
size_t position;
|
||||||
|
while (1) {
|
||||||
|
position = output.find(toBeRemoved);
|
||||||
|
if (position == std::string::npos)
|
||||||
|
break;
|
||||||
|
output.erase(position, 1);
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *StringTools::fmt(const char *format, ...) {
|
||||||
|
static char strChar[512];
|
||||||
|
strChar[0] = 0;
|
||||||
|
|
||||||
|
va_list va;
|
||||||
|
va_start(va, format);
|
||||||
|
if ((vsprintf(strChar, format, va) >= 0)) {
|
||||||
|
va_end(va);
|
||||||
|
return (const char *) strChar;
|
||||||
|
}
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wchar_t *StringTools::wfmt(const char *format, ...) {
|
||||||
|
static char tmp[512];
|
||||||
|
static wchar_t strWChar[512];
|
||||||
|
strWChar[0] = 0;
|
||||||
|
tmp[0] = 0;
|
||||||
|
|
||||||
|
if (!format)
|
||||||
|
return (const wchar_t *) strWChar;
|
||||||
|
|
||||||
|
if (strcmp(format, "") == 0)
|
||||||
|
return (const wchar_t *) strWChar;
|
||||||
|
|
||||||
|
va_list va;
|
||||||
|
va_start(va, format);
|
||||||
|
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||||
|
int32_t bt;
|
||||||
|
int32_t strlength = strlen(tmp);
|
||||||
|
bt = mbstowcs(strWChar, tmp, (strlength < 512) ? strlength : 512);
|
||||||
|
|
||||||
|
if (bt > 0) {
|
||||||
|
strWChar[bt] = 0;
|
||||||
|
return (const wchar_t *) strWChar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t StringTools::strprintf(std::string &str, const char *format, ...) {
|
||||||
|
static char tmp[512];
|
||||||
|
tmp[0] = 0;
|
||||||
|
int32_t result = 0;
|
||||||
|
|
||||||
|
va_list va;
|
||||||
|
va_start(va, format);
|
||||||
|
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||||
|
str = tmp;
|
||||||
|
result = str.size();
|
||||||
|
}
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string StringTools::strfmt(const char *format, ...) {
|
||||||
|
std::string str;
|
||||||
|
static char tmp[512];
|
||||||
|
tmp[0] = 0;
|
||||||
|
|
||||||
|
va_list va;
|
||||||
|
va_start(va, format);
|
||||||
|
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||||
|
str = tmp;
|
||||||
|
}
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL StringTools::char2wchar_t(const char *strChar, wchar_t *dest) {
|
||||||
|
if (!strChar || !dest)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int32_t bt;
|
||||||
|
bt = mbstowcs(dest, strChar, strlen(strChar));
|
||||||
|
if (bt > 0) {
|
||||||
|
dest[bt] = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t StringTools::strtokcmp(const char *string, const char *compare, const char *separator) {
|
||||||
|
if (!string || !compare)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
char TokCopy[512];
|
||||||
|
strncpy(TokCopy, compare, sizeof(TokCopy));
|
||||||
|
TokCopy[511] = '\0';
|
||||||
|
|
||||||
|
char *strTok = strtok(TokCopy, separator);
|
||||||
|
|
||||||
|
while (strTok != NULL) {
|
||||||
|
if (strcasecmp(string, strTok) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
strTok = strtok(NULL, separator);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t StringTools::strextcmp(const char *string, const char *extension, char seperator) {
|
||||||
|
if (!string || !extension)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
char *ptr = strrchr(string, seperator);
|
||||||
|
if (!ptr)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return strcasecmp(ptr + 1, extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<std::string> StringTools::stringSplit(const std::string &inValue, const std::string &splitter) {
|
||||||
|
std::string value = inValue;
|
||||||
|
std::vector<std::string> result;
|
||||||
|
while (true) {
|
||||||
|
uint32_t index = value.find(splitter);
|
||||||
|
if (index == std::string::npos) {
|
||||||
|
result.push_back(value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::string first = value.substr(0, index);
|
||||||
|
result.push_back(first);
|
||||||
|
if (index + splitter.size() == value.length()) {
|
||||||
|
result.push_back("");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (index + splitter.size() > value.length()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
value = value.substr(index + splitter.size(), value.length());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StringTools::findStringIC(const std::string &strHaystack, const std::string &strNeedle) {
|
||||||
|
auto it = std::search(
|
||||||
|
strHaystack.begin(), strHaystack.end(),
|
||||||
|
strNeedle.begin(), strNeedle.end(),
|
||||||
|
[](char ch1, char ch2) { return std::toupper(ch1) == std::toupper(ch2); }
|
||||||
|
);
|
||||||
|
return (it != strHaystack.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StringTools::replace(std::string &str, const std::string &from, const std::string &to) {
|
||||||
|
size_t start_pos = str.find(from);
|
||||||
|
if (start_pos == std::string::npos) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
str.replace(start_pos, from.length(), to);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool StringTools::strCompareIC(const std::string &str1, const std::string &str2) {
|
||||||
|
return str1.size() == str2.size() && std::equal(str1.begin(), str1.end(), str2.begin(), [](auto a, auto b) { return std::tolower(a) == std::tolower(b); });
|
||||||
|
}
|
95
source/utils/StringTools.h
Normal file
95
source/utils/StringTools.h
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2010
|
||||||
|
* by Dimok
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any
|
||||||
|
* damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any
|
||||||
|
* purpose, including commercial applications, and to alter it and
|
||||||
|
* redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you
|
||||||
|
* must not claim that you wrote the original software. If you use
|
||||||
|
* this software in a product, an acknowledgment in the product
|
||||||
|
* documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and
|
||||||
|
* must not be misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* for WiiXplorer 2010
|
||||||
|
***************************************************************************/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <wut_types.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
|
class StringTools {
|
||||||
|
public:
|
||||||
|
static BOOL EndsWith(const std::string &a, const std::string &b);
|
||||||
|
|
||||||
|
static const char *byte_to_binary(int32_t x);
|
||||||
|
|
||||||
|
static std::string removeCharFromString(std::string &input, char toBeRemoved);
|
||||||
|
|
||||||
|
static const char *fmt(const char *format, ...);
|
||||||
|
|
||||||
|
static const wchar_t *wfmt(const char *format, ...);
|
||||||
|
|
||||||
|
static int32_t strprintf(std::string &str, const char *format, ...);
|
||||||
|
|
||||||
|
static std::string strfmt(const char *format, ...);
|
||||||
|
|
||||||
|
static BOOL char2wchar_t(const char *src, wchar_t *dest);
|
||||||
|
|
||||||
|
static int32_t strtokcmp(const char *string, const char *compare, const char *separator);
|
||||||
|
|
||||||
|
static int32_t strextcmp(const char *string, const char *extension, char seperator);
|
||||||
|
|
||||||
|
static const char *FullpathToFilename(const char *path) {
|
||||||
|
if (!path)
|
||||||
|
return path;
|
||||||
|
|
||||||
|
const char *ptr = path;
|
||||||
|
const char *Filename = ptr;
|
||||||
|
|
||||||
|
while (*ptr != '\0') {
|
||||||
|
if (ptr[0] == '/' && ptr[1] != '\0')
|
||||||
|
Filename = ptr + 1;
|
||||||
|
|
||||||
|
++ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RemoveDoubleSlashs(std::string &str) {
|
||||||
|
uint32_t length = str.size();
|
||||||
|
|
||||||
|
//! clear path of double slashes
|
||||||
|
for (uint32_t i = 1; i < length; ++i) {
|
||||||
|
if (str[i - 1] == '/' && str[i] == '/') {
|
||||||
|
str.erase(i, 1);
|
||||||
|
i--;
|
||||||
|
length--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> stringSplit(const std::string &value, const std::string &splitter);
|
||||||
|
|
||||||
|
// https://stackoverflow.com/a/19839371
|
||||||
|
static bool findStringIC(const std::string &strHaystack, const std::string &strNeedle);
|
||||||
|
|
||||||
|
// https://stackoverflow.com/a/3418285
|
||||||
|
static bool replace(std::string& str, const std::string& from, const std::string& to);
|
||||||
|
|
||||||
|
static bool strCompareIC(const std::string &str1, const std::string &str2);
|
||||||
|
};
|
196
source/utils/TinySHA1.hpp
Normal file
196
source/utils/TinySHA1.hpp
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* TinySHA1 - a header only implementation of the SHA1 algorithm in C++. Based
|
||||||
|
* on the implementation in boost::uuid::details.
|
||||||
|
*
|
||||||
|
* SHA1 Wikipedia Page: http://en.wikipedia.org/wiki/SHA-1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012-22 SAURAV MOHAPATRA <mohaps@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef _TINY_SHA1_HPP_
|
||||||
|
#define _TINY_SHA1_HPP_
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <stdint.h>
|
||||||
|
namespace sha1
|
||||||
|
{
|
||||||
|
class SHA1
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef uint32_t digest32_t[5];
|
||||||
|
typedef uint8_t digest8_t[20];
|
||||||
|
inline static uint32_t LeftRotate(uint32_t value, size_t count) {
|
||||||
|
return (value << count) ^ (value >> (32-count));
|
||||||
|
}
|
||||||
|
SHA1(){ reset(); }
|
||||||
|
virtual ~SHA1() {}
|
||||||
|
SHA1(const SHA1& s) { *this = s; }
|
||||||
|
const SHA1& operator = (const SHA1& s) {
|
||||||
|
memcpy(m_digest, s.m_digest, 5 * sizeof(uint32_t));
|
||||||
|
memcpy(m_block, s.m_block, 64);
|
||||||
|
m_blockByteIndex = s.m_blockByteIndex;
|
||||||
|
m_byteCount = s.m_byteCount;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
SHA1& reset() {
|
||||||
|
m_digest[0] = 0x67452301;
|
||||||
|
m_digest[1] = 0xEFCDAB89;
|
||||||
|
m_digest[2] = 0x98BADCFE;
|
||||||
|
m_digest[3] = 0x10325476;
|
||||||
|
m_digest[4] = 0xC3D2E1F0;
|
||||||
|
m_blockByteIndex = 0;
|
||||||
|
m_byteCount = 0;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
SHA1& processByte(uint8_t octet) {
|
||||||
|
this->m_block[this->m_blockByteIndex++] = octet;
|
||||||
|
++this->m_byteCount;
|
||||||
|
if(m_blockByteIndex == 64) {
|
||||||
|
this->m_blockByteIndex = 0;
|
||||||
|
processBlock();
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
SHA1& processBlock(const void* const start, const void* const end) {
|
||||||
|
const uint8_t* begin = static_cast<const uint8_t*>(start);
|
||||||
|
const uint8_t* finish = static_cast<const uint8_t*>(end);
|
||||||
|
while(begin != finish) {
|
||||||
|
processByte(*begin);
|
||||||
|
begin++;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
SHA1& processBytes(const void* const data, size_t len) {
|
||||||
|
const uint8_t* block = static_cast<const uint8_t*>(data);
|
||||||
|
processBlock(block, block + len);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
const uint32_t* getDigest(digest32_t digest) {
|
||||||
|
size_t bitCount = this->m_byteCount * 8;
|
||||||
|
processByte(0x80);
|
||||||
|
if (this->m_blockByteIndex > 56) {
|
||||||
|
while (m_blockByteIndex != 0) {
|
||||||
|
processByte(0);
|
||||||
|
}
|
||||||
|
while (m_blockByteIndex < 56) {
|
||||||
|
processByte(0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (m_blockByteIndex < 56) {
|
||||||
|
processByte(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
processByte(0);
|
||||||
|
processByte(0);
|
||||||
|
processByte(0);
|
||||||
|
processByte(0);
|
||||||
|
processByte( static_cast<unsigned char>((bitCount>>24) & 0xFF));
|
||||||
|
processByte( static_cast<unsigned char>((bitCount>>16) & 0xFF));
|
||||||
|
processByte( static_cast<unsigned char>((bitCount>>8 ) & 0xFF));
|
||||||
|
processByte( static_cast<unsigned char>((bitCount) & 0xFF));
|
||||||
|
|
||||||
|
memcpy(digest, m_digest, 5 * sizeof(uint32_t));
|
||||||
|
return digest;
|
||||||
|
}
|
||||||
|
const uint8_t* getDigestBytes(digest8_t digest) {
|
||||||
|
digest32_t d32;
|
||||||
|
getDigest(d32);
|
||||||
|
size_t di = 0;
|
||||||
|
digest[di++] = ((d32[0] >> 24) & 0xFF);
|
||||||
|
digest[di++] = ((d32[0] >> 16) & 0xFF);
|
||||||
|
digest[di++] = ((d32[0] >> 8) & 0xFF);
|
||||||
|
digest[di++] = ((d32[0]) & 0xFF);
|
||||||
|
|
||||||
|
digest[di++] = ((d32[1] >> 24) & 0xFF);
|
||||||
|
digest[di++] = ((d32[1] >> 16) & 0xFF);
|
||||||
|
digest[di++] = ((d32[1] >> 8) & 0xFF);
|
||||||
|
digest[di++] = ((d32[1]) & 0xFF);
|
||||||
|
|
||||||
|
digest[di++] = ((d32[2] >> 24) & 0xFF);
|
||||||
|
digest[di++] = ((d32[2] >> 16) & 0xFF);
|
||||||
|
digest[di++] = ((d32[2] >> 8) & 0xFF);
|
||||||
|
digest[di++] = ((d32[2]) & 0xFF);
|
||||||
|
|
||||||
|
digest[di++] = ((d32[3] >> 24) & 0xFF);
|
||||||
|
digest[di++] = ((d32[3] >> 16) & 0xFF);
|
||||||
|
digest[di++] = ((d32[3] >> 8) & 0xFF);
|
||||||
|
digest[di++] = ((d32[3]) & 0xFF);
|
||||||
|
|
||||||
|
digest[di++] = ((d32[4] >> 24) & 0xFF);
|
||||||
|
digest[di++] = ((d32[4] >> 16) & 0xFF);
|
||||||
|
digest[di++] = ((d32[4] >> 8) & 0xFF);
|
||||||
|
digest[di++] = ((d32[4]) & 0xFF);
|
||||||
|
return digest;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void processBlock() {
|
||||||
|
uint32_t w[80];
|
||||||
|
for (size_t i = 0; i < 16; i++) {
|
||||||
|
w[i] = (m_block[i*4 + 0] << 24);
|
||||||
|
w[i] |= (m_block[i*4 + 1] << 16);
|
||||||
|
w[i] |= (m_block[i*4 + 2] << 8);
|
||||||
|
w[i] |= (m_block[i*4 + 3]);
|
||||||
|
}
|
||||||
|
for (size_t i = 16; i < 80; i++) {
|
||||||
|
w[i] = LeftRotate((w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t a = m_digest[0];
|
||||||
|
uint32_t b = m_digest[1];
|
||||||
|
uint32_t c = m_digest[2];
|
||||||
|
uint32_t d = m_digest[3];
|
||||||
|
uint32_t e = m_digest[4];
|
||||||
|
|
||||||
|
for (std::size_t i=0; i<80; ++i) {
|
||||||
|
uint32_t f = 0;
|
||||||
|
uint32_t k = 0;
|
||||||
|
|
||||||
|
if (i<20) {
|
||||||
|
f = (b & c) | (~b & d);
|
||||||
|
k = 0x5A827999;
|
||||||
|
} else if (i<40) {
|
||||||
|
f = b ^ c ^ d;
|
||||||
|
k = 0x6ED9EBA1;
|
||||||
|
} else if (i<60) {
|
||||||
|
f = (b & c) | (b & d) | (c & d);
|
||||||
|
k = 0x8F1BBCDC;
|
||||||
|
} else {
|
||||||
|
f = b ^ c ^ d;
|
||||||
|
k = 0xCA62C1D6;
|
||||||
|
}
|
||||||
|
uint32_t temp = LeftRotate(a, 5) + f + e + k + w[i];
|
||||||
|
e = d;
|
||||||
|
d = c;
|
||||||
|
c = LeftRotate(b, 30);
|
||||||
|
b = a;
|
||||||
|
a = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_digest[0] += a;
|
||||||
|
m_digest[1] += b;
|
||||||
|
m_digest[2] += c;
|
||||||
|
m_digest[3] += d;
|
||||||
|
m_digest[4] += e;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
digest32_t m_digest;
|
||||||
|
uint8_t m_block[64];
|
||||||
|
size_t m_blockByteIndex;
|
||||||
|
size_t m_byteCount;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
94
source/utils/WiiUScreen.cpp
Normal file
94
source/utils/WiiUScreen.cpp
Normal 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
53
source/utils/WiiUScreen.h
Normal 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;
|
||||||
|
};
|
36
source/utils/blocksize/AddressInBlocks.h
Normal file
36
source/utils/blocksize/AddressInBlocks.h
Normal 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{};
|
||||||
|
};
|
41
source/utils/blocksize/AddressInDiscBlocks.h
Normal file
41
source/utils/blocksize/AddressInDiscBlocks.h
Normal 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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
28
source/utils/blocksize/AddressInVolumeBlocks.h
Normal file
28
source/utils/blocksize/AddressInVolumeBlocks.h
Normal 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) {
|
||||||
|
}
|
||||||
|
};
|
30
source/utils/blocksize/BlockSize.h
Normal file
30
source/utils/blocksize/BlockSize.h
Normal 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 {};
|
||||||
|
};
|
29
source/utils/blocksize/DiscBlockSize.h
Normal file
29
source/utils/blocksize/DiscBlockSize.h
Normal 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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
27
source/utils/blocksize/SectionAddress.h
Normal file
27
source/utils/blocksize/SectionAddress.h
Normal 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) {
|
||||||
|
}
|
||||||
|
};
|
29
source/utils/blocksize/SectionBlockSize.h
Normal file
29
source/utils/blocksize/SectionBlockSize.h
Normal 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) {
|
||||||
|
}
|
||||||
|
};
|
37
source/utils/blocksize/SizeInBlocks.h
Normal file
37
source/utils/blocksize/SizeInBlocks.h
Normal 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{};
|
||||||
|
};
|
14
source/utils/blocksize/SizeInVolumeBlocks.h
Normal file
14
source/utils/blocksize/SizeInVolumeBlocks.h
Normal 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
Loading…
Reference in New Issue
Block a user