Skip to content

Commit

Permalink
Various improvements including:
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
Maschell committed Jul 27, 2022
1 parent 90b6a36 commit 05aea57
Show file tree
Hide file tree
Showing 74 changed files with 928 additions and 825 deletions.
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM wiiuenv/devkitppc:20220724

COPY --from=wiiuenv/libiosuhax:20220523 /artifacts $DEVKITPRO
COPY --from=wiiuenv/libntfs:20201210 /artifacts $DEVKITPRO
COPY --from=wiiuenv/libntfs:20220726 /artifacts $DEVKITPRO
COPY --from=wiiuenv/libmocha:20220726 /artifacts $DEVKITPRO

WORKDIR project
19 changes: 16 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ SOURCES := source \
source/WUD/entities/TMD

DATA := data
INCLUDES := include source
INCLUDES := source

#-------------------------------------------------------------------------------
# options for code generation
#-------------------------------------------------------------------------------
CFLAGS := -g -Wall -O0 -ffunction-sections \
CFLAGS := -g -Wall -O2 -ffunction-sections \
$(MACHDEP)

CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
Expand All @@ -66,14 +66,25 @@ CXXFLAGS := $(CFLAGS) -std=gnu++20
ASFLAGS := -g $(ARCH)
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
# containing include and lib
#-------------------------------------------------------------------------------
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
Expand Down Expand Up @@ -178,6 +189,8 @@ $(OUTPUT).elf : $(OFILES)

$(OFILES_SRC) : $(HFILES_BIN)

-include $(DEPENDS)

#-------------------------------------------------------------------------------
endif
#-------------------------------------------------------------------------------
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Inspired by [wudump](https://github.com/FIX94/wudump) from FIX94.

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

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).
Expand All @@ -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.

Example:
`copy /b "game.wux.part1" + "game.wux.part2" "C:\wudump\game.wux"`
`copy /b game.wux.part1 + game.wux.part2 game.wux`

