Various improvements including:

- Display name/type of the partition
- Block home menu when launching via HBL
- Use libmocha instead of libiosuhax, which should result in a small performance boost
- Improve logging
- Improve memory management
- Add option to abort dumps
- Slightly improve .wux handling
This commit is contained in:
Maschell 2022-07-26 09:24:06 +02:00
parent 90b6a36add
commit 05aea5756b
74 changed files with 930 additions and 827 deletions

View File

@ -1,6 +1,6 @@
FROM wiiuenv/devkitppc:20220724 FROM wiiuenv/devkitppc:20220724
COPY --from=wiiuenv/libiosuhax:20220523 /artifacts $DEVKITPRO COPY --from=wiiuenv/libntfs:20220726 /artifacts $DEVKITPRO
COPY --from=wiiuenv/libntfs:20201210 /artifacts $DEVKITPRO COPY --from=wiiuenv/libmocha:20220726 /artifacts $DEVKITPRO
WORKDIR project WORKDIR project

View File

@ -51,12 +51,12 @@ SOURCES := source \
source/WUD/entities/TMD source/WUD/entities/TMD
DATA := data DATA := data
INCLUDES := include source INCLUDES := source
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# options for code generation # options for code generation
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
CFLAGS := -g -Wall -O0 -ffunction-sections \ CFLAGS := -g -Wall -O2 -ffunction-sections \
$(MACHDEP) $(MACHDEP)
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
@ -66,7 +66,7 @@ CXXFLAGS := $(CFLAGS) -std=gnu++20
ASFLAGS := -g $(ARCH) ASFLAGS := -g $(ARCH)
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map)
LIBS := -lwut -lntfs -liosuhax LIBS := -lwut -lntfs -lmocha
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level # list of directories containing libraries, this must be the top level
@ -74,6 +74,17 @@ LIBS := -lwut -lntfs -liosuhax
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUT_ROOT)/usr LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUT_ROOT)/usr
ifeq ($(DEBUG),1)
export DEBUG=1
CXXFLAGS += -DDEBUG -g
CFLAGS += -DDEBUG -g
endif
ifeq ($(DEBUG),VERBOSE)
export DEBUG=VERBOSE
CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
endif
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional # no real need to edit anything past this point unless you need to add additional
@ -178,6 +189,8 @@ $(OUTPUT).elf : $(OFILES)
$(OFILES_SRC) : $(HFILES_BIN) $(OFILES_SRC) : $(HFILES_BIN)
-include $(DEPENDS)
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
endif endif
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------

View File

@ -4,7 +4,7 @@ Inspired by [wudump](https://github.com/FIX94/wudump) from FIX94.
Features: Features:
- Dump a Wii U Disc in WUD (uncompressed) or [WUX](https://gbatemp.net/threads/wii-u-image-wud-compression-tool.397901/) (loseless compression) format (including the game.key) - Dump a Wii U Disc in WUD (uncompressed) or [WUX](https://gbatemp.net/threads/wii-u-image-wud-compression-tool.397901/) (loseless compression) format (including the game.key)
- Dump the GM Partitions (Game, Updates, DLCs) of an WiiU Disc as *.app,*.h3, .tmd, .tik, .cert files - Dump the GM Partitions (Game, Updates, DLCs) of an Wii U Disc as *.app,*.h3, .tmd, .tik, .cert files
- Supports dumping to SD (FAT32) and USB (NTFS only). When dumping to SD the files get slitted in 2 GiB parts. - Supports dumping to SD (FAT32) and USB (NTFS only). When dumping to SD the files get slitted in 2 GiB parts.
Files will be dumped to `/wudump/[DISC-ID]/`. The DiscID of a game can be found on the disc (e.g. WUP-P-ARDP for the EUR version of Super Mario 3D World). Files will be dumped to `/wudump/[DISC-ID]/`. The DiscID of a game can be found on the disc (e.g. WUP-P-ARDP for the EUR version of Super Mario 3D World).
@ -14,14 +14,26 @@ Files will be dumped to `/wudump/[DISC-ID]/`. The DiscID of a game can be found
When you dump a .wux or .wud to the SD card it gets splitted into 2 GiB parts (FAT32 limitation). To merge them you can use the `copy` cmd tool. When you dump a .wux or .wud to the SD card it gets splitted into 2 GiB parts (FAT32 limitation). To merge them you can use the `copy` cmd tool.
Example: Example:
`copy /b "game.wux.part1" + "game.wux.part2" "C:\wudump\game.wux"` `copy /b game.wux.part1 + game.wux.part2 game.wux`
## Dependencies ## Dependencies
Requires an [Environment](https://github.com/wiiu-env/EnvironmentLoader) (e.g. Tiramisu or Aroma) with [MochaPayload](https://github.com/wiiu-env/MochaPayload) (Nightly-MochaPayload-20220725-155554 or newer)
- [wut](https://github.com/devkitPro/wut) - [wut](https://github.com/devkitPro/wut)
- [libiosuhax](https://github.com/wiiu-env/libiosuhax) - [libmocha](https://github.com/wiiu-env/libmocha)
- [libntfs](https://github.com/wiiu-env/libntfs) - [libntfs](https://github.com/wiiu-env/libntfs)
## Buildflags
### Logging
Building via `make` only logs errors (via OSReport). To enable logging via the [LoggingModule](https://github.com/wiiu-env/LoggingModule) set `DEBUG` to `1` or `VERBOSE`.
`make` Logs errors only (via OSReport).
`make DEBUG=1` Enables information and error logging via [LoggingModule](https://github.com/wiiu-env/LoggingModule).
`make DEBUG=VERBOSE` Enables verbose information and error logging via [LoggingModule](https://github.com/wiiu-env/LoggingModule).
If the [LoggingModule](https://github.com/wiiu-env/LoggingModule) is not present, it'll fallback to UDP (Port 4405) and [CafeOS](https://github.com/wiiu-env/USBSerialLoggingModule) logging.
## Building using the Dockerfile ## 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. It's possible to use a docker image for building. This way you don't need anything installed on your host system.

View File

@ -26,7 +26,7 @@ public:
this->selectedOptionY++; this->selectedOptionY++;
} }
if (this->selectedOptionY < 0) { if (this->selectedOptionY < 0) {
this->selectedOptionY = maxOptionValue; this->selectedOptionY = maxOptionValue - 1;
} else if (this->selectedOptionY >= maxOptionValue) { } else if (this->selectedOptionY >= maxOptionValue) {
this->selectedOptionY = 0; this->selectedOptionY = 0;
} }
@ -46,6 +46,10 @@ public:
} }
} }
virtual bool buttonPressed(Input *input, Input::eButtons button) {
return input->data.buttons_d & button;
}
virtual bool entrySelected(Input *input) { virtual bool entrySelected(Input *input) {
return input->data.buttons_d & Input::BUTTON_A; return input->data.buttons_d & Input::BUTTON_A;
} }
@ -57,9 +61,13 @@ public:
} }
virtual void printFooter() { virtual void printFooter() {
if (gRunFromHBL) { if (gRunFromHBL && !gBlockHomeButton) {
ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_TV, 0, 25, "Press HOME to exit to HBL"); ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_TV, 0, 25, "Press HOME to exit to HBL");
ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_DRC, 0, 15, "Press HOME to exit to HBL"); ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_DRC, 0, 15, "Press HOME to exit to HBL");
} else if (gRunFromHBL && gBlockHomeButtonCooldown > 0) {
ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_TV, 0, 25, "You can not exit while dumping.");
ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_DRC, 0, 15, "You can not exit while dumping.");
gBlockHomeButtonCooldown--;
} }
ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_TV, 0, 27, "Created by Maschell, inspired by wudump from FIX94"); ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_TV, 0, 27, "Created by Maschell, inspired by wudump from FIX94");
ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_DRC, 0, 17, "Created by Maschell, inspired by wudump from FIX94"); ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_DRC, 0, 17, "Created by Maschell, inspired by wudump from FIX94");

View File

