mirror of
https://github.com/wiiu-env/wudd.git
synced 2024-11-25 19:26:58 +01:00
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:
parent
90b6a36add
commit
05aea5756b
@ -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
|
19
Makefile
19
Makefile
@ -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
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
|
18
README.md
18
README.md
@ -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.
|
||||||
|
@ -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");
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
@ -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 *) §or_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 *) §or_buf[0], (uint8_t *) §or_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;
|
||||||
|
@ -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;
|
||||||
};
|
};
|
@ -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;
|
||||||
};
|
};
|
@ -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();
|
|
||||||
}
|
|
||||||
|
@ -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;
|
|
||||||
};
|
};
|
@ -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)) {
|
||||||
}
|
}
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
};
|
};
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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)) {
|
||||||
|
}
|
||||||
};
|
|
||||||
|
@ -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);
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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{};
|
||||||
};
|
};
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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);
|
||||||
};
|
};
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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)),
|
||||||
|
@ -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);
|
||||||
};
|
};
|
@ -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 {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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];
|
||||||
|
@ -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 {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {};
|
||||||
}
|
}
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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 {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
@ -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(
|
||||||
|
@ -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);
|
||||||
};
|
};
|
@ -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)) {
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
}
|
}
|
@ -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);
|
||||||
};
|
};
|
@ -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();
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
|
@ -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;
|
||||||
};
|
};
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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); });
|
|
||||||
}
|
}
|
@ -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
15
source/utils/WUDUtils.cpp
Normal 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
11
source/utils/WUDUtils.h
Normal 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);
|
||||||
|
};
|
@ -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;
|
||||||
|
@ -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
38
source/utils/logger.c
Normal 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
|
||||||
|
}
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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:
|
||||||
|
Loading…
Reference in New Issue
Block a user