## 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)
- [libiosuhax](https://github.com/wiiu-env/libiosuhax)
- [libmocha](https://github.com/wiiu-env/libmocha)
- [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

It's possible to use a docker image for building. This way you don't need anything installed on your host system.
Expand Down
12 changes: 10 additions & 2 deletions source/ApplicationState.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class ApplicationState {
this->selectedOptionY++;
}
if (this->selectedOptionY < 0) {
this->selectedOptionY = maxOptionValue;
this->selectedOptionY = maxOptionValue - 1;
} else if (this->selectedOptionY >= maxOptionValue) {
this->selectedOptionY = 0;
}
Expand All @@ -46,6 +46,10 @@ class ApplicationState {
}
}

virtual bool buttonPressed(Input *input, Input::eButtons button) {
return input->data.buttons_d & button;
}

virtual bool entrySelected(Input *input) {
return input->data.buttons_d & Input::BUTTON_A;
}
Expand All @@ -57,9 +61,13 @@ class ApplicationState {
}

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_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_DRC, 0, 17, "Created by Maschell, inspired by wudump from FIX94");
Expand Down
87 changes: 70 additions & 17 deletions source/GMPartitionsDumperState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,25 @@
#include <WUD/header/WiiUDiscHeader.h>
#include <common/common.h>
#include <fs/FSUtils.h>
#include <iosuhax.h>
#include <memory>
#include <mocha/fsa.h>
#include <mocha/mocha.h>
#include <utils/StringTools.h>

#define READ_BUFFER_SIZE (SECTOR_SIZE * 128)

GMPartitionsDumperState::GMPartitionsDumperState(eDumpTarget pTargetDevice) : targetDevice(pTargetDevice) {
this->sectorBufSize = SECTOR_SIZE;
this->state = STATE_OPEN_ODD1;
gBlockHomeButton = true;
}

GMPartitionsDumperState::~GMPartitionsDumperState() {
free(this->sectorBuf);
this->sectorBuf = nullptr;
free(this->readBuffer);
this->readBuffer = nullptr;
gBlockHomeButton = false;
}

void GMPartitionsDumperState::render() {
Expand Down Expand Up @@ -73,11 +76,22 @@ void GMPartitionsDumperState::render() {
} else {
uint32_t index = 0;
for (auto &partitionPair : gmPartitionPairs) {
uint32_t size = 0;
uint64_t size = 0;
for (auto &content : partitionPair.second->tmd->contentList) {
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++;
}
WiiUScreen::drawLine();
Expand All @@ -94,6 +108,8 @@ void GMPartitionsDumperState::render() {
} else if (this->state == STATE_DUMP_PARTITION_CONTENTS) {
if (curPartition != nullptr) {
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 {
WiiUScreen::drawLine("Dumping Partition");
}
Expand Down Expand Up @@ -127,10 +143,22 @@ void GMPartitionsDumperState::render() {
if (size > 0) {
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);
} else {
WiiUScreen::drawLine();
}
WiiUScreen::drawLine();
WiiUScreen::drawLine("Press B to abort the dumping");

} else if (this->state == STATE_DUMP_DONE) {
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();
Expand All @@ -149,17 +177,15 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
}

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 (this->sectorBuf == nullptr) {
this->sectorBuf = (void *) memalign(0x100, this->sectorBufSize);
if (this->sectorBuf == nullptr) {
DEBUG_FUNCTION_LINE("ERROR_MALLOC_FAILED");
this->setError(ERROR_MALLOC_FAILED);
return ApplicationState::SUBSTATE_RUNNING;
}
}
DEBUG_FUNCTION_LINE("Opened /dev/odd01 %d", this->oddFd);
this->state = STATE_READ_DISC_INFO;
} else {
this->state = STATE_PLEASE_INSERT_DISC;
Expand All @@ -169,7 +195,7 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
return ApplicationState::SUBSTATE_RETURN;
}
} 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';
memcpy(this->discId.data(), sectorBuf, 10);
if (this->discId[0] == 0) {
Expand All @@ -180,27 +206,30 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
this->state = STATE_READ_DISC_INFO_DONE;
return ApplicationState::SUBSTATE_RUNNING;
}
FSAEx_RawClose(__wut_devoptab_fs_client, this->oddFd);
this->oddFd = -1;

this->setError(ERROR_READ_FIRST_SECTOR);
return ApplicationState::SUBSTATE_RUNNING;
} else if (this->state == STATE_READ_DISC_INFO_DONE) {
this->state = STATE_READ_COMMON_KEY;
} else if (this->state == STATE_READ_COMMON_KEY) {
uint8_t opt[0x400];
IOSUHAX_read_otp(opt, 0x400);
memcpy(cKey.data(), opt + 0xE0, 0x10);
WiiUConsoleOTP otp;
Mocha_ReadOTP(&otp);
memcpy(cKey.data(), otp.wiiUBank.wiiUCommonKey, 0x10);
this->state = STATE_CREATE_DISC_READER;
} else if (this->state == STATE_CREATE_DISC_READER) {
this->discReader = std::make_shared<DiscReaderDiscDrive>();
if (!discReader->IsReady()) {
auto discReaderOpt = DiscReaderDiscDrive::make_unique();
if (!discReaderOpt) {
this->setError(ERROR_OPEN_ODD1);
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) {
auto discHeaderOpt = WiiUDiscHeader::make_unique(discReader);
if (!discHeaderOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to read DiscHeader");
DEBUG_FUNCTION_LINE_ERR("Failed to read DiscHeader");
this->setError(ERROR_PARSE_DISCHEADER);
return SUBSTATE_RUNNING;
}
Expand All @@ -217,16 +246,22 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
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;
} else if (this->state == STATE_CHOOSE_PARTITION_TO_DUMP) {
if (gmPartitionPairs.empty()) {
if (entrySelected(input)) {
return SUBSTATE_RETURN;
}
}

if (buttonPressed(input, Input::BUTTON_B)) {
return SUBSTATE_RETURN;
}

proccessMenuNavigationY(input, (int32_t) gmPartitionPairs.size() + 1);
if (entrySelected(input)) {
if (selectedOptionY >= (int32_t) gmPartitionPairs.size()) {
Expand All @@ -243,7 +278,7 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
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())) {
this->setError(ERROR_CREATE_DIR);
return SUBSTATE_RUNNING;
Expand Down Expand Up @@ -292,6 +327,10 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
this->curContentIndex = 0;
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.
if (curContent == nullptr) {
auto curContentOpt = curNUSTitle->tmd->getContentByIndex(curContentIndex);
Expand Down Expand Up @@ -350,7 +389,7 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {

// alloc readBuffer if needed
if (this->readBuffer == nullptr) {
readBuffer = (uint8_t *) malloc(READ_BUFFER_SIZE);
readBuffer = (uint8_t *) memalign(0x40, ROUNDUP(READ_BUFFER_SIZE, 0x40));
if (readBuffer == nullptr) {
this->setError(ERROR_MALLOC_FAILED);
return SUBSTATE_RUNNING;
Expand All @@ -376,6 +415,20 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
// Go on!
this->state = STATE_DUMP_PARTITION_CONTENTS;
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) {
if (entrySelected(input)) {
return ApplicationState::SUBSTATE_RETURN;
Expand Down
7 changes: 4 additions & 3 deletions source/GMPartitionsDumperState.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ class GMPartitionsDumperState : public ApplicationState {
STATE_DUMP_PARTITION_TICKET,
STATE_DUMP_PARTITION_CERT,
STATE_DUMP_PARTITION_CONTENTS,
STATE_DUMP_DONE
STATE_DUMP_DONE,
STATE_ABORT_CONFIRMATION
};

enum eErrorState {
Expand Down Expand Up @@ -92,8 +93,8 @@ class GMPartitionsDumperState : public ApplicationState {
int32_t oddFd = -1;
void *sectorBuf = nullptr;
uint32_t sectorBufSize;
std::shared_ptr<DiscReaderDiscDrive> discReader = nullptr;
std::unique_ptr<WiiUDiscHeader> discHeader = nullptr;
std::shared_ptr<DiscReader> discReader;
std::unique_ptr<WiiUDiscHeader> discHeader;

std::shared_ptr<WiiUGMPartition> curPartition = nullptr;
std::shared_ptr<NUSDataProvider> dataProvider = nullptr;
Expand Down
Loading

0 comments on commit 05aea57

Please sign in to comment.