@ -21,8 +21,9 @@
#include <WUD/header/WiiUDiscHeader.h> #include <WUD/header/WiiUDiscHeader.h>
#include <common/common.h> #include <common/common.h>
#include <fs/FSUtils.h> #include <fs/FSUtils.h>
#include <iosuhax.h>
#include <memory> #include <memory>
#include <mocha/fsa.h>
#include <mocha/mocha.h>
#include <utils/StringTools.h> #include <utils/StringTools.h>
#define READ_BUFFER_SIZE (SECTOR_SIZE * 128) #define READ_BUFFER_SIZE (SECTOR_SIZE * 128)
@ -30,6 +31,7 @@
GMPartitionsDumperState::GMPartitionsDumperState(eDumpTarget pTargetDevice) : targetDevice(pTargetDevice) { GMPartitionsDumperState::GMPartitionsDumperState(eDumpTarget pTargetDevice) : targetDevice(pTargetDevice) {
this->sectorBufSize = SECTOR_SIZE; this->sectorBufSize = SECTOR_SIZE;
this->state = STATE_OPEN_ODD1; this->state = STATE_OPEN_ODD1;
gBlockHomeButton = true;
} }
GMPartitionsDumperState::~GMPartitionsDumperState() { GMPartitionsDumperState::~GMPartitionsDumperState() {
@ -37,6 +39,7 @@ GMPartitionsDumperState::~GMPartitionsDumperState() {
this->sectorBuf = nullptr; this->sectorBuf = nullptr;
free(this->readBuffer); free(this->readBuffer);
this->readBuffer = nullptr; this->readBuffer = nullptr;
gBlockHomeButton = false;
} }
void GMPartitionsDumperState::render() { void GMPartitionsDumperState::render() {
@ -73,11 +76,22 @@ void GMPartitionsDumperState::render() {
} else { } else {
uint32_t index = 0; uint32_t index = 0;
for (auto &partitionPair : gmPartitionPairs) { for (auto &partitionPair : gmPartitionPairs) {
uint32_t size = 0; uint64_t size = 0;
for (auto &content : partitionPair.second->tmd->contentList) { for (auto &content : partitionPair.second->tmd->contentList) {
size += ROUNDUP(content->encryptedFileSize, 16); size += ROUNDUP(content->encryptedFileSize, 16);
} }
WiiUScreen::drawLinef("%s %s (~%0.2f MiB)", index == (uint32_t) selectedOptionY ? ">" : " ", partitionPair.first->getVolumeId().c_str(), (float) size / 1024.0f / 1024.0f); std::string titleId = partitionPair.first->getVolumeId().substr(2, 18);
std::string appType = "Other ";
if (titleId.starts_with("00050000")) {
appType = "Game ";
} else if (titleId.starts_with("0005000C")) {
appType = "DLC ";
} else if (titleId.starts_with("0005000E")) {
appType = "Update";
}
WiiUScreen::drawLinef("%s %s - %s (~%0.2f GiB) (%s)", index == (uint32_t) selectedOptionY ? ">" : " ", appType.c_str(),
partitionPair.second->getShortnameEn().c_str(),
(float) ((float) size / 1024.0f / 1024.0f / 1024.0f), titleId.c_str());
index++; index++;
} }
WiiUScreen::drawLine(); WiiUScreen::drawLine();
@ -94,6 +108,8 @@ void GMPartitionsDumperState::render() {
} else if (this->state == STATE_DUMP_PARTITION_CONTENTS) { } else if (this->state == STATE_DUMP_PARTITION_CONTENTS) {
if (curPartition != nullptr) { if (curPartition != nullptr) {
WiiUScreen::drawLinef("Dumping Partition %s", curPartition->getVolumeId().c_str()); WiiUScreen::drawLinef("Dumping Partition %s", curPartition->getVolumeId().c_str());
WiiUScreen::drawLinef("Name: %s", curNUSTitle->getLongnameEn().c_str(), curNUSTitle->tmd->titleId);
WiiUScreen::drawLinef("TitleID: %016llX", curNUSTitle->tmd->titleId);
} else { } else {
WiiUScreen::drawLine("Dumping Partition"); WiiUScreen::drawLine("Dumping Partition");
} }
@ -127,10 +143,22 @@ void GMPartitionsDumperState::render() {
if (size > 0) { if (size > 0) {
WiiUScreen::drawLinef("Progress: %.2f MiB / %.2f MiB (%0.2f%%)", offset / 1024.0f / 1024.0f, WiiUScreen::drawLinef("Progress: %.2f MiB / %.2f MiB (%0.2f%%)", offset / 1024.0f / 1024.0f,
size / 1024.0f / 1024.0f, ((offset * 1.0f) / size) * 100.0f); size / 1024.0f / 1024.0f, ((offset * 1.0f) / size) * 100.0f);
} else {
WiiUScreen::drawLine();
} }
WiiUScreen::drawLine();
WiiUScreen::drawLine("Press B to abort the dumping");
} else if (this->state == STATE_DUMP_DONE) { } else if (this->state == STATE_DUMP_DONE) {
WiiUScreen::drawLine("Dumping done. Press A to return."); WiiUScreen::drawLine("Dumping done. Press A to return.");
} else if (this->state == STATE_ABORT_CONFIRMATION) {
WiiUScreen::drawLinef("Do you really want to abort the disc dumping?");
WiiUScreen::drawLinef("");
if (selectedOptionX == 0) {
WiiUScreen::drawLinef("> Continue dumping Abort dumping");
} else {
WiiUScreen::drawLinef(" Continue dumping > Abort dumping");
}
} }
ApplicationState::printFooter(); ApplicationState::printFooter();
@ -149,17 +177,15 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
} }
if (this->state == STATE_OPEN_ODD1) { if (this->state == STATE_OPEN_ODD1) {
auto ret = IOSUHAX_FSA_RawOpen(gFSAfd, "/dev/odd01", &(this->oddFd)); auto ret = FSAEx_RawOpen(__wut_devoptab_fs_client, "/dev/odd01", &(this->oddFd));
if (ret >= 0) { if (ret >= 0) {
if (this->sectorBuf == nullptr) { if (this->sectorBuf == nullptr) {
this->sectorBuf = (void *) memalign(0x100, this->sectorBufSize); this->sectorBuf = (void *) memalign(0x100, this->sectorBufSize);
if (this->sectorBuf == nullptr) { if (this->sectorBuf == nullptr) {
DEBUG_FUNCTION_LINE("ERROR_MALLOC_FAILED");
this->setError(ERROR_MALLOC_FAILED); this->setError(ERROR_MALLOC_FAILED);
return ApplicationState::SUBSTATE_RUNNING; return ApplicationState::SUBSTATE_RUNNING;
} }
} }
DEBUG_FUNCTION_LINE("Opened /dev/odd01 %d", this->oddFd);
this->state = STATE_READ_DISC_INFO; this->state = STATE_READ_DISC_INFO;
} else { } else {
this->state = STATE_PLEASE_INSERT_DISC; this->state = STATE_PLEASE_INSERT_DISC;
@ -169,7 +195,7 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
return ApplicationState::SUBSTATE_RETURN; return ApplicationState::SUBSTATE_RETURN;
} }
} else if (this->state == STATE_READ_DISC_INFO) { } else if (this->state == STATE_READ_DISC_INFO) {
if (IOSUHAX_FSA_RawRead(gFSAfd, this->sectorBuf, READ_SECTOR_SIZE, 1, 0, this->oddFd) >= 0) { if (FSAEx_RawRead(__wut_devoptab_fs_client, this->sectorBuf, READ_SECTOR_SIZE, 1, 0, this->oddFd) >= 0) {
this->discId[10] = '\0'; this->discId[10] = '\0';
memcpy(this->discId.data(), sectorBuf, 10); memcpy(this->discId.data(), sectorBuf, 10);
if (this->discId[0] == 0) { if (this->discId[0] == 0) {
@ -180,27 +206,30 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
this->state = STATE_READ_DISC_INFO_DONE; this->state = STATE_READ_DISC_INFO_DONE;
return ApplicationState::SUBSTATE_RUNNING; return ApplicationState::SUBSTATE_RUNNING;
} }
FSAEx_RawClose(__wut_devoptab_fs_client, this->oddFd);
this->oddFd = -1;
this->setError(ERROR_READ_FIRST_SECTOR); this->setError(ERROR_READ_FIRST_SECTOR);
return ApplicationState::SUBSTATE_RUNNING; return ApplicationState::SUBSTATE_RUNNING;
} else if (this->state == STATE_READ_DISC_INFO_DONE) { } else if (this->state == STATE_READ_DISC_INFO_DONE) {
this->state = STATE_READ_COMMON_KEY; this->state = STATE_READ_COMMON_KEY;
} else if (this->state == STATE_READ_COMMON_KEY) { } else if (this->state == STATE_READ_COMMON_KEY) {
uint8_t opt[0x400]; WiiUConsoleOTP otp;
IOSUHAX_read_otp(opt, 0x400); Mocha_ReadOTP(&otp);
memcpy(cKey.data(), opt + 0xE0, 0x10); memcpy(cKey.data(), otp.wiiUBank.wiiUCommonKey, 0x10);
this->state = STATE_CREATE_DISC_READER; this->state = STATE_CREATE_DISC_READER;
} else if (this->state == STATE_CREATE_DISC_READER) { } else if (this->state == STATE_CREATE_DISC_READER) {
this->discReader = std::make_shared<DiscReaderDiscDrive>(); auto discReaderOpt = DiscReaderDiscDrive::make_unique();
if (!discReader->IsReady()) { if (!discReaderOpt) {
this->setError(ERROR_OPEN_ODD1); this->setError(ERROR_OPEN_ODD1);
return SUBSTATE_RUNNING; return SUBSTATE_RUNNING;
} }
this->state = STATE_PARSE_DISC_HEADER; this->discReader = std::move(discReaderOpt.value());
this->state = STATE_PARSE_DISC_HEADER;
} else if (this->state == STATE_PARSE_DISC_HEADER) { } else if (this->state == STATE_PARSE_DISC_HEADER) {
auto discHeaderOpt = WiiUDiscHeader::make_unique(discReader); auto discHeaderOpt = WiiUDiscHeader::make_unique(discReader);
if (!discHeaderOpt.has_value()) { if (!discHeaderOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to read DiscHeader"); DEBUG_FUNCTION_LINE_ERR("Failed to read DiscHeader");
this->setError(ERROR_PARSE_DISCHEADER); this->setError(ERROR_PARSE_DISCHEADER);
return SUBSTATE_RUNNING; return SUBSTATE_RUNNING;
} }
@ -217,9 +246,10 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
return SUBSTATE_RUNNING; return SUBSTATE_RUNNING;
} }
this->gmPartitionPairs.emplace_back(gmPartition, nusTitleOpt.value()); this->gmPartitionPairs.emplace_back(gmPartition, std::move(nusTitleOpt.value()));
} }
} }
this->state = STATE_CHOOSE_PARTITION_TO_DUMP; this->state = STATE_CHOOSE_PARTITION_TO_DUMP;
} else if (this->state == STATE_CHOOSE_PARTITION_TO_DUMP) { } else if (this->state == STATE_CHOOSE_PARTITION_TO_DUMP) {
if (gmPartitionPairs.empty()) { if (gmPartitionPairs.empty()) {
@ -227,6 +257,11 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
return SUBSTATE_RETURN; return SUBSTATE_RETURN;
} }
} }
if (buttonPressed(input, Input::BUTTON_B)) {
return SUBSTATE_RETURN;
}
proccessMenuNavigationY(input, (int32_t) gmPartitionPairs.size() + 1); proccessMenuNavigationY(input, (int32_t) gmPartitionPairs.size() + 1);
if (entrySelected(input)) { if (entrySelected(input)) {
if (selectedOptionY >= (int32_t) gmPartitionPairs.size()) { if (selectedOptionY >= (int32_t) gmPartitionPairs.size()) {
@ -243,7 +278,7 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
return SUBSTATE_RUNNING; return SUBSTATE_RUNNING;
} }
this->targetPath = StringTools::strfmt("%swudump/%s/%s", getPathForDevice(targetDevice).c_str(), this->discId, curPartition->getVolumeId().c_str()); this->targetPath = string_format("%swudump/%s/%s", getPathForDevice(targetDevice).c_str(), this->discId, curPartition->getVolumeId().c_str());
if (!FSUtils::CreateSubfolder(targetPath.c_str())) { if (!FSUtils::CreateSubfolder(targetPath.c_str())) {
this->setError(ERROR_CREATE_DIR); this->setError(ERROR_CREATE_DIR);
return SUBSTATE_RUNNING; return SUBSTATE_RUNNING;
@ -292,6 +327,10 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
this->curContentIndex = 0; this->curContentIndex = 0;
this->state = STATE_DUMP_PARTITION_CONTENTS; this->state = STATE_DUMP_PARTITION_CONTENTS;
} else if (this->state == STATE_DUMP_PARTITION_CONTENTS) { } else if (this->state == STATE_DUMP_PARTITION_CONTENTS) {
if (buttonPressed(input, Input::BUTTON_B)) {
this->state = STATE_ABORT_CONFIRMATION;
return ApplicationState::SUBSTATE_RUNNING;
}
// Get current content by index. // Get current content by index.
if (curContent == nullptr) { if (curContent == nullptr) {
auto curContentOpt = curNUSTitle->tmd->getContentByIndex(curContentIndex); auto curContentOpt = curNUSTitle->tmd->getContentByIndex(curContentIndex);
@ -350,7 +389,7 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
// alloc readBuffer if needed // alloc readBuffer if needed
if (this->readBuffer == nullptr) { if (this->readBuffer == nullptr) {
readBuffer = (uint8_t *) malloc(READ_BUFFER_SIZE); readBuffer = (uint8_t *) memalign(0x40, ROUNDUP(READ_BUFFER_SIZE, 0x40));
if (readBuffer == nullptr) { if (readBuffer == nullptr) {
this->setError(ERROR_MALLOC_FAILED); this->setError(ERROR_MALLOC_FAILED);
return SUBSTATE_RUNNING; return SUBSTATE_RUNNING;
@ -376,6 +415,20 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
// Go on! // Go on!
this->state = STATE_DUMP_PARTITION_CONTENTS; this->state = STATE_DUMP_PARTITION_CONTENTS;
return ApplicationState::SUBSTATE_RUNNING; return ApplicationState::SUBSTATE_RUNNING;
} else if (this->state == STATE_ABORT_CONFIRMATION) {
if (buttonPressed(input, Input::BUTTON_B)) {
this->state = STATE_DUMP_PARTITION_CONTENTS;
return ApplicationState::SUBSTATE_RUNNING;
}
proccessMenuNavigationX(input, 2);
if (buttonPressed(input, Input::BUTTON_A)) {
if (selectedOptionX == 0) {
this->state = STATE_DUMP_PARTITION_CONTENTS;
return ApplicationState::SUBSTATE_RUNNING;
} else {
return ApplicationState::SUBSTATE_RETURN;
}
}
} else if (state == STATE_DUMP_DONE) { } else if (state == STATE_DUMP_DONE) {
if (entrySelected(input)) { if (entrySelected(input)) {
return ApplicationState::SUBSTATE_RETURN; return ApplicationState::SUBSTATE_RETURN;

View File

@ -48,7 +48,8 @@ public:
STATE_DUMP_PARTITION_TICKET, STATE_DUMP_PARTITION_TICKET,
STATE_DUMP_PARTITION_CERT, STATE_DUMP_PARTITION_CERT,
STATE_DUMP_PARTITION_CONTENTS, STATE_DUMP_PARTITION_CONTENTS,
STATE_DUMP_DONE STATE_DUMP_DONE,
STATE_ABORT_CONFIRMATION
}; };
enum eErrorState { enum eErrorState {
@ -92,8 +93,8 @@ public:
int32_t oddFd = -1; int32_t oddFd = -1;
void *sectorBuf = nullptr; void *sectorBuf = nullptr;
uint32_t sectorBufSize; uint32_t sectorBufSize;
std::shared_ptr<DiscReaderDiscDrive> discReader = nullptr; std::shared_ptr<DiscReader> discReader;
std::unique_ptr<WiiUDiscHeader> discHeader = nullptr; std::unique_ptr<WiiUDiscHeader> discHeader;
std::shared_ptr<WiiUGMPartition> curPartition = nullptr; std::shared_ptr<WiiUGMPartition> curPartition = nullptr;
std::shared_ptr<NUSDataProvider> dataProvider = nullptr; std::shared_ptr<NUSDataProvider> dataProvider = nullptr;

View File

@ -16,24 +16,27 @@
****************************************************************************/ ****************************************************************************/
#include "DefaultNUSDataProcessor.h" #include "DefaultNUSDataProcessor.h"
bool DefaultNUSDataProcessor::readPlainDecryptedContent(const std::shared_ptr<Content> &pContent, std::vector<uint8_t> &out_data) { bool DefaultNUSDataProcessor::readPlainDecryptedContent(const std::shared_ptr<Content> &pContent, std::vector<uint8_t> &out_data) {
if ((pContent->type & 0x0002) == 0x0002) { if ((pContent->type & 0x0002) == 0x0002) {
DEBUG_FUNCTION_LINE("Hashed content not supported yet"); DEBUG_FUNCTION_LINE_ERR("Hashed content not supported yet");
return false; return false;
} }
auto contentSize = ROUNDUP(pContent->encryptedFileSize, 16); auto contentSize = ROUNDUP(pContent->encryptedFileSize, 16);
out_data.resize(contentSize); out_data.resize(contentSize);
auto *inData = (uint8_t *) malloc(contentSize); if (contentSize > UINT32_MAX) {
if (inData == nullptr) { DEBUG_FUNCTION_LINE_ERR("Content is too big to read");
DEBUG_FUNCTION_LINE("Failed to alloc"); OSFatal("Content is too big to read");
}
auto inData = make_unique_nothrow<uint8_t[]>((uint32_t) contentSize);
if (!inData) {
DEBUG_FUNCTION_LINE_ERR("Failed to alloc");
return false; return false;
} }
if (!dataProvider->readRawContent(pContent, inData, 0, contentSize)) { if (!dataProvider->readRawContent(pContent, inData.get(), 0, contentSize)) {
DEBUG_FUNCTION_LINE("Failed tor read content"); DEBUG_FUNCTION_LINE_ERR("Failed tor read content");
free(inData);
return false; return false;
} }
@ -42,12 +45,11 @@ bool DefaultNUSDataProcessor::readPlainDecryptedContent(const std::shared_ptr<Co
uint16_t content_index = pContent->index; uint16_t content_index = pContent->index;
memcpy(IV.data(), &content_index, 2); memcpy(IV.data(), &content_index, 2);
nusDecryption->decryptData(IV, inData, out_data.data(), contentSize); nusDecryption->decryptData(IV, inData.get(), out_data.data(), contentSize);
free(inData);
return true; return true;
} }
std::shared_ptr<NUSDataProvider> DefaultNUSDataProcessor::getDataProvider() { std::shared_ptr<NUSDataProvider> &DefaultNUSDataProcessor::getDataProvider() {
return dataProvider; return dataProvider;
} }

View File

@ -27,7 +27,7 @@ public:
bool readPlainDecryptedContent(const std::shared_ptr<Content> &pContent, std::vector<uint8_t> &out_data) override; bool readPlainDecryptedContent(const std::shared_ptr<Content> &pContent, std::vector<uint8_t> &out_data) override;
std::shared_ptr<NUSDataProvider> getDataProvider() override; std::shared_ptr<NUSDataProvider> &getDataProvider() override;
private: private:
std::shared_ptr<NUSDataProvider> dataProvider; std::shared_ptr<NUSDataProvider> dataProvider;

View File

@ -15,21 +15,21 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/ ****************************************************************************/
#include <MainApplicationState.h> #include "utils/utils.h"
#include <WUD/content/WiiUDiscContentsHeader.h> #include <WUD/content/WiiUDiscContentsHeader.h>
#include <common/common.h> #include <common/common.h>
#include <coreinit/debug.h> #include <coreinit/debug.h>
#include <utils/rijndael.h> #include <utils/rijndael.h>
bool DiscReader::readDecryptedChunk(uint64_t readOffset, uint8_t *out_buffer, uint8_t *key, uint8_t *IV) const { bool DiscReader::readDecryptedChunk(uint64_t readOffset, uint8_t *out_buffer, uint8_t *key, uint8_t *IV) const {
int CHUNK_SIZE = 0x10000; uint32_t CHUNK_SIZE = 0x10000;
uint32_t sectorOffset = readOffset / READ_SECTOR_SIZE; uint32_t sectorOffset = readOffset / READ_SECTOR_SIZE;
auto *encryptedBuffer = (uint8_t *) malloc(CHUNK_SIZE); auto encryptedBuffer = (uint8_t *) memalign(0x40, CHUNK_SIZE);
if (encryptedBuffer == nullptr) { if (!encryptedBuffer) {
DEBUG_FUNCTION_LINE("Failed to alloc buffer"); DEBUG_FUNCTION_LINE_ERR("Failed to alloc buffer");
return false; return false;
} }
@ -41,8 +41,8 @@ bool DiscReader::readDecryptedChunk(uint64_t readOffset, uint8_t *out_buffer, ui
memcpy(IV, &encryptedBuffer[CHUNK_SIZE - 16], 16); memcpy(IV, &encryptedBuffer[CHUNK_SIZE - 16], 16);
result = true; result = true;
} }
free(encryptedBuffer); free(encryptedBuffer);
return result; return result;
} }
@ -61,8 +61,9 @@ bool DiscReader::readDecrypted(uint8_t *out_buffer, uint64_t clusterOffset, uint
uint32_t usedSize = size; uint32_t usedSize = size;
uint64_t usedFileOffset = fileOffset; uint64_t usedFileOffset = fileOffset;
auto *buffer = (uint8_t *) malloc(BLOCK_SIZE); auto buffer = make_unique_nothrow<uint8_t[]>((size_t) BLOCK_SIZE);
if (buffer == nullptr) { if (!buffer) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate buffer");
return false; return false;
} }
@ -77,8 +78,8 @@ bool DiscReader::readDecrypted(uint8_t *out_buffer, uint64_t clusterOffset, uint
do { do {
uint64_t totalOffset = (clusterOffset + usedFileOffset); uint64_t totalOffset = (clusterOffset + usedFileOffset);
uint64_t blockNumber = (totalOffset / BLOCK_SIZE); uint32_t blockNumber = (totalOffset / BLOCK_SIZE);
uint64_t blockOffset = (totalOffset % BLOCK_SIZE); uint32_t blockOffset = (totalOffset % BLOCK_SIZE);
readOffset = (blockNumber * BLOCK_SIZE); readOffset = (blockNumber * BLOCK_SIZE);
if (!useFixedIV) { if (!useFixedIV) {
@ -87,14 +88,14 @@ bool DiscReader::readDecrypted(uint8_t *out_buffer, uint64_t clusterOffset, uint
memcpy(usedIV + 8, &ivTemp, 8); memcpy(usedIV + 8, &ivTemp, 8);
} }
if (!readDecryptedChunk(readOffset, buffer, key, usedIV)) { if (!readDecryptedChunk(readOffset, buffer.get(), key, usedIV)) {
result = false; result = false;
break; break;
} }
maxCopySize = BLOCK_SIZE - blockOffset; maxCopySize = BLOCK_SIZE - blockOffset;
copySize = (usedSize > maxCopySize) ? maxCopySize : usedSize; copySize = (usedSize > maxCopySize) ? maxCopySize : usedSize;
memcpy(out_buffer + totalread, buffer + blockOffset, copySize); memcpy(out_buffer + totalread, buffer.get() + blockOffset, copySize);
totalread += copySize; totalread += copySize;
@ -103,22 +104,21 @@ bool DiscReader::readDecrypted(uint8_t *out_buffer, uint64_t clusterOffset, uint
usedFileOffset += copySize; usedFileOffset += copySize;
} while (totalread < size); } while (totalread < size);
free(buffer);
return result; return result;
} }
bool DiscReader::readEncryptedAligned(uint8_t *buf, uint64_t offset_in_sector, uint32_t size) { bool DiscReader::readEncryptedAligned(uint8_t *buf, uint32_t block_offset, uint32_t size) {
auto full_block_count = size / SECTOR_SIZE; auto full_block_count = size / SECTOR_SIZE;
if (full_block_count > 0) { if (full_block_count > 0) {
if (!readEncryptedSector(buf, full_block_count, offset_in_sector)) { if (!readEncryptedSector(buf, full_block_count, block_offset)) {
return false; return false;
} }
} }
auto remainingSize = size - (full_block_count * SECTOR_SIZE); auto remainingSize = size - (full_block_count * SECTOR_SIZE);
if (remainingSize > 0) { if (remainingSize > 0) {
auto newOffset = offset_in_sector + full_block_count; std::lock_guard<std::mutex> lock(sector_buf_mutex);
auto newOffset = block_offset + full_block_count;
if (!readEncryptedSector(sector_buf, 1, newOffset)) { if (!readEncryptedSector(sector_buf, 1, newOffset)) {
return false; return false;
} }
@ -136,40 +136,48 @@ bool DiscReader::readEncrypted(uint8_t *buf, uint64_t offset, uint32_t size) {
auto curOffset = offset; auto curOffset = offset;
uint32_t offsetInBuf = 0; uint32_t offsetInBuf = 0;
uint32_t totalRead = 0; uint32_t totalRead = 0;
if (missingFromPrevSector > 0) { if (missingFromPrevSector > 0) {
std::lock_guard<std::mutex> lock(sector_buf_mutex);
auto offset_in_sectors = offset / SECTOR_SIZE; auto offset_in_sectors = offset / SECTOR_SIZE;
if (!readEncryptedSector(sector_buf, 1, offset_in_sectors)) { if (!readEncryptedSector(sector_buf, 1, offset_in_sectors)) {
return false; return false;
} }
uint32_t toCopy = SECTOR_SIZE - missingFromPrevSector; uint32_t toCopy = SECTOR_SIZE - missingFromPrevSector;
if (toCopy > size) { if (toCopy > size) {
toCopy = size; toCopy = size;
} }
memcpy(buf, sector_buf + missingFromPrevSector, toCopy); memcpy(buf, sector_buf + missingFromPrevSector, toCopy);
totalRead += toCopy; totalRead += toCopy;
curOffset += missingFromPrevSector; curOffset += toCopy;
offsetInBuf += missingFromPrevSector; offsetInBuf += toCopy;
} }
if (totalRead >= size) { if (totalRead >= size) {
return true; return true;
} }
if (curOffset % SECTOR_SIZE == 0) { if (curOffset % SECTOR_SIZE == 0) {
if (!readEncryptedAligned(buf + offsetInBuf, offset / SECTOR_SIZE, size)) { if (!readEncryptedAligned(buf + offsetInBuf, curOffset / SECTOR_SIZE, size)) {
return false; return false;
} }
} else { } else {
OSFatal("Failed to read encrypted"); return false;
} }
return true; return true;
} }
DiscReader::DiscReader() { DiscReader::DiscReader() {
this->sector_buf = (uint8_t *) malloc(READ_SECTOR_SIZE); this->sector_buf = static_cast<uint8_t *>(memalign(0x40, READ_SECTOR_SIZE));
if (!this->sector_buf) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate sector_buf");
OSFatal("Failed to allocate sector_buf");
}
} }
DiscReader::~DiscReader() { DiscReader::~DiscReader() {
free(this->sector_buf); free(this->sector_buf);
this->sector_buf = nullptr;
} }

View File

@ -17,6 +17,8 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <memory>
#include <mutex>
class DiscReader { class DiscReader {
public: public:
@ -26,9 +28,9 @@ public:
virtual bool IsReady() = 0; virtual bool IsReady() = 0;
virtual bool readEncryptedSector(uint8_t *buffer, uint32_t block_cnt, uint64_t offset_in_sector) const = 0; virtual bool readEncryptedSector(uint8_t *buffer, uint32_t block_cnt, uint32_t block_offset) const = 0;
bool readEncryptedAligned(uint8_t *buf, uint64_t offset_in_sector, uint32_t size); bool readEncryptedAligned(uint8_t *buf, uint32_t block_offset, uint32_t size);
bool readDecryptedChunk(uint64_t readOffset, uint8_t *out_buffer, uint8_t *key, uint8_t *IV) const; bool readDecryptedChunk(uint64_t readOffset, uint8_t *out_buffer, uint8_t *key, uint8_t *IV) const;
@ -40,5 +42,6 @@ public:
bool hasDiscKey = false; bool hasDiscKey = false;
private: private:
uint8_t *sector_buf; std::mutex sector_buf_mutex;
uint8_t *sector_buf = nullptr;
}; };

View File

@ -15,56 +15,67 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/ ****************************************************************************/
#include "DiscReaderDiscDrive.h" #include "DiscReaderDiscDrive.h"
#include <MainApplicationState.h> #include "utils/utils.h"
#include <WUD/content/WiiUDiscContentsHeader.h> #include <WUD/content/WiiUDiscContentsHeader.h>
#include <common/common.h> #include <common/common.h>
#include <iosuhax.h> #include <malloc.h>
#include <mocha/fsa.h>
#include <mocha/mocha.h>
#include <utils/logger.h> #include <utils/logger.h>
#include <utils/rijndael.h> #include <utils/rijndael.h>
DiscReaderDiscDrive::DiscReaderDiscDrive() : DiscReader() { DiscReaderDiscDrive::DiscReaderDiscDrive() : DiscReader() {
auto *sector_buf = (uint8_t *) malloc(READ_SECTOR_SIZE); auto sector_buf = (uint8_t *) memalign(0x40, (size_t) READ_SECTOR_SIZE);
if (sector_buf == nullptr) { if (!sector_buf) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate buffer");
return; return;
} }
auto ret = IOSUHAX_FSA_RawOpen(gFSAfd, "/dev/odd01", &device_handle); auto ret = FSAEx_RawOpen(__wut_devoptab_fs_client, "/dev/odd01", &device_handle);
if (ret < 0) { if (ret < 0) {
free(sector_buf);
return; return;
} }
auto res = IOSUHAX_FSA_RawRead(gFSAfd, sector_buf, READ_SECTOR_SIZE, 1, 3, device_handle); auto res = FSAEx_RawRead(__wut_devoptab_fs_client, sector_buf, READ_SECTOR_SIZE, 1, 3, device_handle);
if (res >= 0) { if (res >= 0) {
if (((uint32_t *) sector_buf)[0] != WiiUDiscContentsHeader::MAGIC) { if (((uint32_t *) sector_buf)[0] != WiiUDiscContentsHeader::MAGIC) {
uint8_t iv[16]; uint8_t iv[16];
memset(iv, 0, 16); memset(iv, 0, 16);
auto discKeyRes = IOSUHAX_ODM_GetDiscKey(discKey); WUDDiscKey discKeyLocal;
if (discKeyRes >= 0) {
hasDiscKey = true; auto discKeyRes = Mocha_ODMGetDiscKey(&discKeyLocal);
auto sector_buf_decrypted = (uint8_t *) malloc(READ_SECTOR_SIZE); if (discKeyRes == MOCHA_RESULT_SUCCESS) {
if (sector_buf_decrypted != nullptr) { hasDiscKey = true;
aes_set_key((uint8_t *) discKey); memcpy(this->discKey, discKeyLocal.key, 16);
aes_decrypt((uint8_t *) iv, (uint8_t *) sector_buf, (uint8_t *) &sector_buf_decrypted[0], READ_SECTOR_SIZE); auto sector_buf_decrypted = make_unique_nothrow<uint8_t[]>((size_t) READ_SECTOR_SIZE);
if (((uint32_t *) sector_buf_decrypted)[0] == WiiUDiscContentsHeader::MAGIC) { if (!sector_buf_decrypted) {
DEBUG_FUNCTION_LINE("Key was correct"); DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory");
this->init_done = true; free(sector_buf);
} return;
free(sector_buf_decrypted);
} }
aes_set_key((uint8_t *) discKey);
aes_decrypt((uint8_t *) iv, (uint8_t *) &sector_buf[0], (uint8_t *) &sector_buf_decrypted[0], READ_SECTOR_SIZE);
if (((uint32_t *) sector_buf_decrypted.get())[0] == WiiUDiscContentsHeader::MAGIC) {
this->init_done = true;
} else {
DEBUG_FUNCTION_LINE_ERR("Invalid disc key");
}
} else {
DEBUG_FUNCTION_LINE_ERR("Failed to get the DiscKey");
this->init_done = false;
} }
} else { } else {
this->init_done = true; this->init_done = true;
} }
} else {
DEBUG_FUNCTION_LINE_ERR("Raw read failed %d", ret);
} }
free(sector_buf);
} }
bool DiscReaderDiscDrive::readEncryptedSector(uint8_t *buffer, uint32_t block_cnt, uint64_t offset_in_sectors) const { bool DiscReaderDiscDrive::readEncryptedSector(uint8_t *buffer, uint32_t block_cnt, uint32_t block_offset) const {
if (IOSUHAX_FSA_RawRead(gFSAfd, buffer, READ_SECTOR_SIZE, block_cnt, offset_in_sectors, device_handle) < 0) { if (FSAEx_RawRead(__wut_devoptab_fs_client, buffer, READ_SECTOR_SIZE, block_cnt, block_offset, device_handle) < 0) {
DEBUG_FUNCTION_LINE("Failed to read from Disc");
return false; return false;
} }
return true; return true;
@ -76,7 +87,8 @@ bool DiscReaderDiscDrive::IsReady() {
DiscReaderDiscDrive::~DiscReaderDiscDrive() { DiscReaderDiscDrive::~DiscReaderDiscDrive() {
if (device_handle != -1) { if (device_handle != -1) {
IOSUHAX_FSA_RawOpen(gFSAfd, "/dev/odd01", &device_handle); FSAEx_RawClose(__wut_devoptab_fs_client, device_handle);
device_handle = -1;
} }
} }
@ -84,22 +96,23 @@ bool DiscReaderDiscDrive::readEncrypted(uint8_t *buf, uint64_t offset, uint32_t
if (size == 0) { if (size == 0) {
return true; return true;
} }
if ((offset & 0x7FFF) != 0 || (size & 0x7FFF) != 0) {
if ((offset & (SECTOR_SIZE - 0x1)) != 0 || (size & (SECTOR_SIZE - 0x1)) != 0) {
return DiscReader::readEncrypted(buf, offset, size); return DiscReader::readEncrypted(buf, offset, size);
} }
uint32_t block_cnt = size >> 15; uint32_t block_cnt = size >> 15;
uint32_t offset_in_sectors = offset >> 15; uint32_t offset_in_sectors = offset >> 15;
if (IOSUHAX_FSA_RawRead(gFSAfd, buf, 0x8000, block_cnt, offset_in_sectors, device_handle) < 0) { if (FSAEx_RawRead(__wut_devoptab_fs_client, buf, 0x8000, block_cnt, offset_in_sectors, device_handle) < 0) {
DEBUG_FUNCTION_LINE("Failed to read from Disc"); DEBUG_FUNCTION_LINE("Failed to read from Disc");
return false; return false;
} }
return true; return true;
} }
std::optional<DiscReaderDiscDrive *> DiscReaderDiscDrive::Create() { std::optional<std::unique_ptr<DiscReaderDiscDrive>> DiscReaderDiscDrive::make_unique() {
auto discReader = new DiscReaderDiscDrive(); auto discReader = make_unique_nothrow<DiscReaderDiscDrive>();
if (!discReader->IsReady()) { if (!discReader || !discReader->IsReady()) {
delete discReader; DEBUG_FUNCTION_LINE_ERR("Failed to init DiscReader %d %d", !discReader, discReader->IsReady());
return {}; return {};
} }
return discReader; return discReader;

View File

@ -18,6 +18,7 @@
#include "DiscReader.h" #include "DiscReader.h"
#include <cstdint> #include <cstdint>
#include <memory>
#include <optional> #include <optional>
class DiscReaderDiscDrive : public DiscReader { class DiscReaderDiscDrive : public DiscReader {
@ -26,15 +27,14 @@ public:
~DiscReaderDiscDrive() override; ~DiscReaderDiscDrive() override;
static std::optional<DiscReaderDiscDrive *> Create(); static std::optional<std::unique_ptr<DiscReaderDiscDrive>> make_unique();
bool readEncryptedSector(uint8_t *buffer, uint32_t block_cnt, uint64_t offset_in_sector) const override; bool readEncryptedSector(uint8_t *buffer, uint32_t block_cnt, uint32_t block_offset) const override;
bool IsReady() override;
bool readEncrypted(uint8_t *buf, uint64_t offset, uint32_t size) override; bool readEncrypted(uint8_t *buf, uint64_t offset, uint32_t size) override;
private: private:
bool IsReady() override;
bool init_done = false; bool init_done = false;
int32_t device_handle = -1; int32_t device_handle = -1;
}; };

View File

@ -10,7 +10,7 @@ protected:
public: public:
virtual ~NUSDataProcessor() = default; virtual ~NUSDataProcessor() = default;
virtual std::shared_ptr<NUSDataProvider> getDataProvider() = 0; virtual std::shared_ptr<NUSDataProvider> &getDataProvider() = 0;
virtual bool readPlainDecryptedContent(const std::shared_ptr<Content> &pContent, std::vector<uint8_t> &out_data) = 0; virtual bool readPlainDecryptedContent(const std::shared_ptr<Content> &pContent, std::vector<uint8_t> &out_data) = 0;
}; };

View File

@ -15,33 +15,44 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/ ****************************************************************************/
#include "NUSDataProviderWUD.h" #include "NUSDataProviderWUD.h"
#include "utils/WUDUtils.h"
NUSDataProviderWUD::NUSDataProviderWUD(const std::shared_ptr<WiiUGMPartition> &pGamePartition, const std::shared_ptr<DiscReader> &pDiscReader) { NUSDataProviderWUD::NUSDataProviderWUD(std::shared_ptr<WiiUGMPartition> pGamePartition, std::shared_ptr<DiscReader> pDiscReader) {
gamePartition = pGamePartition; gamePartition = std::move(pGamePartition);
discReader = pDiscReader; discReader = std::move(pDiscReader);
} }
NUSDataProviderWUD::~NUSDataProviderWUD() = default; NUSDataProviderWUD::~NUSDataProviderWUD() = default;
bool NUSDataProviderWUD::readRawContent(const std::shared_ptr<Content> &content, uint8_t *buffer, uint64_t offset, uint32_t size) { bool NUSDataProviderWUD::readRawContent(const std::shared_ptr<Content> &content, uint8_t *buffer, uint64_t offset, uint32_t size) {
if (buffer == nullptr) { if (buffer == nullptr) {
DEBUG_FUNCTION_LINE_ERR("buffer was NULL");
return false; return false;
} }
auto offsetInWUDOpt = getOffsetInWUD(content); if (!discReader) {
if (!offsetInWUDOpt.has_value()) { DEBUG_FUNCTION_LINE_ERR("No valid disc reader");
return false;
}
auto offsetInWUDOpt = WUDUtils::getOffsetOfContent(this->gamePartition, this->fst, content);
if (!offsetInWUDOpt) {
DEBUG_FUNCTION_LINE_ERR("Failed to get offset for content");
return false; return false;
} }
auto offsetInWUD = offsetInWUDOpt.value() + offset; auto offsetInWUD = offsetInWUDOpt.value() + offset;
if (!discReader) {
return false;
}
return discReader->readEncrypted(buffer, offsetInWUD, size); return discReader->readEncrypted(buffer, offsetInWUD, size);
} }
bool NUSDataProviderWUD::getContentH3Hash(const std::shared_ptr<Content> &content, std::vector<uint8_t> &out_data) { bool NUSDataProviderWUD::getContentH3Hash(const std::shared_ptr<Content> &content, std::vector<uint8_t> &out_data) {
auto cur = gamePartition->getVolumes().begin()->second->h3HashArrayList[content->index]; auto &cur = gamePartition->getVolumes().begin()->second->h3HashArrayList[content->index];
if (cur == nullptr || cur->size == 0) { if (cur == nullptr || cur->size == 0) {
return false; return false;
} }
out_data.resize(cur->size); out_data.resize(cur->size);
memcpy(out_data.data(), cur->data, cur->size); memcpy(out_data.data(), cur->data.get(), cur->size);
return true; return true;
} }
@ -56,29 +67,16 @@ void NUSDataProviderWUD::setFST(const std::shared_ptr<FST> &pFST) {
} }
bool NUSDataProviderWUD::getRawCert(std::vector<uint8_t> &out_data) { bool NUSDataProviderWUD::getRawCert(std::vector<uint8_t> &out_data) {
out_data = gamePartition->rawCert; out_data = gamePartition->getRawCert();
return true; return true;
} }
bool NUSDataProviderWUD::getRawTicket(std::vector<uint8_t> &out_data) { bool NUSDataProviderWUD::getRawTicket(std::vector<uint8_t> &out_data) {
out_data = gamePartition->rawTicket; out_data = gamePartition->getRawTicket();
return true; return true;
} }
bool NUSDataProviderWUD::getRawTMD(std::vector<uint8_t> &out_data) { bool NUSDataProviderWUD::getRawTMD(std::vector<uint8_t> &out_data) {
out_data = gamePartition->rawTMD; out_data = gamePartition->getRawTMD();
return true; return true;
} }
std::optional<uint64_t> NUSDataProviderWUD::getOffsetInWUD(const std::shared_ptr<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.has_value()) {
DEBUG_FUNCTION_LINE("Failed to get section for Content");
return {};
}
return gamePartition->getSectionOffsetOnDefaultPartition() + info.value()->address.getAddressInBytes();
}

View File

@ -25,7 +25,7 @@
class NUSDataProviderWUD : public NUSDataProvider { class NUSDataProviderWUD : public NUSDataProvider {
public: public:
NUSDataProviderWUD(const std::shared_ptr<WiiUGMPartition> &pPartition, const std::shared_ptr<DiscReader> &pDrive); NUSDataProviderWUD(std::shared_ptr<WiiUGMPartition> pPartition, std::shared_ptr<DiscReader> pDiscReader);
~NUSDataProviderWUD() override; ~NUSDataProviderWUD() override;
@ -44,7 +44,4 @@ public:
std::shared_ptr<FST> fst; std::shared_ptr<FST> fst;
std::shared_ptr<WiiUGMPartition> gamePartition; std::shared_ptr<WiiUGMPartition> gamePartition;
std::shared_ptr<DiscReader> discReader; std::shared_ptr<DiscReader> discReader;
private:
[[nodiscard]] std::optional<uint64_t> getOffsetInWUD(const std::shared_ptr<Content> &content) const;
}; };

View File

@ -24,5 +24,5 @@ void NUSDecryption::decryptData(const std::array<uint8_t, 0x10> &IV, uint8_t *in
aes_decrypt((uint8_t *) IV.data(), inData, outData, size); aes_decrypt((uint8_t *) IV.data(), inData, outData, size);
} }
NUSDecryption::NUSDecryption(std::shared_ptr<Ticket> pTicket) : ticket(std::move(pTicket)) { NUSDecryption::NUSDecryption(std::unique_ptr<Ticket> pTicket) : ticket(std::move(pTicket)) {
} }

View File

@ -21,9 +21,9 @@
class NUSDecryption { class NUSDecryption {
public: public:
explicit NUSDecryption(std::shared_ptr<Ticket> pTicket); explicit NUSDecryption(std::unique_ptr<Ticket> pTicket);
void decryptData(const std::array<uint8_t, 0x10> &IV, uint8_t *inData, uint8_t *outData, uint32_t size) const; void decryptData(const std::array<uint8_t, 0x10> &IV, uint8_t *inData, uint8_t *outData, uint32_t size) const;
std::shared_ptr<Ticket> ticket; std::unique_ptr<Ticket> ticket;
}; };

View File

@ -16,66 +16,77 @@
****************************************************************************/ ****************************************************************************/
#include "NUSTitle.h" #include "NUSTitle.h"
#include <memory>
#include <utility> #include <utility>
std::optional<std::shared_ptr<NUSTitle>> NUSTitle::loadTitle(const std::shared_ptr<NUSDataProvider> &dataProvider, const std::array<uint8_t, 16> &commonKey) { std::optional<std::unique_ptr<NUSTitle>> NUSTitle::make_unique(std::unique_ptr<NUSDataProvider> dataProvider, const std::array<uint8_t, 16> &commonKey) {
std::vector<uint8_t> dataBuffer; std::vector<uint8_t> dataBuffer;
if (!dataProvider->getRawTMD(dataBuffer)) { if (!dataProvider->getRawTMD(dataBuffer)) {
DEBUG_FUNCTION_LINE("Failed to read TMD"); DEBUG_FUNCTION_LINE_ERR("Failed to read TMD");
return {}; return {};
} }
auto tmdOpt = TitleMetaData::make_shared(dataBuffer); auto tmdOpt = TitleMetaData::make_unique(dataBuffer);
if (!tmdOpt.has_value()) { if (!tmdOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse TMD"); DEBUG_FUNCTION_LINE_ERR("Failed to parse TMD");
return {}; return {};
} }
dataBuffer.clear(); dataBuffer.clear();
if (!dataProvider->getRawTicket(dataBuffer)) { if (!dataProvider->getRawTicket(dataBuffer)) {
DEBUG_FUNCTION_LINE("Failed to read ticket data"); DEBUG_FUNCTION_LINE_ERR("Failed to read ticket data");
return {}; return {};
} }
auto ticketOpt = Ticket::make_shared(dataBuffer, commonKey); auto ticketOpt = Ticket::make_unique(dataBuffer, commonKey);
if (!ticketOpt.has_value()) { if (!ticketOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse ticket"); DEBUG_FUNCTION_LINE_ERR("Failed to parse ticket");
return {}; return {};
} }
dataBuffer.clear(); dataBuffer.clear();
std::shared_ptr<NUSDataProvider> dataProviderShared = std::move(dataProvider);
auto decryption = std::make_shared<NUSDecryption>(std::move(ticketOpt.value())); auto decryption = std::make_shared<NUSDecryption>(std::move(ticketOpt.value()));
auto dpp = std::shared_ptr<NUSDataProcessor>(new DefaultNUSDataProcessor(dataProvider, decryption)); auto dpp = std::unique_ptr<NUSDataProcessor>(new DefaultNUSDataProcessor(dataProviderShared, decryption));
// If we have more than one content, the index 0 is the FST. // If we have more than one content, the index 0 is the FST.
auto fstContentOpt = tmdOpt.value()->getContentByIndex(0); auto fstContentOpt = tmdOpt.value()->getContentByIndex(0);
if (!fstContentOpt.has_value()) { if (!fstContentOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to get content for index 0"); DEBUG_FUNCTION_LINE_ERR("Failed to get content for index 0");
return {}; return {};
} }
if (!dpp->readPlainDecryptedContent(fstContentOpt.value(), dataBuffer)) { if (!dpp->readPlainDecryptedContent(fstContentOpt.value(), dataBuffer)) {
DEBUG_FUNCTION_LINE("Failed to read decrypted content"); DEBUG_FUNCTION_LINE_ERR("Failed to read decrypted content");
return {}; return {};
} }
auto fstOpt = FST::make_shared(dataBuffer, 0, VolumeBlockSize(1)); auto fstOpt = FST::make_shared(dataBuffer, 0, VolumeBlockSize(1));
if (!fstOpt.has_value()) { if (!fstOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse FST"); DEBUG_FUNCTION_LINE_ERR("Failed to parse FST");
return {}; return {};
} }
// The dataprovider may need the FST to calculate the offset of a content // The dataprovider may need the FST to calculate the offset of a content
// on the partition. // on the partition.
dataProvider->setFST(fstOpt.value()); dataProviderShared->setFST(fstOpt.value());
return std::shared_ptr<NUSTitle>(new NUSTitle(tmdOpt.value(), dpp, dataProvider, decryption, ticketOpt.value(), fstOpt.value()));
return std::unique_ptr<NUSTitle>(new NUSTitle(
std::move(tmdOpt.value()),
std::move(dpp),
dataProviderShared,
decryption,
std::move(ticketOpt.value()),
fstOpt.value()));
} }
NUSTitle::NUSTitle(std::shared_ptr<TitleMetaData> pTMD, NUSTitle::NUSTitle(std::unique_ptr<TitleMetaData> pTMD,
std::shared_ptr<NUSDataProcessor> pProcessor, std::unique_ptr<NUSDataProcessor> pProcessor,
std::shared_ptr<NUSDataProvider> pDataProvider, std::shared_ptr<NUSDataProvider> pDataProvider,
std::shared_ptr<NUSDecryption> pDecryption, std::shared_ptr<NUSDecryption> pDecryption,
std::shared_ptr<Ticket> pTicket, std::unique_ptr<Ticket> pTicket,
std::shared_ptr<FST> pFST) : std::shared_ptr<FST> pFST) :
dataProcessor(std::move(pProcessor)), dataProcessor(std::move(pProcessor)),
@ -86,9 +97,50 @@ NUSTitle::NUSTitle(std::shared_ptr<TitleMetaData> pTMD,
dataProvider(std::move(pDataProvider)) { dataProvider(std::move(pDataProvider)) {
} }
std::optional<std::shared_ptr<NUSTitle>> std::optional<std::unique_ptr<NUSTitle>>
NUSTitle::loadTitleFromGMPartition(const std::shared_ptr<WiiUGMPartition> &pPartition, const std::shared_ptr<DiscReader> &pDrive, const std::array<uint8_t, 16> &commonKey) { NUSTitle::loadTitleFromGMPartition(std::shared_ptr<WiiUGMPartition> pPartition, std::shared_ptr<DiscReader> pDiscReader, const std::array<uint8_t, 16> &commonKey) {
return loadTitle(std::shared_ptr<NUSDataProvider>(new NUSDataProviderWUD(pPartition, pDrive)), commonKey); return make_unique(std::unique_ptr<NUSDataProvider>(new NUSDataProviderWUD(std::move(pPartition), std::move(pDiscReader))), commonKey);
}
std::string NUSTitle::getLongnameEn() {
if (!longname_en) {
auto *xml = (ACPMetaXml *) memalign(0x40, sizeof(ACPMetaXml));
if (xml) {
if (ACPGetTitleMetaXml(tmd->titleId, xml) == ACP_RESULT_SUCCESS) {
std::string tmp = xml->longname_en;
StringTools::StripUnicodeAndLineBreak(tmp);
longname_en = tmp;
}
free(xml);
} else {
longname_en = "Unknown";
}
if (!longname_en || longname_en->empty() || longname_en.value() == " ") {
longname_en = "Unknown";
}
}
return longname_en.value();
}
std::string NUSTitle::getShortnameEn() {
if (!shortname_en) {
auto *xml = (ACPMetaXml *) memalign(0x40, sizeof(ACPMetaXml));
if (xml) {
if (ACPGetTitleMetaXml(tmd->titleId, xml) == ACP_RESULT_SUCCESS) {
std::string tmp = xml->shortname_en;
StringTools::StripUnicodeAndLineBreak(tmp);
shortname_en = tmp;
}
free(xml);
} else {
shortname_en = "Unknown";
}
if (!shortname_en || shortname_en->empty() || shortname_en.value() == " ") {
shortname_en = "Unknown";
}
}
return shortname_en.value();
} }
NUSTitle::~NUSTitle() = default; NUSTitle::~NUSTitle() = default;

View File

@ -22,34 +22,43 @@
#include "NUSDataProviderWUD.h" #include "NUSDataProviderWUD.h"
#include "NUSDecryption.h" #include "NUSDecryption.h"
#include "Ticket.h" #include "Ticket.h"
#include "utils/StringTools.h"
#include <WUD/NUSDataProvider.h> #include <WUD/NUSDataProvider.h>
#include <WUD/content/partitions/WiiUGMPartition.h> #include <WUD/content/partitions/WiiUGMPartition.h>
#include <WUD/entities/TMD/TitleMetaData.h> #include <WUD/entities/TMD/TitleMetaData.h>
#include <nn/acp/title.h>
class NUSTitle { class NUSTitle {
public: public:
~NUSTitle(); ~NUSTitle();
std::shared_ptr<NUSDataProcessor> dataProcessor; std::unique_ptr<NUSDataProcessor> dataProcessor;
std::shared_ptr<TitleMetaData> tmd; std::unique_ptr<TitleMetaData> tmd;
std::shared_ptr<Ticket> ticket; std::unique_ptr<Ticket> ticket;
std::shared_ptr<FST> fst; std::shared_ptr<FST> fst;
std::shared_ptr<NUSDecryption> decryption; std::shared_ptr<NUSDecryption> decryption;
std::shared_ptr<NUSDataProvider> dataProvider; std::shared_ptr<NUSDataProvider> dataProvider;
static std::optional<std::shared_ptr<NUSTitle>> loadTitleFromGMPartition( static std::optional<std::unique_ptr<NUSTitle>> loadTitleFromGMPartition(
const std::shared_ptr<WiiUGMPartition> &pPartition, std::shared_ptr<WiiUGMPartition> pPartition,
const std::shared_ptr<DiscReader> &pDrive, std::shared_ptr<DiscReader> pDiscReader,
const std::array<uint8_t, 16> &commonKey); const std::array<uint8_t, 16> &commonKey);
private: std::string getLongnameEn();
static std::optional<std::shared_ptr<NUSTitle>> loadTitle(const std::shared_ptr<NUSDataProvider> &dataProvider, const std::array<uint8_t, 16> &commonKey);
NUSTitle(std::shared_ptr<TitleMetaData> pTMD, std::string getShortnameEn();
std::shared_ptr<NUSDataProcessor> pProcessor,
private:
std::optional<std::string> longname_en;
std::optional<std::string> shortname_en;
static std::optional<std::unique_ptr<NUSTitle>> make_unique(std::unique_ptr<NUSDataProvider> dataProvider, const std::array<uint8_t, 16> &commonKey);
NUSTitle(std::unique_ptr<TitleMetaData> pTMD,
std::unique_ptr<NUSDataProcessor> pProcessor,
std::shared_ptr<NUSDataProvider> pDataProvider, std::shared_ptr<NUSDataProvider> pDataProvider,
std::shared_ptr<NUSDecryption> pDecryption, std::shared_ptr<NUSDecryption> pDecryption,
std::shared_ptr<Ticket> pTicket, std::unique_ptr<Ticket> pTicket,
std::shared_ptr<FST> pFST); std::shared_ptr<FST> pFST);
}; };

View File

@ -22,9 +22,9 @@ Ticket::Ticket(const std::array<uint8_t, 16> &pEncryptedKey, const std::array<ui
ticketKeyDec(pDecryptedKey) { ticketKeyDec(pDecryptedKey) {
} }
std::optional<std::shared_ptr<Ticket>> Ticket::make_shared(const std::vector<uint8_t> &data, std::optional<const std::array<uint8_t, 16>> commonKey) { std::optional<std::unique_ptr<Ticket>> Ticket::make_unique(const std::vector<uint8_t> &data, std::optional<const std::array<uint8_t, 16>> commonKey) {
if (data.size() <= 0x1DC + 0x10) { if (data.size() <= 0x1DC + 0x10) {
DEBUG_FUNCTION_LINE("Not enough data to parse a ticket"); DEBUG_FUNCTION_LINE_ERR("Not enough data to parse a ticket");
return {}; return {};
} }
@ -46,6 +46,10 @@ std::optional<std::shared_ptr<Ticket>> Ticket::make_shared(const std::vector<uin
aes_set_key((uint8_t *) commonKey.value().data()); aes_set_key((uint8_t *) commonKey.value().data());
aes_decrypt(IV, encryptedKey.data(), decryptedKey.data(), 16); aes_decrypt(IV, encryptedKey.data(), decryptedKey.data(), 16);
} }
auto ticket = new (std::nothrow) Ticket(encryptedKey, decryptedKey);
return std::shared_ptr<Ticket>(new Ticket(encryptedKey, decryptedKey)); if (!ticket) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate Ticket");
return {};
}
return std::unique_ptr<Ticket>(ticket);
} }

View File

@ -29,7 +29,7 @@ public:
std::array<uint8_t, 16> ticketKeyEnc; std::array<uint8_t, 16> ticketKeyEnc;
std::array<uint8_t, 16> ticketKeyDec; std::array<uint8_t, 16> ticketKeyDec;
static std::optional<std::shared_ptr<Ticket>> make_shared(const std::vector<uint8_t> &data, std::optional<const std::array<uint8_t, 16>> commonKey); static std::optional<std::unique_ptr<Ticket>> make_unique(const std::vector<uint8_t> &data, std::optional<const std::array<uint8_t, 16>> commonKey);
private: private:
Ticket(const std::array<uint8_t, 16> &encryptedKey, const std::array<uint8_t, 16> &decryptedKey); Ticket(const std::array<uint8_t, 16> &encryptedKey, const std::array<uint8_t, 16> &decryptedKey);

View File

@ -19,24 +19,24 @@
uint32_t WiiUContentsInformation::LENGTH = 32768; uint32_t WiiUContentsInformation::LENGTH = 32768;
std::optional<std::unique_ptr<WiiUContentsInformation>> WiiUContentsInformation::make_unique(const std::shared_ptr<DiscReader> &discReader, uint32_t offset) { std::optional<std::unique_ptr<WiiUContentsInformation>> WiiUContentsInformation::make_unique(std::shared_ptr<DiscReader> &discReader, uint32_t offset) {
uint32_t curOffset = offset; uint32_t curOffset = offset;
auto discContentHeaderOpt = WiiUDiscContentsHeader::make_unique(discReader, curOffset); auto discContentHeaderOpt = WiiUDiscContentsHeader::make_unique(discReader, curOffset);
if (!discContentHeaderOpt.has_value()) { if (!discContentHeaderOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to read WiiUDiscContentsHeader"); DEBUG_FUNCTION_LINE_ERR("Failed to read WiiUDiscContentsHeader");
return {}; return {};
} }
curOffset += WiiUDiscContentsHeader::LENGTH; curOffset += WiiUDiscContentsHeader::LENGTH;
auto partitionsOpt = WiiUPartitions::make_unique(discReader, curOffset, discContentHeaderOpt.value()->numberOfPartition, discContentHeaderOpt.value()->blockSize); auto partitionsOpt = WiiUPartitions::make_unique(discReader, curOffset, discContentHeaderOpt.value()->numberOfPartition, discContentHeaderOpt.value()->blockSize);
if (!partitionsOpt.has_value()) { if (!partitionsOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to read Partitions"); DEBUG_FUNCTION_LINE_ERR("Failed to read Partitions");
return {}; return {};
} }
curOffset += WiiUPartitions::LENGTH; curOffset += WiiUPartitions::LENGTH;
if (curOffset - offset != LENGTH) { if (curOffset - offset != LENGTH) {
DEBUG_FUNCTION_LINE("Unexpected offset"); DEBUG_FUNCTION_LINE_ERR("Unexpected offset");
return {}; return {};
} }
@ -45,9 +45,7 @@ std::optional<std::unique_ptr<WiiUContentsInformation>> WiiUContentsInformation:
std::move(partitionsOpt.value()))); std::move(partitionsOpt.value())));
} }
WiiUContentsInformation::WiiUContentsInformation(std::unique_ptr<WiiUDiscContentsHeader> pDiscContentHeader, WiiUContentsInformation::WiiUContentsInformation(std::unique_ptr<WiiUDiscContentsHeader> pDiscContentHeader,
std::unique_ptr<WiiUPartitions> pPartitions) : discContentHeader(std::move(pDiscContentHeader)), std::unique_ptr<WiiUPartitions> pPartitions) : discContentHeader(std::move(pDiscContentHeader)),
partitions(std::move(pPartitions)){ partitions(std::move(pPartitions)) {
}
};

View File

@ -30,7 +30,7 @@ public:
static uint32_t LENGTH; static uint32_t LENGTH;
static std::optional<std::unique_ptr<WiiUContentsInformation>> make_unique(const std::shared_ptr<DiscReader> &discReader, uint32_t offset); static std::optional<std::unique_ptr<WiiUContentsInformation>> make_unique(std::shared_ptr<DiscReader> &discReader, uint32_t offset);
private: private:
WiiUContentsInformation(std::unique_ptr<WiiUDiscContentsHeader> pDiscContentsHeader, std::unique_ptr<WiiUPartitions> pPartitions); WiiUContentsInformation(std::unique_ptr<WiiUDiscContentsHeader> pDiscContentsHeader, std::unique_ptr<WiiUPartitions> pPartitions);

View File

@ -15,36 +15,37 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/ ****************************************************************************/
#include "WiiUDiscContentsHeader.h" #include "WiiUDiscContentsHeader.h"
#include "utils/utils.h"
#include <coreinit/debug.h> #include <coreinit/debug.h>
#include <utils/blocksize/DiscBlockSize.h> #include <utils/blocksize/DiscBlockSize.h>
std::optional<std::unique_ptr<WiiUDiscContentsHeader>> WiiUDiscContentsHeader::make_unique(const std::shared_ptr<DiscReader> &discReader, uint32_t offset) { std::optional<std::unique_ptr<WiiUDiscContentsHeader>> WiiUDiscContentsHeader::make_unique(std::shared_ptr<DiscReader> &discReader, uint32_t offset) {
auto *buffer = (uint8_t *) malloc(LENGTH); auto buffer = make_unique_nothrow<uint8_t[]>(LENGTH);
if (!buffer) { if (!buffer) {
DEBUG_FUNCTION_LINE("Failed to alloc buffer"); DEBUG_FUNCTION_LINE_ERR("Failed to alloc buffer");
return {}; return {};
} }
if (!discReader->hasDiscKey) { if (!discReader->hasDiscKey) {
if (!discReader->readEncrypted(buffer, offset, LENGTH)) { DEBUG_FUNCTION_LINE_ERR();
DEBUG_FUNCTION_LINE("Failed to read data"); if (!discReader->readEncrypted(buffer.get(), offset, LENGTH)) {
DEBUG_FUNCTION_LINE_ERR("Failed to read data");
return {}; return {};
} }
} else { } else {
if (!discReader->readDecrypted(buffer, offset, 0, LENGTH, discReader->discKey, nullptr, true)) { if (!discReader->readDecrypted(buffer.get(), offset, 0, LENGTH, discReader->discKey, nullptr, true)) {
DEBUG_FUNCTION_LINE("Failed to read data"); DEBUG_FUNCTION_LINE_ERR("Failed to read data");
return {}; return {};
} }
} }
if (((uint32_t *) buffer)[0] != MAGIC) { if (((uint32_t *) buffer.get())[0] != MAGIC) {
DEBUG_FUNCTION_LINE("MAGIC mismatch"); DEBUG_FUNCTION_LINE_ERR("MAGIC mismatch");
return {}; return {};
} }
auto blockSize = DiscBlockSize(((uint32_t *) buffer)[1]); auto blockSize = DiscBlockSize(((uint32_t *) buffer.get())[1]);
std::array<uint8_t, 20> tocHash{}; std::array<uint8_t, 20> tocHash{};
memcpy(tocHash.data(), &buffer[8], 20); memcpy(tocHash.data(), &buffer[8], 20);
auto numberOfPartition = ((uint32_t *) buffer)[7]; auto numberOfPartition = ((uint32_t *) buffer.get())[7];
free(buffer);
return std::unique_ptr<WiiUDiscContentsHeader>(new WiiUDiscContentsHeader(blockSize, tocHash, numberOfPartition)); return std::unique_ptr<WiiUDiscContentsHeader>(new WiiUDiscContentsHeader(blockSize, tocHash, numberOfPartition));
} }

View File

@ -33,7 +33,7 @@ public:
static constexpr uint32_t LENGTH = 2048; static constexpr uint32_t LENGTH = 2048;
static constexpr uint32_t MAGIC = 0xCCA6E67B; static constexpr uint32_t MAGIC = 0xCCA6E67B;
static std::optional<std::unique_ptr<WiiUDiscContentsHeader>> make_unique(const std::shared_ptr<DiscReader> &discReader, uint32_t offset); static std::optional<std::unique_ptr<WiiUDiscContentsHeader>> make_unique(std::shared_ptr<DiscReader> &discReader, uint32_t offset);
private: private:
WiiUDiscContentsHeader(DiscBlockSize pSize, const std::array<uint8_t, 20> &pTocHash, uint32_t pNumberOfPartitions); WiiUDiscContentsHeader(DiscBlockSize pSize, const std::array<uint8_t, 20> &pTocHash, uint32_t pNumberOfPartitions);

View File

@ -26,11 +26,11 @@ WiiUDataPartition::WiiUDataPartition(
basePartition(std::move(pPartition)) { basePartition(std::move(pPartition)) {
} }
std::string WiiUDataPartition::getVolumeId() const & { const std::string &WiiUDataPartition::getVolumeId() const {
return basePartition->getVolumeId(); return basePartition->getVolumeId();
} }
std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> WiiUDataPartition::getVolumes() const & { const std::map<AddressInDiscBlocks, std::unique_ptr<VolumeHeader>> &WiiUDataPartition::getVolumes() const {
return basePartition->getVolumes(); return basePartition->getVolumes();
} }

View File

@ -29,17 +29,15 @@ public:
~WiiUDataPartition() override; ~WiiUDataPartition() override;
[[nodiscard]] std::string getVolumeId() const & override; [[nodiscard]] const std::string &getVolumeId() const override;
[[nodiscard]] std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> getVolumes() const & override; [[nodiscard]] const std::map<AddressInDiscBlocks, std::unique_ptr<VolumeHeader>> &getVolumes() const override;
[[nodiscard]] uint16_t getFileSystemDescriptor() const override; [[nodiscard]] uint16_t getFileSystemDescriptor() const override;
[[nodiscard]] uint64_t getSectionOffsetOnDefaultPartition() override; [[nodiscard]] uint64_t getSectionOffsetOnDefaultPartition() override;
std::shared_ptr<FST> fst;
private: private:
std::shared_ptr<FST> fst;
std::shared_ptr<WiiUPartition> basePartition; std::shared_ptr<WiiUPartition> basePartition;
}; };

View File

@ -15,23 +15,27 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/ ****************************************************************************/
#include "WiiUGMPartition.h" #include "WiiUGMPartition.h"
#include "WUD/entities/FST/FST.h"
#include "WUD/entities/TMD/Content.h"
WiiUGMPartition::WiiUGMPartition(std::shared_ptr<WiiUPartition> partition, WiiUGMPartition::WiiUGMPartition(std::unique_ptr<WiiUPartition> partition,
std::vector<uint8_t> pRawTicket, std::vector<uint8_t> pRawTicket,
std::vector<uint8_t> pRawTMD, std::vector<uint8_t> pRawTMD,
std::vector<uint8_t> pRawCert) std::vector<uint8_t> pRawCert,
std::string pathOnSIPartition)
: WiiUPartition(), : WiiUPartition(),
rawTicket(std::move(pRawTicket)), rawTicket(std::move(pRawTicket)),
rawTMD(std::move(pRawTMD)), rawTMD(std::move(pRawTMD)),
rawCert(std::move(pRawCert)), rawCert(std::move(pRawCert)),
pathOnSIPartition(std::move(pathOnSIPartition)),
basePartition(std::move(partition)) { basePartition(std::move(partition)) {
} }
std::string WiiUGMPartition::getVolumeId() const & { const std::string &WiiUGMPartition::getVolumeId() const {
return basePartition->getVolumeId(); return basePartition->getVolumeId();
} }
std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> WiiUGMPartition::getVolumes() const & { const std::map<AddressInDiscBlocks, std::unique_ptr<VolumeHeader>> &WiiUGMPartition::getVolumes() const {
return basePartition->getVolumes(); return basePartition->getVolumes();
} }

View File

@ -23,23 +23,40 @@
class WiiUGMPartition : public WiiUPartition { class WiiUGMPartition : public WiiUPartition {
public: public:
WiiUGMPartition(std::shared_ptr<WiiUPartition> partition, WiiUGMPartition(std::unique_ptr<WiiUPartition> partition,
std::vector<uint8_t> pRawTicket, std::vector<uint8_t> pRawTicket,
std::vector<uint8_t> pRawTMD, std::vector<uint8_t> pRawTMD,
std::vector<uint8_t> pRawCert); std::vector<uint8_t> pRawCert,
std::string pathOnSIPartition);
[[nodiscard]] std::string getVolumeId() const & override; [[nodiscard]] const std::string &getVolumeId() const override;
[[nodiscard]] std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> getVolumes() const & override; [[nodiscard]] const std::map<AddressInDiscBlocks, std::unique_ptr<VolumeHeader>> &getVolumes() const override;
[[nodiscard]] uint16_t getFileSystemDescriptor() const override; [[nodiscard]] uint16_t getFileSystemDescriptor() const override;
[[nodiscard]] uint64_t getSectionOffsetOnDefaultPartition() override; [[nodiscard]] uint64_t getSectionOffsetOnDefaultPartition() override;
[[nodiscard]] const std::string &getPathOnSIPartition() const {
return pathOnSIPartition;
}
[[nodiscard]] const std::vector<uint8_t> &getRawCert() const {
return rawCert;
}
[[nodiscard]] const std::vector<uint8_t> &getRawTicket() const {
return rawTicket;
}
[[nodiscard]] const std::vector<uint8_t> &getRawTMD() const {
return rawTMD;
}
private:
std::vector<uint8_t> rawTicket; std::vector<uint8_t> rawTicket;
std::vector<uint8_t> rawTMD; std::vector<uint8_t> rawTMD;
std::vector<uint8_t> rawCert; std::vector<uint8_t> rawCert;
std::string pathOnSIPartition;
private: std::unique_ptr<WiiUPartition> basePartition;
std::shared_ptr<WiiUPartition> basePartition;
}; };

View File

@ -25,63 +25,61 @@ uint64_t WiiUPartition::getSectionOffsetOnDefaultPartition() {
return volumes.begin()->first.getAddressInBytes(); return volumes.begin()->first.getAddressInBytes();
} }
std::optional<std::shared_ptr<WiiUPartition>> WiiUPartition::make_shared(const std::shared_ptr<DiscReader> &discReader, uint32_t offset, const DiscBlockSize &blockSize) { std::optional<std::unique_ptr<WiiUPartition>> WiiUPartition::make_unique(std::shared_ptr<DiscReader> &discReader, uint32_t offset, const DiscBlockSize &blockSize) {
auto buffer = (uint8_t *) malloc(LENGTH); // If we have the discKey, the content is encrypted but we don't know the IV.
if (buffer == nullptr) { // So in this case we read the 0x10 bytes before to the actual offset get the IV.
auto bufferReal = make_unique_nothrow<uint8_t[]>(discReader->hasDiscKey ? LENGTH + 0x10 : LENGTH);
if (!bufferReal) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory");
return {}; return {};
} }
uint8_t *buffer = bufferReal.get();
if (!discReader->hasDiscKey) { if (!discReader->hasDiscKey) {
if (!discReader->readEncrypted(buffer, offset, LENGTH)) { if (!discReader->readEncrypted(bufferReal.get(), offset, LENGTH)) {
return {}; return {};
} }
} else { } else {
auto bufferBigger = (uint8_t *) malloc(LENGTH + 0x10); if (offset < 0x10) {
if (bufferBigger == nullptr) { DEBUG_FUNCTION_LINE_ERR("Tried to read from an invalid offset");
OSFatal("Tried to read from an invalid offset");
}
if (!discReader->readDecrypted(bufferReal.get(), offset - 0x10, 0, LENGTH + 0x10, discReader->discKey, nullptr, true)) {
return {}; return {};
} }
if (!discReader->readDecrypted(bufferBigger, offset - 0x10, 0, LENGTH + 0x10, discReader->discKey, nullptr, true)) { buffer = bufferReal.get() + 0x10;
return {};
}
memcpy(buffer, bufferBigger + 0x10, LENGTH);
free(bufferBigger);
} }
char name[32]; char name[32];
memset(name, 0, sizeof(name)); memset(name, 0, sizeof(name));
memcpy(name, buffer, 31); memcpy(name, buffer, 31);
auto volumeId = name; std::string volumeId = name;
uint8_t num = buffer[31]; uint8_t num = buffer[31];
std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> volumes; std::map<AddressInDiscBlocks, std::unique_ptr<VolumeHeader>> volumes;
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
auto address = *((uint32_t *) &buffer[32 + (i * 4)]); auto address = *((uint32_t *) &buffer[32 + (i * 4)]);
AddressInDiscBlocks discLbaAddress = AddressInDiscBlocks(blockSize, address); AddressInDiscBlocks discLbaAddress = AddressInDiscBlocks(blockSize, address);
auto vh = VolumeHeader::make_shared(discReader, discLbaAddress.getAddressInBytes()); auto vh = VolumeHeader::make_unique(discReader, discLbaAddress.getAddressInBytes());
if (!vh.has_value()) { if (!vh.has_value()) {
free(buffer);
return {}; return {};
} }
volumes[discLbaAddress] = vh.value(); volumes[discLbaAddress] = std::move(vh.value());
} }
auto fileSystemDescriptor = ((uint16_t *) &buffer[64])[0]; auto fileSystemDescriptor = ((uint16_t *) &buffer[64])[0];
free(buffer);
return std::unique_ptr<WiiUPartition>(new WiiUPartition( return std::unique_ptr<WiiUPartition>(new WiiUPartition(
volumeId, volumeId,
volumes, std::move(volumes),
fileSystemDescriptor)); fileSystemDescriptor));
} }
std::string WiiUPartition::getVolumeId() const & { const std::string &WiiUPartition::getVolumeId() const {
return volumeId; return volumeId;
} }
std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> WiiUPartition::getVolumes() const & { const std::map<AddressInDiscBlocks, std::unique_ptr<VolumeHeader>> &WiiUPartition::getVolumes() const {
return volumes; return volumes;
} }

View File

@ -18,7 +18,6 @@
#include "volumes/VolumeHeader.h" #include "volumes/VolumeHeader.h"
#include <map> #include <map>
#include <memory>
#include <utility> #include <utility>
#include <utils/blocksize/AddressInDiscBlocks.h> #include <utils/blocksize/AddressInDiscBlocks.h>
#include <utils/blocksize/DiscBlockSize.h> #include <utils/blocksize/DiscBlockSize.h>
@ -32,23 +31,23 @@ public:
virtual uint64_t getSectionOffsetOnDefaultPartition(); virtual uint64_t getSectionOffsetOnDefaultPartition();
[[nodiscard]] virtual std::string getVolumeId() const &; [[nodiscard]] virtual const std::string &getVolumeId() const;
[[nodiscard]] virtual std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> getVolumes() const &; [[nodiscard]] virtual const std::map<AddressInDiscBlocks, std::unique_ptr<VolumeHeader>> &getVolumes() const;
[[nodiscard]] virtual uint16_t getFileSystemDescriptor() const; [[nodiscard]] virtual uint16_t getFileSystemDescriptor() const;
static std::optional<std::shared_ptr<WiiUPartition>> make_shared(const std::shared_ptr<DiscReader> &discReader, uint32_t offset, const DiscBlockSize &blockSize); static std::optional<std::unique_ptr<WiiUPartition>> make_unique(std::shared_ptr<DiscReader> &discReader, uint32_t offset, const DiscBlockSize &blockSize);
protected: protected:
WiiUPartition() = default; WiiUPartition() = default;
private: private:
WiiUPartition(char *pVolumeId, std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> pVolumes, uint16_t pFileSystemDescriptor) WiiUPartition(std::string pVolumeId, std::map<AddressInDiscBlocks, std::unique_ptr<VolumeHeader>> pVolumes, uint16_t pFileSystemDescriptor)
: volumeId(pVolumeId), volumes(std::move(pVolumes)), fileSystemDescriptor(pFileSystemDescriptor) { : volumeId(std::move(pVolumeId)), volumes(std::move(pVolumes)), fileSystemDescriptor(pFileSystemDescriptor) {
} }
std::string volumeId; const std::string volumeId;
std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> volumes; std::map<AddressInDiscBlocks, std::unique_ptr<VolumeHeader>> volumes;
uint16_t fileSystemDescriptor{}; uint16_t fileSystemDescriptor{};
}; };

View File

@ -14,18 +14,18 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/ ****************************************************************************/
#include <coreinit/debug.h> #include "WiiUPartitions.h"
#include <utils/FSTUtils.h>
#include "WiiUDataPartition.h" #include "WiiUDataPartition.h"
#include "WiiUGMPartition.h" #include "WiiUGMPartition.h"
#include "WiiUPartitions.h" #include <algorithm>
#include <coreinit/debug.h>
#include <utility> #include <utility>
#include <utils/FSTUtils.h>
bool WiiUPartitions::getFSTEntryAsByte(std::string &filePath, bool WiiUPartitions::getFSTEntryAsByte(std::string &filePath,
const std::shared_ptr<FST> &fst, const std::shared_ptr<FST> &fst,
const AddressInDiscBlocks &volumeAddress, const AddressInDiscBlocks &volumeAddress,
const std::shared_ptr<DiscReader> &discReader, std::shared_ptr<DiscReader> &discReader,
std::vector<uint8_t> &out_data) { std::vector<uint8_t> &out_data) {
auto entryOpt = FSTUtils::getFSTEntryByFullPath(fst->getRootEntry(), filePath); auto entryOpt = FSTUtils::getFSTEntryByFullPath(fst->getRootEntry(), filePath);
if (!entryOpt.has_value()) { if (!entryOpt.has_value()) {
@ -56,136 +56,148 @@ bool WiiUPartitions::getFSTEntryAsByte(std::string &filePath,
} }
std::optional<std::unique_ptr<WiiUPartitions>> std::optional<std::unique_ptr<WiiUPartitions>>
WiiUPartitions::make_unique(const std::shared_ptr<DiscReader> &discReader, uint32_t offset, uint32_t numberOfPartitions, const DiscBlockSize &blockSize) { WiiUPartitions::make_unique(std::shared_ptr<DiscReader> &discReader, uint32_t offset, uint32_t numberOfPartitions, const DiscBlockSize &blockSize) {
std::vector<std::shared_ptr<WiiUPartition>> tmp; std::vector<std::unique_ptr<WiiUPartition>> tmp;
std::vector<std::shared_ptr<WiiUPartition>> partitions; std::vector<std::shared_ptr<WiiUPartition>> result;
partitions.reserve(numberOfPartitions); result.reserve(numberOfPartitions);
tmp.reserve(numberOfPartitions); tmp.reserve(numberOfPartitions);
for (uint32_t i = 0; i < numberOfPartitions; i++) { for (uint32_t i = 0; i < numberOfPartitions; i++) {
auto partitionOpt = WiiUPartition::make_shared(discReader, offset + (i * 128), blockSize); auto partitionOpt = WiiUPartition::make_unique(discReader, offset + (i * 128), blockSize);
if (!partitionOpt.has_value()) { if (!partitionOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to read partition"); DEBUG_FUNCTION_LINE_ERR("Failed to read partition");
return {}; return {};
} }
tmp.push_back(partitionOpt.value()); tmp.push_back(std::move(partitionOpt.value()));
}
std::optional<std::shared_ptr<WiiUPartition>> SIPartition;
for (auto &partition : tmp) {
if (partition->getVolumeId().starts_with("SI")) {
SIPartition = partition;
break;
}
} }
if (SIPartition.has_value()) { auto SIPartitionOpt = movePartitionFromList(tmp, "SI");
for (auto const &[key, val] : SIPartition.value()->getVolumes()) {
auto volumeAddress = key;
auto volumeAddressInBytes = volumeAddress.getAddressInBytes();
auto volumeHeader = val;
std::vector<uint8_t> fstData; if (!SIPartitionOpt) {
fstData.resize(volumeHeader->FSTSize); DEBUG_FUNCTION_LINE_ERR("Failed to find SI partition");
return {};
}
if (!discReader->hasDiscKey) { auto SIPartition = std::move(SIPartitionOpt.value());
if (!discReader->readEncrypted(fstData.data(), volumeAddressInBytes + volumeHeader->FSTAddress.getAddressInBytes(),
volumeHeader->FSTSize)) { for (auto const &[key, val] : SIPartition->getVolumes()) {
DEBUG_FUNCTION_LINE("Failed to read FST"); auto volumeAddress = key;
return {}; auto volumeAddressInBytes = volumeAddress.getAddressInBytes();
} auto &volumeHeader = val;
} else {
if (!discReader->readDecrypted(fstData.data(), volumeAddressInBytes + volumeHeader->FSTAddress.getAddressInBytes(), 0, volumeHeader->FSTSize, std::vector<uint8_t> fstData;
discReader->discKey, nullptr, true)) { fstData.resize(volumeHeader->FSTSize);
DEBUG_FUNCTION_LINE("Failed to read FST");
return {}; if (!discReader->hasDiscKey) {
} if (!discReader->readEncrypted(fstData.data(), volumeAddressInBytes + volumeHeader->FSTAddress.getAddressInBytes(),
volumeHeader->FSTSize)) {
DEBUG_FUNCTION_LINE_ERR("Failed to read FST");
return {};
} }
} else {
if (!discReader->readDecrypted(fstData.data(), volumeAddressInBytes + volumeHeader->FSTAddress.getAddressInBytes(), 0, volumeHeader->FSTSize,
discReader->discKey, nullptr, true)) {
DEBUG_FUNCTION_LINE_ERR("Failed to read FST");
return {};
}
}
auto siFST = FST::make_shared(fstData, 0, volumeHeader->blockSize); auto siFST = FST::make_shared(fstData, 0, volumeHeader->blockSize);
if (!siFST.has_value()) { if (!siFST.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse FST"); DEBUG_FUNCTION_LINE_ERR("Failed to parse FST");
return {};
}
for (auto &child : siFST.value()->getRootEntry()->getDirChildren()) {
std::vector<uint8_t> bufferTicket;
std::string tikFilePath = std::string(child->getFullPath() + '/' + WUD_TICKET_FILENAME);
if (!getFSTEntryAsByte(tikFilePath, siFST.value(), volumeAddress, discReader, bufferTicket)) {
DEBUG_FUNCTION_LINE_ERR("Failed to read FSTEntry");
return {}; return {};
} }
for (auto &child : siFST.value()->getRootEntry()->getDirChildren()) { std::vector<uint8_t> bufferTMD;
std::vector<uint8_t> bufferTicket; std::string tmdFilePath = std::string(child->getFullPath() + '/' + WUD_TMD_FILENAME);
std::string tikFilePath = std::string(child->getFullPath() + '/' + WUD_TICKET_FILENAME); if (!getFSTEntryAsByte(tmdFilePath, siFST.value(), volumeAddress, discReader, bufferTMD)) {
if (!getFSTEntryAsByte(tikFilePath, siFST.value(), volumeAddress, discReader, bufferTicket)) { DEBUG_FUNCTION_LINE_ERR("Failed to read FSTEntry");
DEBUG_FUNCTION_LINE("Failted to read FSTEntry"); return {};
return {};
}
std::vector<uint8_t> bufferTMD;
std::string tmdFilePath = std::string(child->getFullPath() + '/' + WUD_TMD_FILENAME);
if (!getFSTEntryAsByte(tmdFilePath, siFST.value(), volumeAddress, discReader, bufferTMD)) {
DEBUG_FUNCTION_LINE("Failted to read FSTEntry");
return {};
}
std::vector<uint8_t> bufferCert;
std::string certFilePath = std::string(child->getFullPath() + '/' + WUD_CERT_FILENAME);
if (!getFSTEntryAsByte(certFilePath, siFST.value(), volumeAddress, discReader, bufferCert)) {
DEBUG_FUNCTION_LINE("Failted to read FSTEntry");
return {};
}
char partitionNameRaw[0x12];
memset(partitionNameRaw, 0, 0x12);
snprintf(partitionNameRaw, 0x11, "%016llX", *((uint64_t *) &bufferTicket[0x1DC]));
std::string partitionName = std::string("GM") + partitionNameRaw;
std::optional<std::shared_ptr<WiiUPartition>> curPartition;
for (auto &partition : tmp) {
if (partition->getVolumeId().starts_with(partitionName)) {
curPartition = partition;
break;
}
}
if (!curPartition.has_value()) {
DEBUG_FUNCTION_LINE("Failed to find partition");
return {};
}
auto gmPartition = std::shared_ptr<WiiUPartition>(new WiiUGMPartition(curPartition.value(), bufferTicket, bufferTMD, bufferCert));
partitions.push_back(gmPartition);
} }
std::vector<uint8_t> bufferCert;
std::string certFilePath = std::string(child->getFullPath() + '/' + WUD_CERT_FILENAME);
if (!getFSTEntryAsByte(certFilePath, siFST.value(), volumeAddress, discReader, bufferCert)) {
DEBUG_FUNCTION_LINE_ERR("Failed to read FSTEntry");
return {};
}
char partitionNameRaw[0x12];
memset(partitionNameRaw, 0, 0x12);
snprintf(partitionNameRaw, 0x11, "%016llX", *((uint64_t *) &bufferTicket[0x1DC]));
std::string partitionName = std::string("GM") + partitionNameRaw;
auto partitionOpt = movePartitionFromList(tmp, partitionName);
if (!partitionOpt) {
DEBUG_FUNCTION_LINE_ERR("Failed to find partition %s", partitionName.c_str());
return {};
}
auto gmPartition = std::unique_ptr<WiiUPartition>(new WiiUGMPartition(std::move(partitionOpt.value()), bufferTicket, bufferTMD, bufferCert, child->getFullPath()));
result.push_back(std::move(gmPartition));
} }
} }
for (auto &partition : tmp) { auto it = tmp.begin();
while (it != tmp.end()) {
auto &partition = *it;
if (partition->getVolumeId().starts_with("GM")) { if (partition->getVolumeId().starts_with("GM")) {
continue; continue;
} }
if (partition->getVolumes().size() != 1) { if (partition->getVolumes().size() != 1) {
OSFatal("We can't handle more or less than one partion address yet."); DEBUG_FUNCTION_LINE_ERR("We can't handle more or less than one partition address yet.");
OSFatal("We can't handle more or less than one partition address yet.");
} }
auto volumeAddress = partition->getVolumes().begin()->first; auto &volumeAddress = partition->getVolumes().begin()->first;
auto vh = partition->getVolumes().begin()->second; auto &vh = partition->getVolumes().begin()->second;
std::vector<uint8_t> fstData; std::vector<uint8_t> fstData;
fstData.resize(vh->FSTSize); fstData.resize(vh->FSTSize);
if (!discReader->hasDiscKey) { if (!discReader->hasDiscKey) {
if (!discReader->readEncrypted(fstData.data(), volumeAddress.getAddressInBytes() + vh->FSTAddress.getAddressInBytes(), vh->FSTSize)) { if (!discReader->readEncrypted(fstData.data(), volumeAddress.getAddressInBytes() + vh->FSTAddress.getAddressInBytes(), vh->FSTSize)) {
DEBUG_FUNCTION_LINE_ERR("WiiUPartition: Failed to read encrypted");
OSFatal("WiiUPartition: Failed to read encrypted"); OSFatal("WiiUPartition: Failed to read encrypted");
} }
} else { } else {
if (!discReader->readDecrypted(fstData.data(), volumeAddress.getAddressInBytes() + vh->FSTAddress.getAddressInBytes(), 0, vh->FSTSize, if (!discReader->readDecrypted(fstData.data(), volumeAddress.getAddressInBytes() + vh->FSTAddress.getAddressInBytes(), 0, vh->FSTSize,
discReader->discKey, nullptr, true)) { discReader->discKey, nullptr, true)) {
DEBUG_FUNCTION_LINE_ERR("WiiUPartition: Failed to read encrypted");
OSFatal("WiiUPartition: Failed to read encrypted"); OSFatal("WiiUPartition: Failed to read encrypted");
} }
} }
auto fstOpt = FST::make_shared(fstData, 0, vh->blockSize); auto fstOpt = FST::make_shared(fstData, 0, vh->blockSize);
if (!fstOpt.has_value()) { if (!fstOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse FST"); DEBUG_FUNCTION_LINE_ERR("Failed to parse FST");
return {}; return {};
} }
partitions.push_back(std::shared_ptr<WiiUPartition>(new WiiUDataPartition(partition, fstOpt.value())));
auto partitionCopy = std::move(*it);
it = tmp.erase(it);
result.push_back(std::unique_ptr<WiiUPartition>(new WiiUDataPartition(std::move(partitionCopy), fstOpt.value())));
} }
return std::unique_ptr<WiiUPartitions>(new WiiUPartitions(partitions)); return std::unique_ptr<WiiUPartitions>(new WiiUPartitions(std::move(result)));
} }
WiiUPartitions::WiiUPartitions(std::vector<std::shared_ptr<WiiUPartition>> pPartitions) : partitions(std::move(pPartitions)) { WiiUPartitions::WiiUPartitions(std::vector<std::shared_ptr<WiiUPartition>> pPartitions) : partitions(std::move(pPartitions)) {
} }
std::optional<std::unique_ptr<WiiUPartition>> WiiUPartitions::movePartitionFromList(std::vector<std::unique_ptr<WiiUPartition>> &list, std::string partitionName) {
auto siPartitionIt = std::find_if(std::begin(list), std::end(list), [partitionName](auto &partition) { return partition->getVolumeId().starts_with(partitionName); });
if (siPartitionIt == std::end(list)) {
return {};
}
auto SIPartition = std::move(*siPartitionIt);
list.erase(siPartitionIt);
return SIPartition;
}

View File

@ -34,18 +34,20 @@ public:
static bool getFSTEntryAsByte(std::string &filePath, static bool getFSTEntryAsByte(std::string &filePath,
const std::shared_ptr<FST> &fst, const std::shared_ptr<FST> &fst,
const AddressInDiscBlocks &volumeAddress, const AddressInDiscBlocks &volumeAddress,
const std::shared_ptr<DiscReader> &discReader, std::shared_ptr<DiscReader> &discReader,
std::vector<uint8_t> &out_data); std::vector<uint8_t> &out_data);
std::vector<std::shared_ptr<WiiUPartition>> partitions; std::vector<std::shared_ptr<WiiUPartition>> partitions;
static constexpr uint32_t LENGTH = 30720; static constexpr uint32_t LENGTH = 30720;
static std::optional<std::unique_ptr<WiiUPartitions>> make_unique( static std::optional<std::unique_ptr<WiiUPartitions>> make_unique(
const std::shared_ptr<DiscReader> &discReader, std::shared_ptr<DiscReader> &discReader,
uint32_t offset, uint32_t offset,
uint32_t numberOfPartitions, uint32_t numberOfPartitions,
const DiscBlockSize &blockSize); const DiscBlockSize &blockSize);
private: private:
explicit WiiUPartitions(std::vector<std::shared_ptr<WiiUPartition>> pPartitions); explicit WiiUPartitions(std::vector<std::shared_ptr<WiiUPartition>> pPartitions);
static std::optional<std::unique_ptr<WiiUPartition>> movePartitionFromList(std::vector<std::unique_ptr<WiiUPartition>> &list, std::string partitionName);
}; };

View File

@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/ ****************************************************************************/
#include "H3HashArray.h" #include "H3HashArray.h"
#include "utils/utils.h"
#include <coreinit/debug.h> #include <coreinit/debug.h>
#include <cstring> #include <cstring>
@ -22,16 +23,12 @@ H3HashArray::H3HashArray(uint8_t *pData, uint32_t pSize) {
size = pSize; size = pSize;
data = nullptr; data = nullptr;
if (pSize > 0) { if (pSize > 0) {
data = (uint8_t *) malloc(pSize); data = make_unique_nothrow<uint8_t[]>(pSize);
if (data == nullptr) { if (!data) {
OSFatal("H3HashArray: Failed to alloc"); OSFatal("H3HashArray: Failed to alloc");
} }
memcpy(data, pData, pSize); memcpy(data.get(), pData, pSize);
} }
} }
H3HashArray::~H3HashArray() { H3HashArray::~H3HashArray() = default;
if (data) {
free(data);
}
}

View File

@ -18,6 +18,7 @@
#include <cstdint> #include <cstdint>
#include <malloc.h> #include <malloc.h>
#include <memory>
class H3HashArray { class H3HashArray {
@ -26,6 +27,6 @@ public:
~H3HashArray(); ~H3HashArray();
uint8_t *data = nullptr; std::unique_ptr<uint8_t[]> data;
uint8_t size; uint8_t size;
}; };

View File

@ -22,8 +22,8 @@
uint32_t VolumeHeader::MAGIC = 0xCC93A4F5; uint32_t VolumeHeader::MAGIC = 0xCC93A4F5;
std::vector<std::shared_ptr<H3HashArray>> VolumeHeader::getH3HashArray(uint8_t *h3Data, uint32_t pNumberOfH3HashArray, uint32_t pH3HashArrayListSize) { std::vector<std::unique_ptr<H3HashArray>> VolumeHeader::getH3HashArray(uint8_t *h3Data, uint32_t pNumberOfH3HashArray, uint32_t pH3HashArrayListSize) {
std::vector<std::shared_ptr<H3HashArray>> arrayList; std::vector<std::unique_ptr<H3HashArray>> arrayList;
if (pNumberOfH3HashArray == 0) { if (pNumberOfH3HashArray == 0) {
return arrayList; return arrayList;
} }
@ -37,30 +37,28 @@ std::vector<std::shared_ptr<H3HashArray>> VolumeHeader::getH3HashArray(uint8_t *
curEnd = offsetPtr[1]; curEnd = offsetPtr[1];
} }
arrayList.push_back(std::make_shared<H3HashArray>(h3Data + curOffset, curEnd - curOffset)); arrayList.push_back(std::make_unique<H3HashArray>(h3Data + curOffset, curEnd - curOffset));
} }
return arrayList; return arrayList;
} }
std::optional<std::shared_ptr<VolumeHeader>> VolumeHeader::make_shared(const std::shared_ptr<DiscReader> &discReader, uint64_t offset) { std::optional<std::unique_ptr<VolumeHeader>> VolumeHeader::make_unique(std::shared_ptr<DiscReader> &discReader, uint64_t offset) {
auto buffer = (uint8_t *) malloc(64); auto buffer = make_unique_nothrow<uint8_t[]>((size_t) 64);
if (buffer == nullptr) { if (!buffer) {
DEBUG_FUNCTION_LINE("Failed to alloc buffer"); DEBUG_FUNCTION_LINE_ERR("Failed to alloc buffer");
return {}; return {};
} }
if (!discReader->readEncrypted(buffer, offset, 64)) { if (!discReader->readEncrypted(buffer.get(), offset, 64)) {
free(buffer); DEBUG_FUNCTION_LINE_ERR("Failed to read data");
DEBUG_FUNCTION_LINE("Failed to read data");
return {}; return {};
} }
auto *bufferUint = (uint32_t *) buffer; auto *bufferUint = (uint32_t *) buffer.get();
if (bufferUint[0] != MAGIC) { if (bufferUint[0] != MAGIC) {
DEBUG_FUNCTION_LINE("MAGIC mismatch"); DEBUG_FUNCTION_LINE_ERR("MAGIC mismatch");
free(buffer);
return {}; return {};
} }
@ -76,26 +74,22 @@ std::optional<std::shared_ptr<VolumeHeader>> VolumeHeader::make_shared(const std
auto minorVersion = buffer[39]; auto minorVersion = buffer[39];
auto expiringMajorVersion = buffer[40]; auto expiringMajorVersion = buffer[40];
free(buffer); auto alignedH3ArrayListSize = ROUNDUP(h3HashArrayListSize, 16);
auto bufferH3 = make_unique_nothrow<uint8_t[]>(alignedH3ArrayListSize);
auto bufferH3 = (uint8_t *) malloc(ROUNDUP(h3HashArrayListSize, 16)); if (!bufferH3) {
if (bufferH3 == nullptr) { DEBUG_FUNCTION_LINE_ERR("Failed to alloc h3 buffer");
DEBUG_FUNCTION_LINE("Failed to alloc h3 buffer");
return {}; return {};
} }
if (!discReader->readEncrypted(bufferH3, offset + 64, ROUNDUP(h3HashArrayListSize, 16))) { if (!discReader->readEncrypted(bufferH3.get(), offset + 64, alignedH3ArrayListSize)) {
DEBUG_FUNCTION_LINE("Failed to read h3 data"); DEBUG_FUNCTION_LINE_ERR("Failed to read h3 data");
free(bufferH3);
return {}; return {};
} }
auto h3HashArrayList = getH3HashArray(bufferH3, numberOfH3HashArray, h3HashArrayListSize); auto h3HashArrayList = getH3HashArray(bufferH3.get(), numberOfH3HashArray, h3HashArrayListSize);
free(bufferH3);
return std::unique_ptr<VolumeHeader>( return std::unique_ptr<VolumeHeader>(
new VolumeHeader(blockSize, volumeSize, FSTSize, FSTAddress, FSTHashMode, encryptType, majorVersion, minorVersion, expiringMajorVersion, h3HashArrayList, h3HashArrayListSize, new VolumeHeader(blockSize, volumeSize, FSTSize, FSTAddress, FSTHashMode, encryptType, majorVersion, minorVersion, expiringMajorVersion, std::move(h3HashArrayList), h3HashArrayListSize,
numberOfH3HashArray)); numberOfH3HashArray));
} }
@ -108,7 +102,7 @@ VolumeHeader::VolumeHeader(const VolumeBlockSize &pBlockSize,
uint8_t pMajorVersion, uint8_t pMajorVersion,
uint8_t pMinorVersion, uint8_t pMinorVersion,
uint8_t pExpiringMajorVersion, uint8_t pExpiringMajorVersion,
std::vector<std::shared_ptr<H3HashArray>> pH3HashArrayList, std::vector<std::unique_ptr<H3HashArray>> pH3HashArrayList,
uint32_t pH3HashArrayListSize, uint32_t pH3HashArrayListSize,
uint32_t pNumberOfH3HashArray) : blockSize(pBlockSize), uint32_t pNumberOfH3HashArray) : blockSize(pBlockSize),
volumeSize(std::move(pVolumeSize)), volumeSize(std::move(pVolumeSize)),

View File

@ -31,7 +31,7 @@
class VolumeHeader { class VolumeHeader {
public: public:
static std::vector<std::shared_ptr<H3HashArray>> getH3HashArray(uint8_t *h3Data, uint32_t numberOfH3HashArray, uint32_t h3HashArrayListSize); static std::vector<std::unique_ptr<H3HashArray>> getH3HashArray(uint8_t *h3Data, uint32_t numberOfH3HashArray, uint32_t h3HashArrayListSize);
static uint32_t MAGIC; static uint32_t MAGIC;
VolumeBlockSize blockSize; VolumeBlockSize blockSize;
@ -43,12 +43,12 @@ public:
uint8_t majorVersion; uint8_t majorVersion;
uint8_t minorVersion; uint8_t minorVersion;
uint8_t expiringMajorVersion; uint8_t expiringMajorVersion;
std::vector<std::shared_ptr<H3HashArray>> h3HashArrayList; std::vector<std::unique_ptr<H3HashArray>> h3HashArrayList;
uint32_t h3HashArrayListSize; uint32_t h3HashArrayListSize;
uint32_t numberOfH3HashArray; uint32_t numberOfH3HashArray;
static std::optional<std::shared_ptr<VolumeHeader>> make_shared(const std::shared_ptr<DiscReader> &discReader, uint64_t offset); static std::optional<std::unique_ptr<VolumeHeader>> make_unique(std::shared_ptr<DiscReader> &discReader, uint64_t offset);
private: private:
VolumeHeader( VolumeHeader(
@ -61,7 +61,7 @@ private:
uint8_t pMajorVersion, uint8_t pMajorVersion,
uint8_t pMinorVersion, uint8_t pMinorVersion,
uint8_t pExpiringMajorVersion, uint8_t pExpiringMajorVersion,
std::vector<std::shared_ptr<H3HashArray>> pH3HashArrayList, std::vector<std::unique_ptr<H3HashArray>> pH3HashArrayList,
uint32_t pH3HashArrayListSize, uint32_t pH3HashArrayListSize,
uint32_t pNumberOfH3HashArray); uint32_t pNumberOfH3HashArray);
}; };

View File

@ -25,7 +25,7 @@ std::optional<std::shared_ptr<FST>> FST::make_shared(const std::vector<uint8_t>
uint32_t curOffset = offset; uint32_t curOffset = offset;
if (curOffset + FSTHeader::LENGTH > data.size()) { if (curOffset + FSTHeader::LENGTH > data.size()) {
DEBUG_FUNCTION_LINE("Not enough data to parse the FSTHeader"); DEBUG_FUNCTION_LINE_ERR("Not enough data to parse the FSTHeader");
return {}; return {};
} }
@ -34,14 +34,14 @@ std::optional<std::shared_ptr<FST>> FST::make_shared(const std::vector<uint8_t>
auto headerOpt = FSTHeader::make_unique(fstData); auto headerOpt = FSTHeader::make_unique(fstData);
if (!headerOpt.has_value()) { if (!headerOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse FSTHeader"); DEBUG_FUNCTION_LINE_ERR("Failed to parse FSTHeader");
return {}; return {};
} }
curOffset += FSTHeader::LENGTH; curOffset += FSTHeader::LENGTH;
uint32_t sectionEntriesDataSize = headerOpt.value()->numberOfSections * SectionEntry::LENGTH; uint32_t sectionEntriesDataSize = headerOpt.value()->numberOfSections * SectionEntry::LENGTH;
if (curOffset + sectionEntriesDataSize > data.size()) { if (curOffset + sectionEntriesDataSize > data.size()) {
DEBUG_FUNCTION_LINE("Not enough data to parse the SectionEntries"); DEBUG_FUNCTION_LINE_ERR("Not enough data to parse the SectionEntries");
return {}; return {};
} }
@ -51,7 +51,7 @@ std::optional<std::shared_ptr<FST>> FST::make_shared(const std::vector<uint8_t>
auto sectionEntriesOpt = SectionEntries::make_shared(sectionEntriesData, headerOpt.value()->numberOfSections, blockSize); auto sectionEntriesOpt = SectionEntries::make_shared(sectionEntriesData, headerOpt.value()->numberOfSections, blockSize);
if (!sectionEntriesOpt.has_value()) { if (!sectionEntriesOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse FSTHeader"); DEBUG_FUNCTION_LINE_ERR("Failed to parse FSTHeader");
return {}; return {};
} }
curOffset += sectionEntriesOpt.value()->getSizeInBytes(); curOffset += sectionEntriesOpt.value()->getSizeInBytes();
@ -65,13 +65,13 @@ std::optional<std::shared_ptr<FST>> FST::make_shared(const std::vector<uint8_t>
auto stringTableOpt = StringTable::make_shared(data, stringTableOffset, lastEntryNumber); auto stringTableOpt = StringTable::make_shared(data, stringTableOffset, lastEntryNumber);
if (!stringTableOpt.has_value()) { if (!stringTableOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse StringTable"); DEBUG_FUNCTION_LINE_ERR("Failed to parse StringTable");
return {}; return {};
} }
auto nodeEntriesOpt = NodeEntries::make_unique(data, curOffset, sectionEntriesOpt.value(), stringTableOpt.value(), headerOpt.value()->blockSize); auto nodeEntriesOpt = NodeEntries::make_unique(data, curOffset, sectionEntriesOpt.value(), stringTableOpt.value(), headerOpt.value()->blockSize);
if (!nodeEntriesOpt.has_value()) { if (!nodeEntriesOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse NodeEntries"); DEBUG_FUNCTION_LINE_ERR("Failed to parse NodeEntries");
return {}; return {};
} }

View File

@ -21,7 +21,7 @@
std::optional<std::unique_ptr<FSTHeader>> FSTHeader::make_unique(const std::array<uint8_t, FSTHeader::LENGTH> &data) { std::optional<std::unique_ptr<FSTHeader>> FSTHeader::make_unique(const std::array<uint8_t, FSTHeader::LENGTH> &data) {
auto *dataAsUint = (uint32_t *) data.data(); auto *dataAsUint = (uint32_t *) data.data();
if ((dataAsUint[0] & 0xFFFFFF00) != 0x46535400) { if ((dataAsUint[0] & 0xFFFFFF00) != 0x46535400) {
DEBUG_FUNCTION_LINE("FST Header magic was wrong"); DEBUG_FUNCTION_LINE_ERR("FST Header magic was wrong");
return {}; return {};
} }
auto FSTVersion = data[3]; auto FSTVersion = data[3];

View File

@ -24,13 +24,13 @@ DirectoryEntry::parseData(const std::array<uint8_t, NodeEntry::LENGTH> &data, co
auto lastEntryNumber = ((uint32_t *) &data[8])[0]; auto lastEntryNumber = ((uint32_t *) &data[8])[0];
auto stringNameOpt = stringTable->getStringEntry(param.uint24); auto stringNameOpt = stringTable->getStringEntry(param.uint24);
if (!stringNameOpt.has_value()) { if (!stringNameOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to get string name"); DEBUG_FUNCTION_LINE_ERR("Failed to get string name");
return {}; return {};
} }
auto sectionEntryOpt = sectionEntries->getSection(param.sectionNumber); auto sectionEntryOpt = sectionEntries->getSection(param.sectionNumber);
if (!sectionEntryOpt.has_value()) { if (!sectionEntryOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to get section entry"); DEBUG_FUNCTION_LINE_ERR("Failed to get section entry");
return {}; return {};
} }

View File

@ -32,13 +32,13 @@ FileEntry::parseData(const std::array<uint8_t, NodeEntry::LENGTH> &data,
auto stringNameOpt = stringTable->getStringEntry(param.uint24); auto stringNameOpt = stringTable->getStringEntry(param.uint24);
if (!stringNameOpt.has_value()) { if (!stringNameOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to get string name"); DEBUG_FUNCTION_LINE_ERR("Failed to get string name");
return {}; return {};
} }
auto sectionEntryOpt = sectionEntries->getSection(param.sectionNumber); auto sectionEntryOpt = sectionEntries->getSection(param.sectionNumber);
if (!sectionEntryOpt.has_value()) { if (!sectionEntryOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to get section entry"); DEBUG_FUNCTION_LINE_ERR("Failed to get section entry");
return {}; return {};
} }

View File

@ -26,7 +26,7 @@ std::optional<std::shared_ptr<NodeEntry>> NodeEntries::DeserializeImpl(const std
const SectionBlockSize &pBlockSize) { const SectionBlockSize &pBlockSize) {
auto nodeEntry = NodeEntry::AutoDeserialize(pData, pOffset, pParent, pEntryNumber, pSectionEntries, pStringTable, pBlockSize); auto nodeEntry = NodeEntry::AutoDeserialize(pData, pOffset, pParent, pEntryNumber, pSectionEntries, pStringTable, pBlockSize);
if (!nodeEntry.has_value()) { if (!nodeEntry.has_value()) {
DEBUG_FUNCTION_LINE("Failed to AutoDeserialize NodeEntry"); DEBUG_FUNCTION_LINE_ERR("Failed to AutoDeserialize NodeEntry");
return {}; return {};
} }
auto asDirEntry = std::dynamic_pointer_cast<DirectoryEntry>(nodeEntry.value()); auto asDirEntry = std::dynamic_pointer_cast<DirectoryEntry>(nodeEntry.value());
@ -36,7 +36,7 @@ std::optional<std::shared_ptr<NodeEntry>> NodeEntries::DeserializeImpl(const std
auto entry = NodeEntries::DeserializeImpl(pData, pOffset + (curEntryNumber - asDirEntry->entryNumber) * NodeEntry::LENGTH, auto entry = NodeEntries::DeserializeImpl(pData, pOffset + (curEntryNumber - asDirEntry->entryNumber) * NodeEntry::LENGTH,
asDirEntry, curEntryNumber, pSectionEntries, pStringTable, pBlockSize); asDirEntry, curEntryNumber, pSectionEntries, pStringTable, pBlockSize);
if (!entry.has_value()) { if (!entry.has_value()) {
DEBUG_FUNCTION_LINE("Failed to Deserialize child of NodeEntry"); DEBUG_FUNCTION_LINE_ERR("Failed to Deserialize child of NodeEntry");
return {}; return {};
} }
asDirEntry->addChild(entry.value()); asDirEntry->addChild(entry.value());
@ -56,14 +56,14 @@ NodeEntries::make_unique(const std::vector<uint8_t> &data, uint32_t offset, cons
const SectionBlockSize &blockSize) { const SectionBlockSize &blockSize) {
auto rootEntry = NodeEntries::DeserializeImpl(data, offset, std::nullopt, 0, pSectionEntries, pStringTable, blockSize); auto rootEntry = NodeEntries::DeserializeImpl(data, offset, std::nullopt, 0, pSectionEntries, pStringTable, blockSize);
if (!rootEntry.has_value()) { if (!rootEntry.has_value()) {
DEBUG_FUNCTION_LINE("DeserializeImpl for root entry has failed"); DEBUG_FUNCTION_LINE_ERR("DeserializeImpl for root entry has failed");
return {}; return {};
} }
auto rootEntryCasted = std::dynamic_pointer_cast<RootEntry>(rootEntry.value()); auto rootEntryCasted = std::dynamic_pointer_cast<RootEntry>(rootEntry.value());
if (rootEntryCasted != nullptr) { if (rootEntryCasted != nullptr) {
return std::unique_ptr<NodeEntries>(new NodeEntries(rootEntryCasted)); return std::unique_ptr<NodeEntries>(new NodeEntries(rootEntryCasted));
} }
DEBUG_FUNCTION_LINE("Failed to parse Root"); DEBUG_FUNCTION_LINE_ERR("Failed to parse Root");
return {}; return {};
} }

View File

@ -49,19 +49,19 @@ NodeEntry::AutoDeserialize(const std::vector<uint8_t> &data,
if ((param.type & ENTRY_TYPE_Directory) == ENTRY_TYPE_Directory && param.uint24 == 0) { // Root if ((param.type & ENTRY_TYPE_Directory) == ENTRY_TYPE_Directory && param.uint24 == 0) { // Root
auto res = RootEntry::parseData(curEntryData, param, sectionEntries, stringTable); auto res = RootEntry::parseData(curEntryData, param, sectionEntries, stringTable);
if (!res.has_value()) { if (!res.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse node"); DEBUG_FUNCTION_LINE_ERR("Failed to parse node");
return {}; return {};
} }
return res; return res;
} else if ((param.type & ENTRY_TYPE_Directory) == ENTRY_TYPE_Directory) { } else if ((param.type & ENTRY_TYPE_Directory) == ENTRY_TYPE_Directory) {
auto res = DirectoryEntry::parseData(curEntryData, param, sectionEntries, stringTable); auto res = DirectoryEntry::parseData(curEntryData, param, sectionEntries, stringTable);
if (!res.has_value()) { if (!res.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse node"); DEBUG_FUNCTION_LINE_ERR("Failed to parse node");
return {}; return {};
} }
auto resAsNodeEntry = std::dynamic_pointer_cast<NodeEntry>(res.value()); auto resAsNodeEntry = std::dynamic_pointer_cast<NodeEntry>(res.value());
if (resAsNodeEntry == nullptr) { if (resAsNodeEntry == nullptr) {
DEBUG_FUNCTION_LINE("Failed to cast to NodeEntry"); DEBUG_FUNCTION_LINE_ERR("Failed to cast to NodeEntry");
return {}; return {};
} }
return resAsNodeEntry; return resAsNodeEntry;
@ -69,18 +69,18 @@ NodeEntry::AutoDeserialize(const std::vector<uint8_t> &data,
auto res = FileEntry::parseData(curEntryData, param, sectionEntries, stringTable, blockSize); auto res = FileEntry::parseData(curEntryData, param, sectionEntries, stringTable, blockSize);
if (!res.has_value()) { if (!res.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse node"); DEBUG_FUNCTION_LINE_ERR("Failed to parse node");
return {}; return {};
} }
auto resAsNodeEntry = std::dynamic_pointer_cast<NodeEntry>(res.value()); auto resAsNodeEntry = std::dynamic_pointer_cast<NodeEntry>(res.value());
if (resAsNodeEntry == nullptr) { if (resAsNodeEntry == nullptr) {
DEBUG_FUNCTION_LINE("Failed to cast to NodeEntry"); DEBUG_FUNCTION_LINE_ERR("Failed to cast to NodeEntry");
return {}; return {};
} }
return resAsNodeEntry; return resAsNodeEntry;
} }
DEBUG_FUNCTION_LINE("FST Unknown Node Type"); DEBUG_FUNCTION_LINE_ERR("FST Unknown Node Type");
return {}; return {};
} }

View File

@ -32,11 +32,11 @@ RootEntry::parseData(const std::array<uint8_t, NodeEntry::LENGTH> &data,
auto dir = DirectoryEntry::parseData(data, param, sectionEntries, stringTable); auto dir = DirectoryEntry::parseData(data, param, sectionEntries, stringTable);
if (dir.has_value()) { if (dir.has_value()) {
if ((dir.value()->entryType & ENTRY_TYPE_Directory) != ENTRY_TYPE_Directory || dir.value()->entryNumber != 0) { if ((dir.value()->entryType & ENTRY_TYPE_Directory) != ENTRY_TYPE_Directory || dir.value()->entryNumber != 0) {
DEBUG_FUNCTION_LINE("Input is no root entry."); DEBUG_FUNCTION_LINE_ERR("Input is no root entry.");
return {}; return {};
} }
return std::shared_ptr<NodeEntry>(new RootEntry(dir.value())); return std::shared_ptr<NodeEntry>(new RootEntry(dir.value()));
} }
DEBUG_FUNCTION_LINE("Failed to parse dir"); DEBUG_FUNCTION_LINE_ERR("Failed to parse dir");
return {}; return {};
} }

View File

@ -37,13 +37,12 @@ std::optional<std::shared_ptr<SectionEntries>> SectionEntries::make_shared(const
std::vector<std::shared_ptr<SectionEntry>> list; std::vector<std::shared_ptr<SectionEntry>> list;
for (uint32_t i = 0; i < numberOfSections; i++) { for (uint32_t i = 0; i < numberOfSections; i++) {
if (data.size() < (i + 1) * SectionEntry::LENGTH) { if (data.size() < (i + 1) * SectionEntry::LENGTH) {
DEBUG_FUNCTION_LINE("Failed to parse SectionEntries"); DEBUG_FUNCTION_LINE_ERR("Failed to parse SectionEntries");
return {}; return {};
} }
std::array<uint8_t, SectionEntry::LENGTH> sectionEntryData{}; std::array<uint8_t, SectionEntry::LENGTH> sectionEntryData{};
memcpy(sectionEntryData.data(), data.data() + (i * SectionEntry::LENGTH), SectionEntry::LENGTH); memcpy(sectionEntryData.data(), data.data() + (i * SectionEntry::LENGTH), SectionEntry::LENGTH);
list.push_back(std::make_shared<SectionEntry>(sectionEntryData, i, pBlockSize)); list.push_back(std::make_shared<SectionEntry>(sectionEntryData, i, pBlockSize));
;
} }
return std::shared_ptr<SectionEntries>(new SectionEntries(list)); return std::shared_ptr<SectionEntries>(new SectionEntries(list));
} }

View File

@ -22,7 +22,7 @@
std::optional<std::shared_ptr<StringTable>> StringTable::make_shared(const std::vector<uint8_t> &data, uint32_t offset, uint32_t stringCount) { std::optional<std::shared_ptr<StringTable>> StringTable::make_shared(const std::vector<uint8_t> &data, uint32_t offset, uint32_t stringCount) {
if (offset >= data.size()) { if (offset >= data.size()) {
DEBUG_FUNCTION_LINE("Invalid offset for reading StringTable"); DEBUG_FUNCTION_LINE_ERR("Invalid offset for reading StringTable");
return {}; return {};
} }
auto stringTable = std::shared_ptr<StringTable>(new StringTable()); auto stringTable = std::shared_ptr<StringTable>(new StringTable());
@ -35,7 +35,7 @@ std::optional<std::shared_ptr<StringTable>> StringTable::make_shared(const std::
} }
if (i < stringCount) { if (i < stringCount) {
DEBUG_FUNCTION_LINE("stringtable is broken"); DEBUG_FUNCTION_LINE_ERR("StringTable is broken");
return {}; return {};
} }

View File

@ -19,9 +19,8 @@
#include <utility> #include <utility>
#include <utils/logger.h> #include <utils/logger.h>
TitleMetaData::TitleMetaData(std::vector<std::shared_ptr<Content>> pContentList) : contentList(std::move(pContentList)) { TitleMetaData::TitleMetaData(uint64_t titleId, std::vector<std::shared_ptr<Content>> pContentList) : contentList(std::move(pContentList)) {
this->titleId = titleId;
// Get Contents
} }
std::optional<std::shared_ptr<Content>> TitleMetaData::getContentByIndex(uint16_t i) { std::optional<std::shared_ptr<Content>> TitleMetaData::getContentByIndex(uint16_t i) {
@ -33,16 +32,17 @@ std::optional<std::shared_ptr<Content>> TitleMetaData::getContentByIndex(uint16_
return {}; return {};
} }
std::optional<std::shared_ptr<TitleMetaData>> TitleMetaData::make_shared(const std::vector<uint8_t> &data) { std::optional<std::unique_ptr<TitleMetaData>> TitleMetaData::make_unique(const std::vector<uint8_t> &data) {
if (data.empty() || data.size() <= 0xB04) { if (data.empty() || data.size() <= 0xB04) {
return {}; return {};
} }
std::vector<std::shared_ptr<Content>> contentList; std::vector<std::shared_ptr<Content>> contentList;
auto contentCount = ((uint16_t *) &data[0x1DE])[0]; auto contentCount = ((uint16_t *) &data[0x1DE])[0];
auto titleID = ((uint64_t *) &data[0x18C])[0];
for (uint16_t i = 0; i < contentCount; i++) { for (uint16_t i = 0; i < contentCount; i++) {
auto curOffset = 0xB04 + (i * Content::LENGTH); auto curOffset = 0xB04 + (i * Content::LENGTH);
if (data.size() < curOffset + Content::LENGTH) { if (data.size() < curOffset + Content::LENGTH) {
DEBUG_FUNCTION_LINE("Failed to parse TitleMetaData"); DEBUG_FUNCTION_LINE_ERR("Failed to parse TitleMetaData");
return {}; return {};
} }
std::array<uint8_t, Content::LENGTH> contentData{}; std::array<uint8_t, Content::LENGTH> contentData{};
@ -50,11 +50,11 @@ std::optional<std::shared_ptr<TitleMetaData>> TitleMetaData::make_shared(const s
auto curContentOpt = Content::make_shared(contentData); auto curContentOpt = Content::make_shared(contentData);
if (!curContentOpt.has_value()) { if (!curContentOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse Content"); DEBUG_FUNCTION_LINE_ERR("Failed to parse Content");
return {}; return {};
} }
contentList.push_back(curContentOpt.value()); contentList.push_back(curContentOpt.value());
} }
return std::shared_ptr<TitleMetaData>(new TitleMetaData(contentList)); return std::unique_ptr<TitleMetaData>(new TitleMetaData(titleID, contentList));
} }

View File

@ -28,8 +28,9 @@ public:
std::optional<std::shared_ptr<Content>> getContentByIndex(uint16_t index); std::optional<std::shared_ptr<Content>> getContentByIndex(uint16_t index);
static std::optional<std::shared_ptr<TitleMetaData>> make_shared(const std::vector<uint8_t> &data); static std::optional<std::unique_ptr<TitleMetaData>> make_unique(const std::vector<uint8_t> &data);
uint64_t titleId;
private: private:
explicit TitleMetaData(std::vector<std::shared_ptr<Content>> pContentList); explicit TitleMetaData(uint64_t titleId, std::vector<std::shared_ptr<Content>> pContentList);
}; };

View File

@ -19,42 +19,42 @@
uint32_t WiiUDiscHeader::LENGTH = 131072L; uint32_t WiiUDiscHeader::LENGTH = 131072L;
WiiUDiscHeader::WiiUDiscHeader(std::unique_ptr<WiiUManufactorDiscId> pManufactorDiscId, WiiUDiscHeader::WiiUDiscHeader(std::unique_ptr<WiiUManufacturerDiscId> pManufacturerDiscId,
std::unique_ptr<WiiUDiscId> pDiscId, std::unique_ptr<WiiUDiscId> pDiscId,
std::unique_ptr<WiiUContentsInformation> pWiiUContentsInformation) : manufactorDiscId(std::move(pManufactorDiscId)), std::unique_ptr<WiiUContentsInformation> pWiiUContentsInformation) : manufacturerDiscId(std::move(pManufacturerDiscId)),
discId(std::move(pDiscId)), discId(std::move(pDiscId)),
wiiUContentsInformation(std::move(pWiiUContentsInformation)) { wiiUContentsInformation(std::move(pWiiUContentsInformation)) {
} }
std::optional<std::unique_ptr<WiiUDiscHeader>> WiiUDiscHeader::make_unique(const std::shared_ptr<DiscReader> &discReader) { std::optional<std::unique_ptr<WiiUDiscHeader>> WiiUDiscHeader::make_unique(std::shared_ptr<DiscReader> &discReader) {
if (!discReader->IsReady()) { if (!discReader->IsReady()) {
DEBUG_FUNCTION_LINE("DiscReader is not ready"); DEBUG_FUNCTION_LINE_ERR("DiscReader is not ready");
return {}; return {};
} }
uint32_t offset = 0; uint32_t offset = 0;
uint32_t curOffset = offset; uint32_t curOffset = offset;
auto manufactorDiscIDOpt = WiiUManufactorDiscId::make_unique(discReader); auto manufactorDiscIDOpt = WiiUManufacturerDiscId::make_unique(discReader);
if (!manufactorDiscIDOpt.has_value()) { if (!manufactorDiscIDOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to read ManufactorDiscId"); DEBUG_FUNCTION_LINE_ERR("Failed to read ManufactorDiscId");
return {}; return {};
} }
curOffset += WiiUManufactorDiscId::LENGTH; curOffset += WiiUManufacturerDiscId::LENGTH;
auto discIdOpt = WiiUDiscId::make_unique(discReader, curOffset); auto discIdOpt = WiiUDiscId::make_unique(discReader, curOffset);
if (!discIdOpt.has_value()) { if (!discIdOpt) {
DEBUG_FUNCTION_LINE("Failed to read DiscId"); DEBUG_FUNCTION_LINE_ERR("Failed to read DiscId");
return {}; return {};
} }
curOffset += WiiUDiscId::LENGTH; curOffset += WiiUDiscId::LENGTH;
auto wiiUContentsInformationOpt = WiiUContentsInformation::make_unique(discReader, curOffset); auto wiiUContentsInformationOpt = WiiUContentsInformation::make_unique(discReader, curOffset);
if (!wiiUContentsInformationOpt.has_value()) { if (!wiiUContentsInformationOpt) {
DEBUG_FUNCTION_LINE("Failed to read WiiUContentsInformation"); DEBUG_FUNCTION_LINE_ERR("Failed to read WiiUContentsInformation");
return {}; return {};
} }
curOffset += WiiUContentsInformation::LENGTH; curOffset += WiiUContentsInformation::LENGTH;
if (curOffset - offset != LENGTH) { if (curOffset - offset != LENGTH) {
DEBUG_FUNCTION_LINE("Unexpected offset"); DEBUG_FUNCTION_LINE_ERR("Unexpected offset");
return {}; return {};
} }
return std::unique_ptr<WiiUDiscHeader>(new WiiUDiscHeader( return std::unique_ptr<WiiUDiscHeader>(new WiiUDiscHeader(

View File

@ -17,7 +17,7 @@
#pragma once #pragma once
#include "WiiUDiscId.h" #include "WiiUDiscId.h"
#include "WiiUManufactorDiscId.h" #include "WiiUManufacturerDiscId.h"
#include <WUD/DiscReader.h> #include <WUD/DiscReader.h>
#include <WUD/DiscReaderDiscDrive.h> #include <WUD/DiscReaderDiscDrive.h>
#include <WUD/content/WiiUContentsInformation.h> #include <WUD/content/WiiUContentsInformation.h>
@ -26,9 +26,9 @@
class WiiUDiscHeader { class WiiUDiscHeader {
public: public:
static std::optional<std::unique_ptr<WiiUDiscHeader>> make_unique(const std::shared_ptr<DiscReader> &discReader); static std::optional<std::unique_ptr<WiiUDiscHeader>> make_unique(std::shared_ptr<DiscReader> &discReader);
std::unique_ptr<WiiUManufactorDiscId> manufactorDiscId; std::unique_ptr<WiiUManufacturerDiscId> manufacturerDiscId;
std::unique_ptr<WiiUDiscId> discId; std::unique_ptr<WiiUDiscId> discId;
std::unique_ptr<WiiUContentsInformation> wiiUContentsInformation; std::unique_ptr<WiiUContentsInformation> wiiUContentsInformation;
@ -36,7 +36,7 @@ public:
private: private:
explicit WiiUDiscHeader( explicit WiiUDiscHeader(
std::unique_ptr<WiiUManufactorDiscId> pManufactorDiscId, std::unique_ptr<WiiUManufacturerDiscId> pManufacturerDiscId,
std::unique_ptr<WiiUDiscId> pDiscId, std::unique_ptr<WiiUDiscId> pDiscId,
std::unique_ptr<WiiUContentsInformation> pWiiUContentsInformation); std::unique_ptr<WiiUContentsInformation> pWiiUContentsInformation);
}; };

View File

@ -15,24 +15,26 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/ ****************************************************************************/
#include "WiiUDiscId.h" #include "WiiUDiscId.h"
#include "utils/utils.h"
#include <coreinit/debug.h> #include <coreinit/debug.h>
#include <memory> #include <memory>
#include <utility>
#include <utils/logger.h> #include <utils/logger.h>
std::optional<std::unique_ptr<WiiUDiscId>> WiiUDiscId::make_unique(const std::shared_ptr<DiscReader> &discReader, uint32_t offset) { std::optional<std::unique_ptr<WiiUDiscId>> WiiUDiscId::make_unique(std::shared_ptr<DiscReader> &discReader, uint32_t offset) {
auto data = (uint8_t *) malloc(WiiUDiscId::LENGTH); auto data = make_unique_nothrow<uint8_t[]>(WiiUDiscId::LENGTH);
if (data == nullptr) { if (data == nullptr) {
DEBUG_FUNCTION_LINE("Failed to alloc memory"); DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory");
return {}; return {};
} }
if (!discReader->readEncrypted(data, offset, WiiUDiscId::LENGTH)) { if (!discReader->readEncrypted(data.get(), offset, WiiUDiscId::LENGTH)) {
DEBUG_FUNCTION_LINE("Failed to read data"); DEBUG_FUNCTION_LINE_ERR("Failed to read data");
return {}; return {};
} }
if (((uint32_t *) data)[0] != WiiUDiscId::MAGIC) { if (((uint32_t *) data.get())[0] != WiiUDiscId::MAGIC) {
DEBUG_FUNCTION_LINE("MAGIC mismatch"); DEBUG_FUNCTION_LINE_ERR("MAGIC mismatch");
return {}; return {};
} }
@ -41,12 +43,10 @@ std::optional<std::unique_ptr<WiiUDiscId>> WiiUDiscId::make_unique(const std::sh
auto footprint = std::string((char *) &data[32]); auto footprint = std::string((char *) &data[32]);
free(data);
return std::unique_ptr<WiiUDiscId>(new WiiUDiscId(minorVersion, majorVersion, footprint)); return std::unique_ptr<WiiUDiscId>(new WiiUDiscId(minorVersion, majorVersion, footprint));
} }
WiiUDiscId::WiiUDiscId(uint8_t pMinorVersion, uint8_t pMajorVersion, const std::string &pFootprint) : minorVersion(pMinorVersion), WiiUDiscId::WiiUDiscId(uint8_t pMinorVersion, uint8_t pMajorVersion, std::string pFootprint) : minorVersion(pMinorVersion),
majorVersion(pMajorVersion), majorVersion(pMajorVersion),
footprint(pFootprint) { footprint(std::move(pFootprint)) {
} }

View File

@ -31,8 +31,8 @@ public:
uint8_t majorVersion; uint8_t majorVersion;
std::string footprint; std::string footprint;
static std::optional<std::unique_ptr<WiiUDiscId>> make_unique(const std::shared_ptr<DiscReader> &discReader, uint32_t offset); static std::optional<std::unique_ptr<WiiUDiscId>> make_unique(std::shared_ptr<DiscReader> &discReader, uint32_t offset);
private: private:
WiiUDiscId(uint8_t pMinorVersion, uint8_t pMajorVersion, const std::string &pFootprint); WiiUDiscId(uint8_t pMinorVersion, uint8_t pMajorVersion, std::string pFootprint);
}; };

View File

@ -14,24 +14,24 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/ ****************************************************************************/
#include "WiiUManufactorDiscId.h" #include "WiiUManufacturerDiscId.h"
#include <coreinit/debug.h> #include <coreinit/debug.h>
#include <utils/logger.h> #include <utils/logger.h>
std::optional<std::unique_ptr<WiiUManufactorDiscId>> WiiUManufactorDiscId::make_unique(const std::shared_ptr<DiscReader> &discReader) { std::optional<std::unique_ptr<WiiUManufacturerDiscId>> WiiUManufacturerDiscId::make_unique(std::shared_ptr<DiscReader> &discReader) {
if (!discReader->IsReady()) { if (!discReader->IsReady()) {
DEBUG_FUNCTION_LINE("DiscReader is not ready"); DEBUG_FUNCTION_LINE_ERR("DiscReader is not ready");
return {}; return {};
} }
std::array<uint8_t, WiiUManufactorDiscId::LENGTH> data{}; std::array<uint8_t, WiiUManufacturerDiscId::LENGTH> data{};
if (!discReader->readEncrypted(data.data(), 0, WiiUManufactorDiscId::LENGTH)) { if (!discReader->readEncrypted(data.data(), 0, WiiUManufacturerDiscId::LENGTH)) {
DEBUG_FUNCTION_LINE("Failed to read data"); DEBUG_FUNCTION_LINE_ERR("Failed to read data");
return {}; return {};
} }
return std::unique_ptr<WiiUManufactorDiscId>(new WiiUManufactorDiscId(data)); return std::unique_ptr<WiiUManufacturerDiscId>(new WiiUManufacturerDiscId(data));
} }
WiiUManufactorDiscId::WiiUManufactorDiscId(const std::array<uint8_t, WiiUManufactorDiscId::LENGTH> &pData) : data(pData) { WiiUManufacturerDiscId::WiiUManufacturerDiscId(const std::array<uint8_t, WiiUManufacturerDiscId::LENGTH> &pData) : data(pData) {
this->data = pData; this->data = pData;
} }

View File

@ -22,15 +22,15 @@
#include <memory> #include <memory>
#include <optional> #include <optional>
class WiiUManufactorDiscId { class WiiUManufacturerDiscId {
public: public:
static std::optional<std::unique_ptr<WiiUManufactorDiscId>> make_unique(const std::shared_ptr<DiscReader> &discReader); static std::optional<std::unique_ptr<WiiUManufacturerDiscId>> make_unique(std::shared_ptr<DiscReader> &discReader);
static constexpr uint32_t LENGTH = 65536; static constexpr uint32_t LENGTH = 65536;
std::array<uint8_t, WiiUManufactorDiscId::LENGTH> data; std::array<uint8_t, WiiUManufacturerDiscId::LENGTH> data;
private: private:
explicit WiiUManufactorDiscId(const std::array<uint8_t, WiiUManufactorDiscId::LENGTH> &pData); explicit WiiUManufacturerDiscId(const std::array<uint8_t, WiiUManufacturerDiscId::LENGTH> &pData);
}; };

View File

@ -18,8 +18,9 @@
#include <WUD/content/WiiUDiscContentsHeader.h> #include <WUD/content/WiiUDiscContentsHeader.h>
#include <common/common.h> #include <common/common.h>
#include <fs/FSUtils.h> #include <fs/FSUtils.h>
#include <iosuhax.h>
#include <malloc.h> #include <malloc.h>
#include <mocha/fsa.h>
#include <mocha/mocha.h>
#include <utils/StringTools.h> #include <utils/StringTools.h>
#include <utils/WiiUScreen.h> #include <utils/WiiUScreen.h>
#include <utils/utils.h> #include <utils/utils.h>
@ -28,14 +29,16 @@ WUDDumperState::WUDDumperState(WUDDumperState::eDumpTargetFormat pTargetFormat,
: targetFormat(pTargetFormat), targetDevice(pTargetDevice) { : targetFormat(pTargetFormat), targetDevice(pTargetDevice) {
this->sectorBufSize = READ_SECTOR_SIZE * READ_NUM_SECTORS; this->sectorBufSize = READ_SECTOR_SIZE * READ_NUM_SECTORS;
this->state = STATE_OPEN_ODD1; this->state = STATE_OPEN_ODD1;
gBlockHomeButton = true;
} }
WUDDumperState::~WUDDumperState() { WUDDumperState::~WUDDumperState() {
if (this->oddFd >= 0) { if (this->oddFd >= 0) {
IOSUHAX_FSA_RawClose(gFSAfd, oddFd); FSAEx_RawClose(__wut_devoptab_fs_client, oddFd);
} }
free(sectorBuf); free(sectorBuf);
free(emptySector); free(emptySector);
gBlockHomeButton = false;
} }
ApplicationState::eSubState WUDDumperState::update(Input *input) { ApplicationState::eSubState WUDDumperState::update(Input *input) {
@ -47,7 +50,7 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
} }
if (this->state == STATE_OPEN_ODD1) { if (this->state == STATE_OPEN_ODD1) {
if (this->currentSector > 0) { if (this->currentSector > 0) {
auto ret = IOSUHAX_FSA_RawOpen(gFSAfd, "/dev/odd01", &(this->oddFd)); auto ret = FSAEx_RawOpen(__wut_devoptab_fs_client, "/dev/odd01", &(this->oddFd));
if (ret >= 0) { if (ret >= 0) {
// continue! // continue!
this->state = STATE_DUMP_DISC; this->state = STATE_DUMP_DISC;
@ -61,7 +64,7 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
this->state = STATE_PLEASE_INSERT_DISC; this->state = STATE_PLEASE_INSERT_DISC;
return ApplicationState::SUBSTATE_RUNNING; return ApplicationState::SUBSTATE_RUNNING;
} }
auto ret = IOSUHAX_FSA_RawOpen(gFSAfd, "/dev/odd01", &(this->oddFd)); auto ret = FSAEx_RawOpen(__wut_devoptab_fs_client, "/dev/odd01", &(this->oddFd));
if (ret >= 0) { if (ret >= 0) {
if (this->sectorBuf == nullptr) { if (this->sectorBuf == nullptr) {
this->sectorBuf = (void *) memalign(0x100, this->sectorBufSize); this->sectorBuf = (void *) memalign(0x100, this->sectorBufSize);
@ -79,7 +82,7 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
return SUBSTATE_RETURN; return SUBSTATE_RETURN;
} }
} else if (this->state == STATE_READ_DISC_INFO) { } else if (this->state == STATE_READ_DISC_INFO) {
if (IOSUHAX_FSA_RawRead(gFSAfd, this->sectorBuf, READ_SECTOR_SIZE, 1, 0, this->oddFd) >= 0) { if (FSAEx_RawRead(__wut_devoptab_fs_client, this->sectorBuf, READ_SECTOR_SIZE, 1, 0, this->oddFd) >= 0) {
this->discId[10] = '\0'; this->discId[10] = '\0';
memcpy(this->discId.data(), sectorBuf, 10); memcpy(this->discId.data(), sectorBuf, 10);
if (this->discId[0] == 0) { if (this->discId[0] == 0) {
@ -96,39 +99,39 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
this->state = STATE_DUMP_DISC_KEY; this->state = STATE_DUMP_DISC_KEY;
} else if (this->state == STATE_DUMP_DISC_KEY) { } else if (this->state == STATE_DUMP_DISC_KEY) {
// Read the WiiUDiscContentsHeader to determine if we need disckey and if it's the correct one. // Read the WiiUDiscContentsHeader to determine if we need disckey and if it's the correct one.
auto res = IOSUHAX_FSA_RawRead(gFSAfd, this->sectorBuf, READ_SECTOR_SIZE, 1, 3, this->oddFd); auto res = FSAEx_RawRead(__wut_devoptab_fs_client, this->sectorBuf, READ_SECTOR_SIZE, 1, 3, this->oddFd);
uint8_t discKey[16]; WUDDiscKey discKey;
bool hasDiscKey = false; bool hasDiscKey = false;
if (res >= 0) { if (res >= 0) {
if (((uint32_t *) this->sectorBuf)[0] != WiiUDiscContentsHeader::MAGIC) { if (((uint32_t *) this->sectorBuf)[0] != WiiUDiscContentsHeader::MAGIC) {
auto discKeyRes = IOSUHAX_ODM_GetDiscKey(discKey); auto discKeyRes = Mocha_ODMGetDiscKey(&discKey);
if (discKeyRes >= 0) { if (discKeyRes == MOCHA_RESULT_SUCCESS) {
hasDiscKey = true; hasDiscKey = true;
} }
} }
} }
if (hasDiscKey) { if (hasDiscKey) {
if (!FSUtils::CreateSubfolder(StringTools::fmt("%swudump/%s", getPathForDevice(targetDevice).c_str(), discId))) { if (!FSUtils::CreateSubfolder(string_format("%swudump/%s", getPathForDevice(targetDevice).c_str(), discId).c_str())) {
setError(ERROR_WRITE_FAILED); setError(ERROR_WRITE_FAILED);
return SUBSTATE_RUNNING; return SUBSTATE_RUNNING;
} }
if (!FSUtils::saveBufferToFile(StringTools::fmt("%swudump/%s/game.key", getPathForDevice(targetDevice).c_str(), discId), discKey, 16)) { if (!FSUtils::saveBufferToFile(string_format("%swudump/%s/game.key", getPathForDevice(targetDevice).c_str(), discId).c_str(), discKey.key, 16)) {
setError(ERROR_WRITE_FAILED); setError(ERROR_WRITE_FAILED);
return SUBSTATE_RUNNING; return SUBSTATE_RUNNING;
} }
} }
this->state = STATE_DUMP_DISC_START; this->state = STATE_DUMP_DISC_START;
} else if (this->state == STATE_DUMP_DISC_START) { } else if (this->state == STATE_DUMP_DISC_START) {
if (!FSUtils::CreateSubfolder(StringTools::fmt("%swudump/%s", getPathForDevice(targetDevice).c_str(), discId))) { if (!FSUtils::CreateSubfolder(string_format("%swudump/%s", getPathForDevice(targetDevice).c_str(), discId).c_str())) {
setError(ERROR_WRITE_FAILED); setError(ERROR_WRITE_FAILED);
return ApplicationState::SUBSTATE_RUNNING; return ApplicationState::SUBSTATE_RUNNING;
} }
if (targetFormat == DUMP_AS_WUX) { if (targetFormat == DUMP_AS_WUX) {
this->fileHandle = std::make_unique<WUXFileWriter>(StringTools::fmt("%swudump/%s/game.wux", getPathForDevice(targetDevice).c_str(), discId), READ_SECTOR_SIZE * WRITE_BUFFER_NUM_SECTORS, this->fileHandle = std::make_unique<WUXFileWriter>(string_format("%swudump/%s/game.wux", getPathForDevice(targetDevice).c_str(), discId).c_str(), READ_SECTOR_SIZE * WRITE_BUFFER_NUM_SECTORS,
SECTOR_SIZE, targetDevice == TARGET_SD); SECTOR_SIZE, targetDevice == TARGET_SD);
} else { } else {
this->fileHandle = std::make_unique<WUDFileWriter>(StringTools::fmt("%swudump/%s/game.wud", getPathForDevice(targetDevice).c_str(), discId), READ_SECTOR_SIZE * WRITE_BUFFER_NUM_SECTORS, this->fileHandle = std::make_unique<WUDFileWriter>(string_format("%swudump/%s/game.wud", getPathForDevice(targetDevice).c_str(), discId).c_str(), READ_SECTOR_SIZE * WRITE_BUFFER_NUM_SECTORS,
SECTOR_SIZE, targetDevice == TARGET_SD); SECTOR_SIZE, targetDevice == TARGET_SD);
} }
if (!this->fileHandle->isOpen()) { if (!this->fileHandle->isOpen()) {
@ -145,8 +148,13 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
this->writtenSectors = 0; this->writtenSectors = 0;
this->retryCount = 10; this->retryCount = 10;
} else if (this->state == STATE_DUMP_DISC) { } else if (this->state == STATE_DUMP_DISC) {
if (buttonPressed(input, Input::BUTTON_B)) {
this->state = STATE_ABORT_CONFIRMATION;
return ApplicationState::SUBSTATE_RUNNING;
}
size_t numSectors = this->currentSector + READ_NUM_SECTORS > this->totalSectorCount ? this->totalSectorCount - this->currentSector : READ_NUM_SECTORS; size_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 ((this->readResult = FSAEx_RawRead(__wut_devoptab_fs_client, sectorBuf, READ_SECTOR_SIZE, numSectors, this->currentSector, this->oddFd)) >= 0) {
auto curWrittenSectors = fileHandle->writeSector((const uint8_t *) this->sectorBuf, numSectors); auto curWrittenSectors = fileHandle->writeSector((const uint8_t *) this->sectorBuf, numSectors);
if (curWrittenSectors < 0) { if (curWrittenSectors < 0) {
this->setError(ERROR_WRITE_FAILED); this->setError(ERROR_WRITE_FAILED);
@ -171,15 +179,30 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
} else { } else {
this->state = STATE_WAIT_USER_ERROR_CONFIRM; this->state = STATE_WAIT_USER_ERROR_CONFIRM;
if (this->oddFd >= 0) { if (this->oddFd >= 0) {
IOSUHAX_FSA_RawClose(gFSAfd, this->oddFd); FSAEx_RawClose(__wut_devoptab_fs_client, this->oddFd);
this->oddFd = -1; this->oddFd = -1;
} }
return ApplicationState::SUBSTATE_RUNNING; return ApplicationState::SUBSTATE_RUNNING;
} }
} else if (this->state == STATE_ABORT_CONFIRMATION) {
if (buttonPressed(input, Input::BUTTON_B)) {
this->state = STATE_DUMP_DISC;
return ApplicationState::SUBSTATE_RUNNING;
}
proccessMenuNavigationX(input, 2);
if (buttonPressed(input, Input::BUTTON_A)) {
if (selectedOptionX == 0) {
this->state = STATE_DUMP_DISC;
return ApplicationState::SUBSTATE_RUNNING;
} else {
return ApplicationState::SUBSTATE_RETURN;
}
}
} else if (this->state == STATE_WAIT_USER_ERROR_CONFIRM) { } else if (this->state == STATE_WAIT_USER_ERROR_CONFIRM) {
if (this->autoSkipOnError) { if (this->autoSkipOnError) {
if (this->oddFd >= 0) { if (this->oddFd >= 0) {
IOSUHAX_FSA_RawClose(gFSAfd, this->oddFd); FSAEx_RawClose(__wut_devoptab_fs_client, this->oddFd);
this->oddFd = -1; this->oddFd = -1;
} }
} }
@ -206,10 +229,10 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
this->currentSector += 1; this->currentSector += 1;
this->writtenSectors += curWrittenSectors; this->writtenSectors += curWrittenSectors;
this->readResult = 0; this->readResult = 0;
} else if (input->data.buttons_d & Input::BUTTON_B) { } else if (buttonPressed(input, Input::BUTTON_B)) {
this->state = STATE_OPEN_ODD1; this->state = STATE_OPEN_ODD1;
this->readResult = 0; this->readResult = 0;
} else if (input->data.buttons_d & Input::BUTTON_Y) { } else if (buttonPressed(input, Input::BUTTON_Y)) {
this->autoSkipOnError = true; this->autoSkipOnError = true;
} }
} else if (this->state == STATE_DUMP_DISC_DONE) { } else if (this->state == STATE_DUMP_DISC_DONE) {
@ -278,9 +301,19 @@ void WUDDumperState::render() {
WiiUScreen::drawLine(); WiiUScreen::drawLine();
if (!this->skippedSectors.empty()) { if (!this->skippedSectors.empty()) {
WiiUScreen::drawLinef("Skipped dumping %d sectors", this->skippedSectors.size()); WiiUScreen::drawLinef("Skipped dumping %d sectors", this->skippedSectors.size());
WiiUScreen::drawLine();
} }
WiiUScreen::drawLinef("Press B to abort");
} else if (this->state == STATE_DUMP_DISC_DONE) { } else if (this->state == STATE_DUMP_DISC_DONE) {
WiiUScreen::drawLinef("Dumping done! Press A to continue"); WiiUScreen::drawLinef("Dumping done! Press A to continue");
} else if (this->state == STATE_ABORT_CONFIRMATION) {
WiiUScreen::drawLinef("Do you really want to abort the disc dumping?");
WiiUScreen::drawLinef("");
if (selectedOptionX == 0) {
WiiUScreen::drawLinef("> Continue dumping Abort dumping");
} else {
WiiUScreen::drawLinef(" Continue dumping > Abort dumping");
}
} }
ApplicationState::printFooter(); ApplicationState::printFooter();

View File

@ -49,6 +49,7 @@ public:
STATE_DUMP_DISC_DONE, STATE_DUMP_DISC_DONE,
STATE_WAIT_USER_ERROR_CONFIRM, STATE_WAIT_USER_ERROR_CONFIRM,
STATE_DUMP_DISC, STATE_DUMP_DISC,
STATE_ABORT_CONFIRMATION,
}; };
enum eErrorState { enum eErrorState {

View File

@ -1,7 +1,6 @@
#include "common.h" #include "common.h"
ntfs_md *ntfs_mounts = nullptr;
int32_t gFSAfd = -1; int ntfs_mount_count = 0;
BOOL gRunFromHBL = false;
ntfs_md *ntfs_mounts = nullptr; BOOL gBlockHomeButton = false;
int ntfs_mount_count = 0; uint32_t gBlockHomeButtonCooldown = 0;
BOOL gRunFromHBL = false;

View File

@ -3,15 +3,17 @@
#include <ntfs.h> #include <ntfs.h>
#include <wut.h> #include <wut.h>
extern int32_t gFSAfd;
#define SECTOR_SIZE 0x8000 #define SECTOR_SIZE 0x8000
#define READ_SECTOR_SIZE SECTOR_SIZE #define READ_SECTOR_SIZE SECTOR_SIZE
extern ntfs_md *ntfs_mounts; extern ntfs_md *ntfs_mounts;
extern int ntfs_mount_count; extern int ntfs_mount_count;
extern "C" FSClient *__wut_devoptab_fs_client;
extern BOOL gRunFromHBL; extern BOOL gRunFromHBL;
extern BOOL gBlockHomeButton;
extern uint32_t gBlockHomeButtonCooldown;
enum eDumpTarget { enum eDumpTarget {
TARGET_SD, TARGET_SD,

View File

@ -1,6 +1,7 @@
#include "FSUtils.h" #include "FSUtils.h"
#include "CFile.hpp" #include "CFile.hpp"
#include "utils/logger.h" #include "utils/logger.h"
#include "utils/utils.h"
#include <fcntl.h> #include <fcntl.h>
#include <malloc.h> #include <malloc.h>
#include <stdio.h> #include <stdio.h>
@ -20,7 +21,7 @@ int32_t FSUtils::LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_
uint32_t filesize = lseek(iFd, 0, SEEK_END); uint32_t filesize = lseek(iFd, 0, SEEK_END);
lseek(iFd, 0, SEEK_SET); lseek(iFd, 0, SEEK_SET);
auto *buffer = (uint8_t *) malloc(filesize); auto *buffer = (uint8_t *) memalign(0x40, ROUNDUP(filesize, 0x40));
if (buffer == nullptr) { if (buffer == nullptr) {
close(iFd); close(iFd);
return -2; return -2;
@ -146,7 +147,7 @@ bool FSUtils::copyFile(const std::string &in, const std::string &out) {
} }
auto bufferSize = 1024 * 1024; auto bufferSize = 1024 * 1024;
char *buf = (char *) malloc(bufferSize); char *buf = (char *) memalign(0x40, ROUNDUP(bufferSize, 0x40));
if (buf == NULL) { if (buf == NULL) {
return false; return false;
} }

View File

@ -16,6 +16,7 @@
****************************************************************************/ ****************************************************************************/
#include "WUXFileWriter.h" #include "WUXFileWriter.h"
#include "WUDDumperState.h" #include "WUDDumperState.h"
#include "utils/StringTools.h"
#include <utils/logger.h> #include <utils/logger.h>
WUXFileWriter::WUXFileWriter(const char *path, int32_t cacheSize, int32_t sectorSize, bool split) : WUDFileWriter(path, cacheSize, sectorSize, split) { WUXFileWriter::WUXFileWriter(const char *path, int32_t cacheSize, int32_t sectorSize, bool split) : WUDFileWriter(path, cacheSize, sectorSize, split) {
@ -30,7 +31,7 @@ WUXFileWriter::WUXFileWriter(const char *path, int32_t cacheSize, int32_t sector
this->sectorTableStart = this->tell(); this->sectorTableStart = this->tell();
this->totalSectorCount = WUD_FILE_SIZE / this->sectorSize; this->totalSectorCount = WUD_FILE_SIZE / this->sectorSize;
this->sectorIndexTable = (void *) malloc(totalSectorCount * 4); this->sectorIndexTable = (void *) memalign(0x40, ROUNDUP(totalSectorCount * 4, 0x40));
if (sectorIndexTable == nullptr) { if (sectorIndexTable == nullptr) {
DEBUG_FUNCTION_LINE("Failed to alloc"); DEBUG_FUNCTION_LINE("Failed to alloc");
WUDFileWriter::close(); WUDFileWriter::close();
@ -50,7 +51,7 @@ WUXFileWriter::WUXFileWriter(const char *path, int32_t cacheSize, int32_t sector
this->sectorTableEnd -= (this->sectorTableEnd % this->sectorSize); this->sectorTableEnd -= (this->sectorTableEnd % this->sectorSize);
uint64_t padding = this->sectorTableEnd - tableEnd; uint64_t padding = this->sectorTableEnd - tableEnd;
auto *paddingData = (uint8_t *) malloc(padding); auto *paddingData = (uint8_t *) memalign(0x40, ROUNDUP(padding, 0x40));
memset(paddingData, 0, padding); memset(paddingData, 0, padding);
this->write(reinterpret_cast<const uint8_t *>(paddingData), padding); this->write(reinterpret_cast<const uint8_t *>(paddingData), padding);
free(paddingData); free(paddingData);
@ -58,25 +59,22 @@ WUXFileWriter::WUXFileWriter(const char *path, int32_t cacheSize, int32_t sector
flush(); flush();
} }
int32_t WUXFileWriter::writeSector(const uint8_t *buffer, uint32_t numberOfSectors) { int32_t WUXFileWriter::writeSector(const uint8_t *buffer, uint32_t numberOfSectors) {
char hashOut[32];
int32_t curWrittenSectors = 0; int32_t curWrittenSectors = 0;
for (uint32_t i = 0; i < numberOfSectors; i++) { for (uint32_t i = 0; i < numberOfSectors; i++) {
uint32_t addr = ((uint32_t) buffer) + (i * this->sectorSize); uint32_t addr = ((uint32_t) buffer) + (i * this->sectorSize);
calculateHash256(reinterpret_cast<unsigned char *>(addr), this->sectorSize, reinterpret_cast<unsigned char *>(hashOut)); std::array<uint8_t, 32> hashOut{};
char tmp[34]; calculateHash256(reinterpret_cast<unsigned char *>(addr), this->sectorSize, reinterpret_cast<unsigned char *>(hashOut.data()));
auto *test = (uint32_t *) hashOut;
snprintf(tmp, 33, "%08X%08X%08X%08X", test[0], test[1], test[2], test[3]);
std::string hash(tmp);
auto *indexTable = (uint32_t *) this->sectorIndexTable; auto *indexTable = (uint32_t *) this->sectorIndexTable;
auto it = hashMap.find(hash); auto it = hashMap.find(hashOut);
if (it != hashMap.end()) { if (it != hashMap.end()) {
indexTable[this->currentSector] = swap_uint32(this->hashMap[hash]); indexTable[this->currentSector] = swap_uint32(this->hashMap[hashOut]);
} else { } else {
indexTable[this->currentSector] = swap_uint32(this->writtenSector); indexTable[this->currentSector] = swap_uint32(this->writtenSector);
hashMap[hash] = writtenSector; hashMap[hashOut] = writtenSector;
if (isOpen()) { if (isOpen()) {
if (!write((uint8_t *) addr, this->sectorSize)) { if (!write((uint8_t *) addr, this->sectorSize)) {
DEBUG_FUNCTION_LINE("Write failed"); DEBUG_FUNCTION_LINE("Write failed");

View File

@ -50,7 +50,7 @@ private:
uint64_t sectorTableEnd; uint64_t sectorTableEnd;
void *sectorIndexTable = nullptr; void *sectorIndexTable = nullptr;
std::map<std::string, uint32_t> hashMap; std::map<std::array<uint8_t, 32>, uint32_t> hashMap;
uint32_t currentSector = 0; uint32_t currentSector = 0;
uint32_t writtenSector = 0; uint32_t writtenSector = 0;
}; };

View File

@ -23,8 +23,8 @@
#define SPLIT_SIZE (0x80000000) #define SPLIT_SIZE (0x80000000)
WriteOnlyFileWithCache::WriteOnlyFileWithCache(const char *path, int32_t cacheSize, bool split) : CFile(split ? std::string(path) + ".part1" : path, WriteOnly), WriteOnlyFileWithCache::WriteOnlyFileWithCache(const char *path, int32_t cacheSize, bool split) : CFile(split ? std::string(path) + ".part1" : path, WriteOnly),
originalPath(path), splitFile(split),
splitFile(split) { originalPath(path) {
if (!this->isOpen()) { if (!this->isOpen()) {
return; return;
} }
@ -81,8 +81,8 @@ int32_t WriteOnlyFileWithCache::write(const uint8_t *addr, size_t writeSize) {
CFile::close(); CFile::close();
// open the next part // open the next part
DEBUG_FUNCTION_LINE("Open %s", StringTools::strfmt("%s.part%d", originalPath.c_str(), part).c_str()); DEBUG_FUNCTION_LINE("Open %s", string_format("%s.part%d", originalPath.c_str(), part).c_str());
this->open(StringTools::strfmt("%s.part%d", originalPath.c_str(), part), WriteOnly); this->open(string_format("%s.part%d", originalPath.c_str(), part), WriteOnly);
} }
if (finalWriteSize == 0) { if (finalWriteSize == 0) {
return (int32_t) writeSize; return (int32_t) writeSize;
@ -134,8 +134,8 @@ int32_t WriteOnlyFileWithCache::seek(int64_t offset, int32_t origin) {
flush(); flush();
close(); close();
part = (offset / SPLIT_SIZE) + 1; part = (offset / SPLIT_SIZE) + 1;
DEBUG_FUNCTION_LINE("Open %s", StringTools::strfmt("%s.part%d", originalPath.c_str(), part).c_str()); DEBUG_FUNCTION_LINE("Open %s", string_format("%s.part%d", originalPath.c_str(), part).c_str());
this->open(StringTools::strfmt("%s.part%d", originalPath.c_str(), part), ReadWrite); this->open(string_format("%s.part%d", originalPath.c_str(), part), ReadWrite);
} }
return CFile::seek(offset % SPLIT_SIZE, SEEK_SET); return CFile::seek(offset % SPLIT_SIZE, SEEK_SET);
} }

View File

@ -1,39 +1,48 @@
#include <whb/log.h> #include "MainApplicationState.h"
#include <whb/log_udp.h> #include "input/VPADInput.h"
#include <whb/proc.h> #include "utils/WiiUScreen.h"
#include "utils/logger.h"
#include <thread>
#include <coreinit/debug.h> #include <coreinit/debug.h>
#include <coreinit/energysaver.h> #include <coreinit/energysaver.h>
#include <coreinit/title.h> #include <coreinit/title.h>
#include <input/CombinedInput.h> #include <input/CombinedInput.h>
#include <input/WPADInput.h> #include <input/WPADInput.h>
#include <iosuhax.h> #include <mocha/disc_interface.h>
#include <mocha/mocha.h>
#include <ntfs.h> #include <ntfs.h>
#include <padscore/kpad.h> #include <padscore/kpad.h>
#include <thread>
#include <whb/log.h>
#include <whb/proc.h>
#include "MainApplicationState.h" void initMochaLib();
#include "input/VPADInput.h"
#include "utils/WiiUScreen.h"
#include "utils/logger.h"
void deInitMochaLib();
void initIOSUHax();
void deInitIOSUHax();
void main_loop(); void main_loop();
bool sIosuhaxMount = false; bool slibMochaMount = false;
extern "C" void ACPInitialize();
static uint32_t
procHomeButtonDeniedCustom(void *context) {
if (!gBlockHomeButton && gRunFromHBL) {
WHBProcStopRunning();
} else {
gBlockHomeButtonCooldown = 5;
}
return 0;
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
WHBLogUdpInit(); initLogging();
DEBUG_FUNCTION_LINE("Hello from wudump!"); DEBUG_FUNCTION_LINE("Hello from wudump!");
WHBProcInit(); WHBProcInit();
WiiUScreen::Init(); WiiUScreen::Init();
initIOSUHax(); initMochaLib();
ACPInitialize();
uint64_t titleID = OSGetTitleID(); uint64_t titleID = OSGetTitleID();
if (titleID == 0x0005000013374842 || if (titleID == 0x0005000013374842 ||
@ -41,6 +50,12 @@ int main(int argc, char **argv) {
titleID == 0x000500101004A100 || titleID == 0x000500101004A100 ||
titleID == 0x000500101004A200) { titleID == 0x000500101004A200) {
gRunFromHBL = true; gRunFromHBL = true;
ProcUIClearCallbacks();
ProcUIRegisterCallback(PROCUI_CALLBACK_HOME_BUTTON_DENIED,
&procHomeButtonDeniedCustom, NULL, 100);
} else { } else {
gRunFromHBL = false; gRunFromHBL = false;
} }
@ -66,7 +81,7 @@ int main(int argc, char **argv) {
WPADInput::close(); WPADInput::close();
if (ntfs_mounts != nullptr) { if (ntfs_mounts != nullptr) {
int i = 0; int i;
for (i = 0; i < ntfs_mount_count; i++) { for (i = 0; i < ntfs_mount_count; i++) {
ntfsUnmount(ntfs_mounts[i].name, true); ntfsUnmount(ntfs_mounts[i].name, true);
} }
@ -78,7 +93,7 @@ int main(int argc, char **argv) {
IMEnableAPD(); IMEnableAPD();
} }
deInitIOSUHax(); deInitMochaLib();
WiiUScreen::DeInit(); WiiUScreen::DeInit();
WHBProcShutdown(); WHBProcShutdown();
@ -97,11 +112,6 @@ void main_loop() {
WPAD_CHAN_2, WPAD_CHAN_2,
WPAD_CHAN_3}; WPAD_CHAN_3};
if (gFSAfd < 0 || !sIosuhaxMount) {
// state.setError(MainApplicationState::eErrorState::ERROR_IOSUHAX_FAILED);
OSFatal("IOSUHAX Failed");
}
DEBUG_FUNCTION_LINE("Entering main loop"); DEBUG_FUNCTION_LINE("Entering main loop");
while (WHBProcIsRunning()) { while (WHBProcIsRunning()) {
baseInput.reset(); baseInput.reset();
@ -119,27 +129,22 @@ void main_loop() {
} }
} }
void initIOSUHax() { void initMochaLib() {
sIosuhaxMount = false; slibMochaMount = false;
int res = IOSUHAX_Open(nullptr); MochaUtilsStatus res = Mocha_InitLibrary();
if (res < 0) { if (res != MOCHA_RESULT_SUCCESS) {
DEBUG_FUNCTION_LINE("IOSUHAX_open failed"); DEBUG_FUNCTION_LINE_ERR("Mocha_InitLibrary failed: %s", Mocha_GetStatusStr(res));
OSFatal("Failed to init libmocha. Please update MochaPayload.");
} else { } else {
sIosuhaxMount = true; slibMochaMount = true;
gFSAfd = IOSUHAX_FSA_Open();
if (gFSAfd < 0) {
DEBUG_FUNCTION_LINE("IOSUHAX_FSA_Open failed");
} else {
DEBUG_FUNCTION_LINE("IOSUHAX done");
}
} }
} }
void deInitIOSUHax() { void deInitMochaLib() {
if (sIosuhaxMount) { if (slibMochaMount) {
if (gFSAfd >= 0) { Mocha_DeinitLibrary();
IOSUHAX_FSA_Close(gFSAfd);
}
IOSUHAX_Close();
} }
Mocha_sdio_disc_interface.shutdown();
Mocha_usb_disc_interface.shutdown();
} }

View File

@ -17,7 +17,7 @@
#include "ScreenUtils.h" #include "ScreenUtils.h"
#include <coreinit/screen.h> #include <coreinit/screen.h>
void ScreenUtils::printTextOnScreen(ConsoleScreenID screen, int x, int y, const char *msg) { void ScreenUtils::printTextOnScreen(ConsoleScreenID screen, uint32_t x, uint32_t y, const char *msg) {
if (!msg) { if (!msg) {
return; return;
} }

View File

@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/ ****************************************************************************/
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
//! Defines the ID of a display usable with OSScreen. //! Defines the ID of a display usable with OSScreen.
@ -36,7 +37,7 @@ public:
\param y defines on which line 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. \param msg C string that contains the text to be printed.
**/ **/
static void printTextOnScreen(ConsoleScreenID screen, int x, int y, const char *msg); static void printTextOnScreen(ConsoleScreenID screen, uint32_t x, uint32_t y, const char *msg);
/** /**
Clears the screen for the given screens Clears the screen for the given screens

View File

@ -24,209 +24,15 @@
* for WiiXplorer 2010 * for WiiXplorer 2010
***************************************************************************/ ***************************************************************************/
#include "StringTools.h" #include "StringTools.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string> #include <string>
#include <strings.h>
#include <vector> #include <vector>
#include <wchar.h>
#include <wut_types.h>
bool invalidChar(unsigned char c) {
BOOL StringTools::EndsWith(const std::string &a, const std::string &b) { return !(c >= 0 && c < 128) || c == 0x0A || c == 0x0D;
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) { void StringTools::StripUnicodeAndLineBreak(std::string &str) {
static char b[9]; std::replace(str.begin(), str.end(), (char) 0x0A, ' '); // replace LF with space
b[0] = '\0'; std::replace(str.begin(), str.end(), (char) 0x0D, ' '); // replace CR with space
str.erase(remove_if(str.begin(), str.end(), invalidChar), str.end());
int32_t z;
for (z = 128; z > 0; z >>= 1) {
strcat(b, ((x & z) == z) ? "1" : "0");
}
return b;
}
std::string StringTools::removeCharFromString(std::string &input, char toBeRemoved) {
std::string output = input;
size_t position;
while (1) {
position = output.find(toBeRemoved);
if (position == std::string::npos)
break;
output.erase(position, 1);
}
return output;
}
const char *StringTools::fmt(const char *format, ...) {
static char strChar[512];
strChar[0] = 0;
va_list va;
va_start(va, format);
if ((vsprintf(strChar, format, va) >= 0)) {
va_end(va);
return (const char *) strChar;
}
va_end(va);
return NULL;
}
const wchar_t *StringTools::wfmt(const char *format, ...) {
static char tmp[512];
static wchar_t strWChar[512];
strWChar[0] = 0;
tmp[0] = 0;
if (!format)
return (const wchar_t *) strWChar;
if (strcmp(format, "") == 0)
return (const wchar_t *) strWChar;
va_list va;
va_start(va, format);
if ((vsprintf(tmp, format, va) >= 0)) {
int32_t bt;
int32_t strlength = strlen(tmp);
bt = mbstowcs(strWChar, tmp, (strlength < 512) ? strlength : 512);
if (bt > 0) {
strWChar[bt] = 0;
return (const wchar_t *) strWChar;
}
}
va_end(va);
return NULL;
}
int32_t StringTools::strprintf(std::string &str, const char *format, ...) {
static char tmp[512];
tmp[0] = 0;
int32_t result = 0;
va_list va;
va_start(va, format);
if ((vsprintf(tmp, format, va) >= 0)) {
str = tmp;
result = str.size();
}
va_end(va);
return result;
}
std::string StringTools::strfmt(const char *format, ...) {
std::string str;
static char tmp[512];
tmp[0] = 0;
va_list va;
va_start(va, format);
if ((vsprintf(tmp, format, va) >= 0)) {
str = tmp;
}
va_end(va);
return str;
}
BOOL StringTools::char2wchar_t(const char *strChar, wchar_t *dest) {
if (!strChar || !dest)
return false;
int32_t bt;
bt = mbstowcs(dest, strChar, strlen(strChar));
if (bt > 0) {
dest[bt] = 0;
return true;
}
return false;
}
int32_t StringTools::strtokcmp(const char *string, const char *compare, const char *separator) {
if (!string || !compare)
return -1;
char TokCopy[512];
strncpy(TokCopy, compare, sizeof(TokCopy));
TokCopy[511] = '\0';
char *strTok = strtok(TokCopy, separator);
while (strTok != NULL) {
if (strcasecmp(string, strTok) == 0) {
return 0;
}
strTok = strtok(NULL, separator);
}
return -1;
}
int32_t StringTools::strextcmp(const char *string, const char *extension, char seperator) {
if (!string || !extension)
return -1;
char *ptr = strrchr(string, seperator);
if (!ptr)
return -1;
return strcasecmp(ptr + 1, extension);
}
std::vector<std::string> StringTools::stringSplit(const std::string &inValue, const std::string &splitter) {
std::string value = inValue;
std::vector<std::string> result;
while (true) {
uint32_t index = value.find(splitter);
if (index == std::string::npos) {
result.push_back(value);
break;
}
std::string first = value.substr(0, index);
result.push_back(first);
if (index + splitter.size() == value.length()) {
result.push_back("");
break;
}
if (index + splitter.size() > value.length()) {
break;
}
value = value.substr(index + splitter.size(), value.length());
}
return result;
}
bool StringTools::findStringIC(const std::string &strHaystack, const std::string &strNeedle) {
auto it = std::search(
strHaystack.begin(), strHaystack.end(),
strNeedle.begin(), strNeedle.end(),
[](char ch1, char ch2) { return std::toupper(ch1) == std::toupper(ch2); });
return (it != strHaystack.end());
}
bool StringTools::replace(std::string &str, const std::string &from, const std::string &to) {
size_t start_pos = str.find(from);
if (start_pos == std::string::npos) {
return false;
}
str.replace(start_pos, from.length(), to);
return true;
}
bool StringTools::strCompareIC(const std::string &str1, const std::string &str2) {
return str1.size() == str2.size() && std::equal(str1.begin(), str1.end(), str2.begin(), [](auto a, auto b) { return std::tolower(a) == std::tolower(b); });
} }

View File

@ -25,71 +25,31 @@
***************************************************************************/ ***************************************************************************/
#pragma once #pragma once
#include "logger.h"
#include "utils.h"
#include <algorithm> #include <algorithm>
#include <cctype> #include <cctype>
#include <coreinit/debug.h>
#include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
#include <wut_types.h> #include <wut_types.h>
template<typename... Args>
std::string string_format(const std::string &format, Args... args) {
int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0'
auto size = static_cast<size_t>(size_s);
auto buf = make_unique_nothrow<char[]>(size);
if (!buf) {
DEBUG_FUNCTION_LINE_ERR("string_format failed, not enough memory");
OSFatal("string_format failed, not enough memory");
return std::string("");
}
std::snprintf(buf.get(), size, format.c_str(), args...);
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
}
class StringTools { class StringTools {
public: public:
static BOOL EndsWith(const std::string &a, const std::string &b); static void StripUnicodeAndLineBreak(std::string &str);
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);
}; };

15
source/utils/WUDUtils.cpp Normal file
View File

@ -0,0 +1,15 @@
#include "WUDUtils.h"
#include "FSTUtils.h"
std::optional<uint64_t> WUDUtils::getOffsetOfContent(const std::shared_ptr<WiiUGMPartition> &gamePartition, const std::shared_ptr<FST> &fst, const std::shared_ptr<Content> &content) {
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.has_value()) {
DEBUG_FUNCTION_LINE_ERR("Failed to get section for Content");
return {};
}
return gamePartition->getSectionOffsetOnDefaultPartition() + info.value()->address.getAddressInBytes();
}

11
source/utils/WUDUtils.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include "WUD/content/partitions/WiiUGMPartition.h"
#include "WUD/entities/FST/FST.h"
#include "WUD/entities/TMD/Content.h"
#include <memory>
#include <optional>
class WUDUtils {
public:
static std::optional<uint64_t> getOffsetOfContent(const std::shared_ptr<WiiUGMPartition> &gamePartition, const std::shared_ptr<FST> &fst, const std::shared_ptr<Content> &content);
};

View File

@ -13,7 +13,7 @@ uint32_t WiiUScreen::consoleColor = 0x041F60FF;
uint32_t WiiUScreen::consoleCursorY = 0; uint32_t WiiUScreen::consoleCursorY = 0;
uint32_t WiiUScreen::ProcCallbackAcquired(void *context) { uint32_t WiiUScreen::ProcCallbackAcquired([[maybe_unused]] void *context) {
MEMHeapHandle heap = MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM1); MEMHeapHandle heap = MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM1);
if (sBufferSizeTV) { if (sBufferSizeTV) {
sBufferTV = MEMAllocFromFrmHeapEx(heap, sBufferSizeTV, 4); sBufferTV = MEMAllocFromFrmHeapEx(heap, sBufferSizeTV, 4);
@ -29,7 +29,7 @@ uint32_t WiiUScreen::ProcCallbackAcquired(void *context) {
return 0; return 0;
} }
uint32_t WiiUScreen::ProcCallbackReleased(void *context) { uint32_t WiiUScreen::ProcCallbackReleased([[maybe_unused]] void *context) {
MEMHeapHandle heap = MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM1); MEMHeapHandle heap = MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM1);
MEMFreeByStateToFrmHeap(heap, CONSOLE_FRAME_HEAP_TAG); MEMFreeByStateToFrmHeap(heap, CONSOLE_FRAME_HEAP_TAG);
sConsoleHasForeground = FALSE; sConsoleHasForeground = FALSE;

View File

@ -27,9 +27,9 @@
class WiiUScreen { class WiiUScreen {
public: public:
static uint32_t ProcCallbackAcquired(void *context); static uint32_t ProcCallbackAcquired([[maybe_unused]] void *context);
static uint32_t ProcCallbackReleased(void *context); static uint32_t ProcCallbackReleased([[maybe_unused]] void *context);
static bool Init(); static bool Init();

38
source/utils/logger.c Normal file
View File

@ -0,0 +1,38 @@
#ifdef DEBUG
#include <nsysnet/_socket.h>
#include <stdint.h>
#include <whb/log_cafe.h>
#include <whb/log_module.h>
#include <whb/log_udp.h>
uint32_t moduleLogInit = false;
uint32_t cafeLogInit = false;
uint32_t udpLogInit = false;
#endif // DEBUG
void initLogging() {
#ifdef DEBUG
if (!(moduleLogInit = WHBLogModuleInit())) {
socket_lib_init();
cafeLogInit = WHBLogCafeInit();
udpLogInit = WHBLogUdpInit();
}
#endif // DEBUG
}
void deinitLogging() {
#ifdef DEBUG
if (moduleLogInit) {
WHBLogModuleDeinit();
moduleLogInit = false;
}
if (cafeLogInit) {
WHBLogCafeDeinit();
cafeLogInit = false;
}
if (udpLogInit) {
WHBLogUdpDeinit();
udpLogInit = false;
}
#endif // DEBUG
}

View File

@ -1,24 +1,56 @@
#pragma once #pragma once
#include <coreinit/debug.h>
#include <string.h>
#include <whb/log.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#include <cstring> #define LOG_APP_TYPE "H"
#include <whb/log.h> #define LOG_APP_NAME "WUDD"
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) #define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__) #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) \ #define LOG(LOG_FUNC, FMT, ARGS...) LOG_EX(LOG_FUNC, "", "", FMT, ##ARGS)
do { \
WHBLogPrintf("[%23s]%30s@L%04d: " FMT, __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \ #define LOG_EX(LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) \
do { \
LOG_FUNC("[(%s)%18s][%23s]%30s@L%04d: " LOG_LEVEL "" FMT "" LINE_END, LOG_APP_TYPE, LOG_APP_NAME, __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
} while (0) } while (0)
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) \
do { \ #ifdef DEBUG
WHBLogWritef("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
} while (0) #ifdef VERBOSE_DEBUG
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
#else
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
#endif
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) LOG(WHBLogWritef, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS)
#else
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX(OSReport, "##ERROR## ", "\n", FMT, ##ARGS)
#endif
void initLogging();
void deinitLogging();
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1,12 +1,9 @@
#pragma once #pragma once
#include <malloc.h> #include <malloc.h>
#include <memory>
#include <string> #include <string>
#ifdef __cplusplus
extern "C" {
#endif
#define LIMIT(x, min, max) \ #define LIMIT(x, min, max) \
({ \ ({ \
typeof(x) _x = x; \ typeof(x) _x = x; \
@ -37,10 +34,20 @@ unsigned long long swap_uint64(unsigned long long val);
void calculateHash256(unsigned char *data, unsigned int length, unsigned char *hashOut); void calculateHash256(unsigned char *data, unsigned int length, unsigned char *hashOut);
#ifdef __cplusplus template<class T, class... Args>
std::unique_ptr<T> make_unique_nothrow(Args &&...args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
return std::unique_ptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
} }
#endif
template<typename T>
inline typename std::unique_ptr<T> make_unique_nothrow(size_t num) noexcept {
return std::unique_ptr<T>(new (std::nothrow) std::remove_extent_t<T>[num]());
}
template<class T, class... Args>
std::shared_ptr<T> make_shared_nothrow(Args &&...args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
return std::shared_ptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
}
class Utils { class Utils {
public: public: