mirror of
https://github.com/wiiu-env/wudd.git
synced 2024-11-22 09:59:16 +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
|
||||
|
||||
COPY --from=wiiuenv/libiosuhax:20220523 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/libntfs:20201210 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/libntfs:20220726 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/libmocha:20220726 /artifacts $DEVKITPRO
|
||||
|
||||
WORKDIR project
|
19
Makefile
19
Makefile
@ -51,12 +51,12 @@ SOURCES := source \
|
||||
source/WUD/entities/TMD
|
||||
|
||||
DATA := data
|
||||
INCLUDES := include source
|
||||
INCLUDES := source
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#-------------------------------------------------------------------------------
|
||||
CFLAGS := -g -Wall -O0 -ffunction-sections \
|
||||
CFLAGS := -g -Wall -O2 -ffunction-sections \
|
||||
$(MACHDEP)
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
|
||||
@ -66,7 +66,7 @@ CXXFLAGS := $(CFLAGS) -std=gnu++20
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
LIBS := -lwut -lntfs -liosuhax
|
||||
LIBS := -lwut -lntfs -lmocha
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level
|
||||
@ -74,6 +74,17 @@ LIBS := -lwut -lntfs -liosuhax
|
||||
#-------------------------------------------------------------------------------
|
||||
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
|
||||
@ -178,6 +189,8 @@ $(OUTPUT).elf : $(OFILES)
|
||||
|
||||
$(OFILES_SRC) : $(HFILES_BIN)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
endif
|
||||
#-------------------------------------------------------------------------------
|
||||
|
18
README.md
18
README.md
@ -4,7 +4,7 @@ Inspired by [wudump](https://github.com/FIX94/wudump) from FIX94.
|
||||
|
||||
Features:
|
||||
- Dump a Wii U Disc in WUD (uncompressed) or [WUX](https://gbatemp.net/threads/wii-u-image-wud-compression-tool.397901/) (loseless compression) format (including the game.key)
|
||||
- Dump the GM Partitions (Game, Updates, DLCs) of an WiiU Disc as *.app,*.h3, .tmd, .tik, .cert files
|
||||
- Dump the GM Partitions (Game, Updates, DLCs) of an Wii U Disc as *.app,*.h3, .tmd, .tik, .cert files
|
||||
- Supports dumping to SD (FAT32) and USB (NTFS only). When dumping to SD the files get slitted in 2 GiB parts.
|
||||
|
||||
Files will be dumped to `/wudump/[DISC-ID]/`. The DiscID of a game can be found on the disc (e.g. WUP-P-ARDP for the EUR version of Super Mario 3D World).
|
||||
@ -14,14 +14,26 @@ Files will be dumped to `/wudump/[DISC-ID]/`. The DiscID of a game can be found
|
||||
When you dump a .wux or .wud to the SD card it gets splitted into 2 GiB parts (FAT32 limitation). To merge them you can use the `copy` cmd tool.
|
||||
|
||||
Example:
|
||||
`copy /b "game.wux.part1" + "game.wux.part2" "C:\wudump\game.wux"`
|
||||
`copy /b game.wux.part1 + game.wux.part2 game.wux`
|
||||
|
||||
## Dependencies
|
||||
Requires an [Environment](https://github.com/wiiu-env/EnvironmentLoader) (e.g. Tiramisu or Aroma) with [MochaPayload](https://github.com/wiiu-env/MochaPayload) (Nightly-MochaPayload-20220725-155554 or newer)
|
||||
|
||||
- [wut](https://github.com/devkitPro/wut)
|
||||
- [libiosuhax](https://github.com/wiiu-env/libiosuhax)
|
||||
- [libmocha](https://github.com/wiiu-env/libmocha)
|
||||
- [libntfs](https://github.com/wiiu-env/libntfs)
|
||||
|
||||
## Buildflags
|
||||
|
||||
### Logging
|
||||
Building via `make` only logs errors (via OSReport). To enable logging via the [LoggingModule](https://github.com/wiiu-env/LoggingModule) set `DEBUG` to `1` or `VERBOSE`.
|
||||
|
||||
`make` Logs errors only (via OSReport).
|
||||
`make DEBUG=1` Enables information and error logging via [LoggingModule](https://github.com/wiiu-env/LoggingModule).
|
||||
`make DEBUG=VERBOSE` Enables verbose information and error logging via [LoggingModule](https://github.com/wiiu-env/LoggingModule).
|
||||
|
||||
If the [LoggingModule](https://github.com/wiiu-env/LoggingModule) is not present, it'll fallback to UDP (Port 4405) and [CafeOS](https://github.com/wiiu-env/USBSerialLoggingModule) logging.
|
||||
|
||||
## Building using the Dockerfile
|
||||
|
||||
It's possible to use a docker image for building. This way you don't need anything installed on your host system.
|
||||
|
@ -26,7 +26,7 @@ public:
|
||||
this->selectedOptionY++;
|
||||
}
|
||||
if (this->selectedOptionY < 0) {
|
||||
this->selectedOptionY = maxOptionValue;
|
||||
this->selectedOptionY = maxOptionValue - 1;
|
||||
} else if (this->selectedOptionY >= maxOptionValue) {
|
||||
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) {
|
||||
return input->data.buttons_d & Input::BUTTON_A;
|
||||
}
|
||||
@ -57,9 +61,13 @@ public:
|
||||
}
|
||||
|
||||
virtual void printFooter() {
|
||||
if (gRunFromHBL) {
|
||||
if (gRunFromHBL && !gBlockHomeButton) {
|
||||
ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_TV, 0, 25, "Press HOME to exit to HBL");
|
||||
ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_DRC, 0, 15, "Press HOME to exit to HBL");
|
||||
} else if (gRunFromHBL && gBlockHomeButtonCooldown > 0) {
|
||||
ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_TV, 0, 25, "You can not exit while dumping.");
|
||||
ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_DRC, 0, 15, "You can not exit while dumping.");
|
||||
gBlockHomeButtonCooldown--;
|
||||
}
|
||||
ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_TV, 0, 27, "Created by Maschell, inspired by wudump from FIX94");
|
||||
ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_DRC, 0, 17, "Created by Maschell, inspired by wudump from FIX94");
|
||||
|
@ -21,8 +21,9 @@
|
||||
#include <WUD/header/WiiUDiscHeader.h>
|
||||
#include <common/common.h>
|
||||
#include <fs/FSUtils.h>
|
||||
#include <iosuhax.h>
|
||||
#include <memory>
|
||||
#include <mocha/fsa.h>
|
||||
#include <mocha/mocha.h>
|
||||
#include <utils/StringTools.h>
|
||||
|
||||
#define READ_BUFFER_SIZE (SECTOR_SIZE * 128)
|
||||
@ -30,6 +31,7 @@
|
||||
GMPartitionsDumperState::GMPartitionsDumperState(eDumpTarget pTargetDevice) : targetDevice(pTargetDevice) {
|
||||
this->sectorBufSize = SECTOR_SIZE;
|
||||
this->state = STATE_OPEN_ODD1;
|
||||
gBlockHomeButton = true;
|
||||
}
|
||||
|
||||
GMPartitionsDumperState::~GMPartitionsDumperState() {
|
||||
@ -37,6 +39,7 @@ GMPartitionsDumperState::~GMPartitionsDumperState() {
|
||||
this->sectorBuf = nullptr;
|
||||
free(this->readBuffer);
|
||||
this->readBuffer = nullptr;
|
||||
gBlockHomeButton = false;
|
||||
}
|
||||
|
||||
void GMPartitionsDumperState::render() {
|
||||
@ -73,11 +76,22 @@ void GMPartitionsDumperState::render() {
|
||||
} else {
|
||||
uint32_t index = 0;
|
||||
for (auto &partitionPair : gmPartitionPairs) {
|
||||
uint32_t size = 0;
|
||||
uint64_t size = 0;
|
||||
for (auto &content : partitionPair.second->tmd->contentList) {
|
||||
size += ROUNDUP(content->encryptedFileSize, 16);
|
||||
}
|
||||
WiiUScreen::drawLinef("%s %s (~%0.2f MiB)", index == (uint32_t) selectedOptionY ? ">" : " ", partitionPair.first->getVolumeId().c_str(), (float) size / 1024.0f / 1024.0f);
|
||||
std::string titleId = partitionPair.first->getVolumeId().substr(2, 18);
|
||||
std::string appType = "Other ";
|
||||
if (titleId.starts_with("00050000")) {
|
||||
appType = "Game ";
|
||||
} else if (titleId.starts_with("0005000C")) {
|
||||
appType = "DLC ";
|
||||
} else if (titleId.starts_with("0005000E")) {
|
||||
appType = "Update";
|
||||
}
|
||||
WiiUScreen::drawLinef("%s %s - %s (~%0.2f GiB) (%s)", index == (uint32_t) selectedOptionY ? ">" : " ", appType.c_str(),
|
||||
partitionPair.second->getShortnameEn().c_str(),
|
||||
(float) ((float) size / 1024.0f / 1024.0f / 1024.0f), titleId.c_str());
|
||||
index++;
|
||||
}
|
||||
WiiUScreen::drawLine();
|
||||
@ -94,6 +108,8 @@ void GMPartitionsDumperState::render() {
|
||||
} else if (this->state == STATE_DUMP_PARTITION_CONTENTS) {
|
||||
if (curPartition != nullptr) {
|
||||
WiiUScreen::drawLinef("Dumping Partition %s", curPartition->getVolumeId().c_str());
|
||||
WiiUScreen::drawLinef("Name: %s", curNUSTitle->getLongnameEn().c_str(), curNUSTitle->tmd->titleId);
|
||||
WiiUScreen::drawLinef("TitleID: %016llX", curNUSTitle->tmd->titleId);
|
||||
} else {
|
||||
WiiUScreen::drawLine("Dumping Partition");
|
||||
}
|
||||
@ -127,10 +143,22 @@ void GMPartitionsDumperState::render() {
|
||||
if (size > 0) {
|
||||
WiiUScreen::drawLinef("Progress: %.2f MiB / %.2f MiB (%0.2f%%)", offset / 1024.0f / 1024.0f,
|
||||
size / 1024.0f / 1024.0f, ((offset * 1.0f) / size) * 100.0f);
|
||||
} else {
|
||||
WiiUScreen::drawLine();
|
||||
}
|
||||
WiiUScreen::drawLine();
|
||||
WiiUScreen::drawLine("Press B to abort the dumping");
|
||||
|
||||
} else if (this->state == STATE_DUMP_DONE) {
|
||||
WiiUScreen::drawLine("Dumping done. Press A to return.");
|
||||
} else if (this->state == STATE_ABORT_CONFIRMATION) {
|
||||
WiiUScreen::drawLinef("Do you really want to abort the disc dumping?");
|
||||
WiiUScreen::drawLinef("");
|
||||
if (selectedOptionX == 0) {
|
||||
WiiUScreen::drawLinef("> Continue dumping Abort dumping");
|
||||
} else {
|
||||
WiiUScreen::drawLinef(" Continue dumping > Abort dumping");
|
||||
}
|
||||
}
|
||||
|
||||
ApplicationState::printFooter();
|
||||
@ -149,17 +177,15 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
|
||||
}
|
||||
|
||||
if (this->state == STATE_OPEN_ODD1) {
|
||||
auto ret = IOSUHAX_FSA_RawOpen(gFSAfd, "/dev/odd01", &(this->oddFd));
|
||||
auto ret = FSAEx_RawOpen(__wut_devoptab_fs_client, "/dev/odd01", &(this->oddFd));
|
||||
if (ret >= 0) {
|
||||
if (this->sectorBuf == nullptr) {
|
||||
this->sectorBuf = (void *) memalign(0x100, this->sectorBufSize);
|
||||
if (this->sectorBuf == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("ERROR_MALLOC_FAILED");
|
||||
this->setError(ERROR_MALLOC_FAILED);
|
||||
return ApplicationState::SUBSTATE_RUNNING;
|
||||
}
|
||||
}
|
||||
DEBUG_FUNCTION_LINE("Opened /dev/odd01 %d", this->oddFd);
|
||||
this->state = STATE_READ_DISC_INFO;
|
||||
} else {
|
||||
this->state = STATE_PLEASE_INSERT_DISC;
|
||||
@ -169,7 +195,7 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
|
||||
return ApplicationState::SUBSTATE_RETURN;
|
||||
}
|
||||
} else if (this->state == STATE_READ_DISC_INFO) {
|
||||
if (IOSUHAX_FSA_RawRead(gFSAfd, this->sectorBuf, READ_SECTOR_SIZE, 1, 0, this->oddFd) >= 0) {
|
||||
if (FSAEx_RawRead(__wut_devoptab_fs_client, this->sectorBuf, READ_SECTOR_SIZE, 1, 0, this->oddFd) >= 0) {
|
||||
this->discId[10] = '\0';
|
||||
memcpy(this->discId.data(), sectorBuf, 10);
|
||||
if (this->discId[0] == 0) {
|
||||
@ -180,27 +206,30 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
|
||||
this->state = STATE_READ_DISC_INFO_DONE;
|
||||
return ApplicationState::SUBSTATE_RUNNING;
|
||||
}
|
||||
FSAEx_RawClose(__wut_devoptab_fs_client, this->oddFd);
|
||||
this->oddFd = -1;
|
||||
|
||||
this->setError(ERROR_READ_FIRST_SECTOR);
|
||||
return ApplicationState::SUBSTATE_RUNNING;
|
||||
} else if (this->state == STATE_READ_DISC_INFO_DONE) {
|
||||
this->state = STATE_READ_COMMON_KEY;
|
||||
} else if (this->state == STATE_READ_COMMON_KEY) {
|
||||
uint8_t opt[0x400];
|
||||
IOSUHAX_read_otp(opt, 0x400);
|
||||
memcpy(cKey.data(), opt + 0xE0, 0x10);
|
||||
WiiUConsoleOTP otp;
|
||||
Mocha_ReadOTP(&otp);
|
||||
memcpy(cKey.data(), otp.wiiUBank.wiiUCommonKey, 0x10);
|
||||
this->state = STATE_CREATE_DISC_READER;
|
||||
} else if (this->state == STATE_CREATE_DISC_READER) {
|
||||
this->discReader = std::make_shared<DiscReaderDiscDrive>();
|
||||
if (!discReader->IsReady()) {
|
||||
auto discReaderOpt = DiscReaderDiscDrive::make_unique();
|
||||
if (!discReaderOpt) {
|
||||
this->setError(ERROR_OPEN_ODD1);
|
||||
return SUBSTATE_RUNNING;
|
||||
}
|
||||
this->state = STATE_PARSE_DISC_HEADER;
|
||||
this->discReader = std::move(discReaderOpt.value());
|
||||
this->state = STATE_PARSE_DISC_HEADER;
|
||||
} else if (this->state == STATE_PARSE_DISC_HEADER) {
|
||||
auto discHeaderOpt = WiiUDiscHeader::make_unique(discReader);
|
||||
if (!discHeaderOpt.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to read DiscHeader");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to read DiscHeader");
|
||||
this->setError(ERROR_PARSE_DISCHEADER);
|
||||
return SUBSTATE_RUNNING;
|
||||
}
|
||||
@ -217,9 +246,10 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
|
||||
return SUBSTATE_RUNNING;
|
||||
}
|
||||
|
||||
this->gmPartitionPairs.emplace_back(gmPartition, nusTitleOpt.value());
|
||||
this->gmPartitionPairs.emplace_back(gmPartition, std::move(nusTitleOpt.value()));
|
||||
}
|
||||
}
|
||||
|
||||
this->state = STATE_CHOOSE_PARTITION_TO_DUMP;
|
||||
} else if (this->state == STATE_CHOOSE_PARTITION_TO_DUMP) {
|
||||
if (gmPartitionPairs.empty()) {
|
||||
@ -227,6 +257,11 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
|
||||
return SUBSTATE_RETURN;
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonPressed(input, Input::BUTTON_B)) {
|
||||
return SUBSTATE_RETURN;
|
||||
}
|
||||
|
||||
proccessMenuNavigationY(input, (int32_t) gmPartitionPairs.size() + 1);
|
||||
if (entrySelected(input)) {
|
||||
if (selectedOptionY >= (int32_t) gmPartitionPairs.size()) {
|
||||
@ -243,7 +278,7 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
|
||||
return SUBSTATE_RUNNING;
|
||||
}
|
||||
|
||||
this->targetPath = StringTools::strfmt("%swudump/%s/%s", getPathForDevice(targetDevice).c_str(), this->discId, curPartition->getVolumeId().c_str());
|
||||
this->targetPath = string_format("%swudump/%s/%s", getPathForDevice(targetDevice).c_str(), this->discId, curPartition->getVolumeId().c_str());
|
||||
if (!FSUtils::CreateSubfolder(targetPath.c_str())) {
|
||||
this->setError(ERROR_CREATE_DIR);
|
||||
return SUBSTATE_RUNNING;
|
||||
@ -292,6 +327,10 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
|
||||
this->curContentIndex = 0;
|
||||
this->state = STATE_DUMP_PARTITION_CONTENTS;
|
||||
} else if (this->state == STATE_DUMP_PARTITION_CONTENTS) {
|
||||
if (buttonPressed(input, Input::BUTTON_B)) {
|
||||
this->state = STATE_ABORT_CONFIRMATION;
|
||||
return ApplicationState::SUBSTATE_RUNNING;
|
||||
}
|
||||
// Get current content by index.
|
||||
if (curContent == nullptr) {
|
||||
auto curContentOpt = curNUSTitle->tmd->getContentByIndex(curContentIndex);
|
||||
@ -350,7 +389,7 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
|
||||
|
||||
// alloc readBuffer if needed
|
||||
if (this->readBuffer == nullptr) {
|
||||
readBuffer = (uint8_t *) malloc(READ_BUFFER_SIZE);
|
||||
readBuffer = (uint8_t *) memalign(0x40, ROUNDUP(READ_BUFFER_SIZE, 0x40));
|
||||
if (readBuffer == nullptr) {
|
||||
this->setError(ERROR_MALLOC_FAILED);
|
||||
return SUBSTATE_RUNNING;
|
||||
@ -376,6 +415,20 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
|
||||
// Go on!
|
||||
this->state = STATE_DUMP_PARTITION_CONTENTS;
|
||||
return ApplicationState::SUBSTATE_RUNNING;
|
||||
} else if (this->state == STATE_ABORT_CONFIRMATION) {
|
||||
if (buttonPressed(input, Input::BUTTON_B)) {
|
||||
this->state = STATE_DUMP_PARTITION_CONTENTS;
|
||||
return ApplicationState::SUBSTATE_RUNNING;
|
||||
}
|
||||
proccessMenuNavigationX(input, 2);
|
||||
if (buttonPressed(input, Input::BUTTON_A)) {
|
||||
if (selectedOptionX == 0) {
|
||||
this->state = STATE_DUMP_PARTITION_CONTENTS;
|
||||
return ApplicationState::SUBSTATE_RUNNING;
|
||||
} else {
|
||||
return ApplicationState::SUBSTATE_RETURN;
|
||||
}
|
||||
}
|
||||
} else if (state == STATE_DUMP_DONE) {
|
||||
if (entrySelected(input)) {
|
||||
return ApplicationState::SUBSTATE_RETURN;
|
||||
|
@ -48,7 +48,8 @@ public:
|
||||
STATE_DUMP_PARTITION_TICKET,
|
||||
STATE_DUMP_PARTITION_CERT,
|
||||
STATE_DUMP_PARTITION_CONTENTS,
|
||||
STATE_DUMP_DONE
|
||||
STATE_DUMP_DONE,
|
||||
STATE_ABORT_CONFIRMATION
|
||||
};
|
||||
|
||||
enum eErrorState {
|
||||
@ -92,8 +93,8 @@ public:
|
||||
int32_t oddFd = -1;
|
||||
void *sectorBuf = nullptr;
|
||||
uint32_t sectorBufSize;
|
||||
std::shared_ptr<DiscReaderDiscDrive> discReader = nullptr;
|
||||
std::unique_ptr<WiiUDiscHeader> discHeader = nullptr;
|
||||
std::shared_ptr<DiscReader> discReader;
|
||||
std::unique_ptr<WiiUDiscHeader> discHeader;
|
||||
|
||||
std::shared_ptr<WiiUGMPartition> curPartition = nullptr;
|
||||
std::shared_ptr<NUSDataProvider> dataProvider = nullptr;
|
||||
|
@ -16,24 +16,27 @@
|
||||
****************************************************************************/
|
||||
#include "DefaultNUSDataProcessor.h"
|
||||
|
||||
|
||||
bool DefaultNUSDataProcessor::readPlainDecryptedContent(const std::shared_ptr<Content> &pContent, std::vector<uint8_t> &out_data) {
|
||||
if ((pContent->type & 0x0002) == 0x0002) {
|
||||
DEBUG_FUNCTION_LINE("Hashed content not supported yet");
|
||||
DEBUG_FUNCTION_LINE_ERR("Hashed content not supported yet");
|
||||
return false;
|
||||
}
|
||||
auto contentSize = ROUNDUP(pContent->encryptedFileSize, 16);
|
||||
out_data.resize(contentSize);
|
||||
|
||||
auto *inData = (uint8_t *) malloc(contentSize);
|
||||
if (inData == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Failed to alloc");
|
||||
if (contentSize > UINT32_MAX) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Content is too big to read");
|
||||
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;
|
||||
}
|
||||
|
||||
if (!dataProvider->readRawContent(pContent, inData, 0, contentSize)) {
|
||||
DEBUG_FUNCTION_LINE("Failed tor read content");
|
||||
free(inData);
|
||||
if (!dataProvider->readRawContent(pContent, inData.get(), 0, contentSize)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed tor read content");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -42,12 +45,11 @@ bool DefaultNUSDataProcessor::readPlainDecryptedContent(const std::shared_ptr<Co
|
||||
uint16_t content_index = pContent->index;
|
||||
memcpy(IV.data(), &content_index, 2);
|
||||
|
||||
nusDecryption->decryptData(IV, inData, out_data.data(), contentSize);
|
||||
free(inData);
|
||||
nusDecryption->decryptData(IV, inData.get(), out_data.data(), contentSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<NUSDataProvider> DefaultNUSDataProcessor::getDataProvider() {
|
||||
std::shared_ptr<NUSDataProvider> &DefaultNUSDataProcessor::getDataProvider() {
|
||||
return dataProvider;
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ public:
|
||||
|
||||
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:
|
||||
std::shared_ptr<NUSDataProvider> dataProvider;
|
||||
|
@ -15,21 +15,21 @@
|
||||
* 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 <common/common.h>
|
||||
#include <coreinit/debug.h>
|
||||
#include <utils/rijndael.h>
|
||||
|
||||
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;
|
||||
|
||||
auto *encryptedBuffer = (uint8_t *) malloc(CHUNK_SIZE);
|
||||
auto encryptedBuffer = (uint8_t *) memalign(0x40, CHUNK_SIZE);
|
||||
|
||||
if (encryptedBuffer == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Failed to alloc buffer");
|
||||
if (!encryptedBuffer) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -41,8 +41,8 @@ bool DiscReader::readDecryptedChunk(uint64_t readOffset, uint8_t *out_buffer, ui
|
||||
memcpy(IV, &encryptedBuffer[CHUNK_SIZE - 16], 16);
|
||||
result = true;
|
||||
}
|
||||
|
||||
free(encryptedBuffer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -61,8 +61,9 @@ bool DiscReader::readDecrypted(uint8_t *out_buffer, uint64_t clusterOffset, uint
|
||||
|
||||
uint32_t usedSize = size;
|
||||
uint64_t usedFileOffset = fileOffset;
|
||||
auto *buffer = (uint8_t *) malloc(BLOCK_SIZE);
|
||||
if (buffer == nullptr) {
|
||||
auto buffer = make_unique_nothrow<uint8_t[]>((size_t) BLOCK_SIZE);
|
||||
if (!buffer) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -77,8 +78,8 @@ bool DiscReader::readDecrypted(uint8_t *out_buffer, uint64_t clusterOffset, uint
|
||||
|
||||
do {
|
||||
uint64_t totalOffset = (clusterOffset + usedFileOffset);
|
||||
uint64_t blockNumber = (totalOffset / BLOCK_SIZE);
|
||||
uint64_t blockOffset = (totalOffset % BLOCK_SIZE);
|
||||
uint32_t blockNumber = (totalOffset / BLOCK_SIZE);
|
||||
uint32_t blockOffset = (totalOffset % BLOCK_SIZE);
|
||||
|
||||
readOffset = (blockNumber * BLOCK_SIZE);
|
||||
if (!useFixedIV) {
|
||||
@ -87,14 +88,14 @@ bool DiscReader::readDecrypted(uint8_t *out_buffer, uint64_t clusterOffset, uint
|
||||
memcpy(usedIV + 8, &ivTemp, 8);
|
||||
}
|
||||
|
||||
if (!readDecryptedChunk(readOffset, buffer, key, usedIV)) {
|
||||
if (!readDecryptedChunk(readOffset, buffer.get(), key, usedIV)) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
maxCopySize = BLOCK_SIZE - blockOffset;
|
||||
copySize = (usedSize > maxCopySize) ? maxCopySize : usedSize;
|
||||
|
||||
memcpy(out_buffer + totalread, buffer + blockOffset, copySize);
|
||||
memcpy(out_buffer + totalread, buffer.get() + blockOffset, copySize);
|
||||
|
||||
totalread += copySize;
|
||||
|
||||
@ -103,22 +104,21 @@ bool DiscReader::readDecrypted(uint8_t *out_buffer, uint64_t clusterOffset, uint
|
||||
usedFileOffset += copySize;
|
||||
} while (totalread < size);
|
||||
|
||||
free(buffer);
|
||||
|
||||
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;
|
||||
if (full_block_count > 0) {
|
||||
if (!readEncryptedSector(buf, full_block_count, offset_in_sector)) {
|
||||
if (!readEncryptedSector(buf, full_block_count, block_offset)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto remainingSize = size - (full_block_count * SECTOR_SIZE);
|
||||
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)) {
|
||||
return false;
|
||||
}
|
||||
@ -136,40 +136,48 @@ bool DiscReader::readEncrypted(uint8_t *buf, uint64_t offset, uint32_t size) {
|
||||
auto curOffset = offset;
|
||||
uint32_t offsetInBuf = 0;
|
||||
uint32_t totalRead = 0;
|
||||
|
||||
if (missingFromPrevSector > 0) {
|
||||
std::lock_guard<std::mutex> lock(sector_buf_mutex);
|
||||
auto offset_in_sectors = offset / SECTOR_SIZE;
|
||||
|
||||
if (!readEncryptedSector(sector_buf, 1, offset_in_sectors)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t toCopy = SECTOR_SIZE - missingFromPrevSector;
|
||||
if (toCopy > size) {
|
||||
toCopy = size;
|
||||
}
|
||||
memcpy(buf, sector_buf + missingFromPrevSector, toCopy);
|
||||
totalRead += toCopy;
|
||||
curOffset += missingFromPrevSector;
|
||||
offsetInBuf += missingFromPrevSector;
|
||||
curOffset += toCopy;
|
||||
offsetInBuf += toCopy;
|
||||
}
|
||||
|
||||
if (totalRead >= size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (curOffset % SECTOR_SIZE == 0) {
|
||||
if (!readEncryptedAligned(buf + offsetInBuf, offset / SECTOR_SIZE, size)) {
|
||||
if (!readEncryptedAligned(buf + offsetInBuf, curOffset / SECTOR_SIZE, size)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
OSFatal("Failed to read encrypted");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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() {
|
||||
free(this->sector_buf);
|
||||
this->sector_buf = nullptr;
|
||||
}
|
||||
|
@ -17,6 +17,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
class DiscReader {
|
||||
public:
|
||||
@ -26,9 +28,9 @@ public:
|
||||
|
||||
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;
|
||||
|
||||
@ -40,5 +42,6 @@ public:
|
||||
bool hasDiscKey = false;
|
||||
|
||||
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/>.
|
||||
****************************************************************************/
|
||||
#include "DiscReaderDiscDrive.h"
|
||||
#include <MainApplicationState.h>
|
||||
#include "utils/utils.h"
|
||||
#include <WUD/content/WiiUDiscContentsHeader.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/rijndael.h>
|
||||
|
||||
|
||||
DiscReaderDiscDrive::DiscReaderDiscDrive() : DiscReader() {
|
||||
auto *sector_buf = (uint8_t *) malloc(READ_SECTOR_SIZE);
|
||||
if (sector_buf == nullptr) {
|
||||
auto sector_buf = (uint8_t *) memalign(0x40, (size_t) READ_SECTOR_SIZE);
|
||||
if (!sector_buf) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate buffer");
|
||||
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) {
|
||||
free(sector_buf);
|
||||
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 (((uint32_t *) sector_buf)[0] != WiiUDiscContentsHeader::MAGIC) {
|
||||
uint8_t iv[16];
|
||||
memset(iv, 0, 16);
|
||||
|
||||
auto discKeyRes = IOSUHAX_ODM_GetDiscKey(discKey);
|
||||
if (discKeyRes >= 0) {
|
||||
hasDiscKey = true;
|
||||
auto sector_buf_decrypted = (uint8_t *) malloc(READ_SECTOR_SIZE);
|
||||
if (sector_buf_decrypted != nullptr) {
|
||||
aes_set_key((uint8_t *) discKey);
|
||||
aes_decrypt((uint8_t *) iv, (uint8_t *) sector_buf, (uint8_t *) §or_buf_decrypted[0], READ_SECTOR_SIZE);
|
||||
if (((uint32_t *) sector_buf_decrypted)[0] == WiiUDiscContentsHeader::MAGIC) {
|
||||
DEBUG_FUNCTION_LINE("Key was correct");
|
||||
this->init_done = true;
|
||||
}
|
||||
free(sector_buf_decrypted);
|
||||
WUDDiscKey discKeyLocal;
|
||||
|
||||
auto discKeyRes = Mocha_ODMGetDiscKey(&discKeyLocal);
|
||||
if (discKeyRes == MOCHA_RESULT_SUCCESS) {
|
||||
hasDiscKey = true;
|
||||
memcpy(this->discKey, discKeyLocal.key, 16);
|
||||
auto sector_buf_decrypted = make_unique_nothrow<uint8_t[]>((size_t) READ_SECTOR_SIZE);
|
||||
if (!sector_buf_decrypted) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory");
|
||||
free(sector_buf);
|
||||
return;
|
||||
}
|
||||
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 {
|
||||
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 {
|
||||
if (IOSUHAX_FSA_RawRead(gFSAfd, buffer, READ_SECTOR_SIZE, block_cnt, offset_in_sectors, device_handle) < 0) {
|
||||
DEBUG_FUNCTION_LINE("Failed to read from Disc");
|
||||
bool DiscReaderDiscDrive::readEncryptedSector(uint8_t *buffer, uint32_t block_cnt, uint32_t block_offset) const {
|
||||
if (FSAEx_RawRead(__wut_devoptab_fs_client, buffer, READ_SECTOR_SIZE, block_cnt, block_offset, device_handle) < 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -76,7 +87,8 @@ bool DiscReaderDiscDrive::IsReady() {
|
||||
|
||||
DiscReaderDiscDrive::~DiscReaderDiscDrive() {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
uint32_t block_cnt = size >> 15;
|
||||
uint32_t offset_in_sectors = offset >> 15;
|
||||
if (IOSUHAX_FSA_RawRead(gFSAfd, buf, 0x8000, block_cnt, offset_in_sectors, device_handle) < 0) {
|
||||
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");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<DiscReaderDiscDrive *> DiscReaderDiscDrive::Create() {
|
||||
auto discReader = new DiscReaderDiscDrive();
|
||||
if (!discReader->IsReady()) {
|
||||
delete discReader;
|
||||
std::optional<std::unique_ptr<DiscReaderDiscDrive>> DiscReaderDiscDrive::make_unique() {
|
||||
auto discReader = make_unique_nothrow<DiscReaderDiscDrive>();
|
||||
if (!discReader || !discReader->IsReady()) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to init DiscReader %d %d", !discReader, discReader->IsReady());
|
||||
return {};
|
||||
}
|
||||
return discReader;
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include "DiscReader.h"
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
class DiscReaderDiscDrive : public DiscReader {
|
||||
@ -26,15 +27,14 @@ public:
|
||||
|
||||
~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 IsReady() override;
|
||||
bool readEncryptedSector(uint8_t *buffer, uint32_t block_cnt, uint32_t block_offset) const override;
|
||||
|
||||
bool readEncrypted(uint8_t *buf, uint64_t offset, uint32_t size) override;
|
||||
|
||||
private:
|
||||
bool IsReady() override;
|
||||
bool init_done = false;
|
||||
int32_t device_handle = -1;
|
||||
};
|
@ -10,7 +10,7 @@ protected:
|
||||
public:
|
||||
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;
|
||||
};
|
@ -15,33 +15,44 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#include "NUSDataProviderWUD.h"
|
||||
#include "utils/WUDUtils.h"
|
||||
|
||||
NUSDataProviderWUD::NUSDataProviderWUD(const std::shared_ptr<WiiUGMPartition> &pGamePartition, const std::shared_ptr<DiscReader> &pDiscReader) {
|
||||
gamePartition = pGamePartition;
|
||||
discReader = pDiscReader;
|
||||
NUSDataProviderWUD::NUSDataProviderWUD(std::shared_ptr<WiiUGMPartition> pGamePartition, std::shared_ptr<DiscReader> pDiscReader) {
|
||||
gamePartition = std::move(pGamePartition);
|
||||
discReader = std::move(pDiscReader);
|
||||
}
|
||||
|
||||
NUSDataProviderWUD::~NUSDataProviderWUD() = default;
|
||||
|
||||
bool NUSDataProviderWUD::readRawContent(const std::shared_ptr<Content> &content, uint8_t *buffer, uint64_t offset, uint32_t size) {
|
||||
if (buffer == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("buffer was NULL");
|
||||
return false;
|
||||
}
|
||||
auto offsetInWUDOpt = getOffsetInWUD(content);
|
||||
if (!offsetInWUDOpt.has_value()) {
|
||||
if (!discReader) {
|
||||
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;
|
||||
}
|
||||
auto offsetInWUD = offsetInWUDOpt.value() + offset;
|
||||
if (!discReader) {
|
||||
return false;
|
||||
}
|
||||
return discReader->readEncrypted(buffer, offsetInWUD, size);
|
||||
}
|
||||
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
out_data.resize(cur->size);
|
||||
memcpy(out_data.data(), cur->data, cur->size);
|
||||
memcpy(out_data.data(), cur->data.get(), cur->size);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -56,29 +67,16 @@ void NUSDataProviderWUD::setFST(const std::shared_ptr<FST> &pFST) {
|
||||
}
|
||||
|
||||
bool NUSDataProviderWUD::getRawCert(std::vector<uint8_t> &out_data) {
|
||||
out_data = gamePartition->rawCert;
|
||||
out_data = gamePartition->getRawCert();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NUSDataProviderWUD::getRawTicket(std::vector<uint8_t> &out_data) {
|
||||
out_data = gamePartition->rawTicket;
|
||||
out_data = gamePartition->getRawTicket();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NUSDataProviderWUD::getRawTMD(std::vector<uint8_t> &out_data) {
|
||||
out_data = gamePartition->rawTMD;
|
||||
out_data = gamePartition->getRawTMD();
|
||||
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 {
|
||||
|
||||
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;
|
||||
|
||||
@ -44,7 +44,4 @@ public:
|
||||
std::shared_ptr<FST> fst;
|
||||
std::shared_ptr<WiiUGMPartition> gamePartition;
|
||||
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);
|
||||
}
|
||||
|
||||
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 {
|
||||
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;
|
||||
|
||||
std::shared_ptr<Ticket> ticket;
|
||||
std::unique_ptr<Ticket> ticket;
|
||||
};
|
||||
|
@ -16,66 +16,77 @@
|
||||
****************************************************************************/
|
||||
#include "NUSTitle.h"
|
||||
|
||||
#include <memory>
|
||||
#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;
|
||||
if (!dataProvider->getRawTMD(dataBuffer)) {
|
||||
DEBUG_FUNCTION_LINE("Failed to read TMD");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to read TMD");
|
||||
return {};
|
||||
}
|
||||
|
||||
auto tmdOpt = TitleMetaData::make_shared(dataBuffer);
|
||||
auto tmdOpt = TitleMetaData::make_unique(dataBuffer);
|
||||
if (!tmdOpt.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to parse TMD");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to parse TMD");
|
||||
return {};
|
||||
}
|
||||
dataBuffer.clear();
|
||||
|
||||
if (!dataProvider->getRawTicket(dataBuffer)) {
|
||||
DEBUG_FUNCTION_LINE("Failed to read ticket data");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to read ticket data");
|
||||
return {};
|
||||
}
|
||||
|
||||
auto ticketOpt = Ticket::make_shared(dataBuffer, commonKey);
|
||||
auto ticketOpt = Ticket::make_unique(dataBuffer, commonKey);
|
||||
if (!ticketOpt.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to parse ticket");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to parse ticket");
|
||||
return {};
|
||||
}
|
||||
|
||||
dataBuffer.clear();
|
||||
|
||||
std::shared_ptr<NUSDataProvider> dataProviderShared = std::move(dataProvider);
|
||||
|
||||
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.
|
||||
auto fstContentOpt = tmdOpt.value()->getContentByIndex(0);
|
||||
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 {};
|
||||
}
|
||||
|
||||
if (!dpp->readPlainDecryptedContent(fstContentOpt.value(), dataBuffer)) {
|
||||
DEBUG_FUNCTION_LINE("Failed to read decrypted content");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to read decrypted content");
|
||||
return {};
|
||||
}
|
||||
auto fstOpt = FST::make_shared(dataBuffer, 0, VolumeBlockSize(1));
|
||||
|
||||
if (!fstOpt.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to parse FST");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to parse FST");
|
||||
return {};
|
||||
}
|
||||
|
||||
// The dataprovider may need the FST to calculate the offset of a content
|
||||
// on the partition.
|
||||
dataProvider->setFST(fstOpt.value());
|
||||
return std::shared_ptr<NUSTitle>(new NUSTitle(tmdOpt.value(), dpp, dataProvider, decryption, ticketOpt.value(), fstOpt.value()));
|
||||
dataProviderShared->setFST(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,
|
||||
std::shared_ptr<NUSDataProcessor> pProcessor,
|
||||
NUSTitle::NUSTitle(std::unique_ptr<TitleMetaData> pTMD,
|
||||
std::unique_ptr<NUSDataProcessor> pProcessor,
|
||||
std::shared_ptr<NUSDataProvider> pDataProvider,
|
||||
std::shared_ptr<NUSDecryption> pDecryption,
|
||||
std::shared_ptr<Ticket> pTicket,
|
||||
std::unique_ptr<Ticket> pTicket,
|
||||
std::shared_ptr<FST> pFST) :
|
||||
|
||||
dataProcessor(std::move(pProcessor)),
|
||||
@ -86,9 +97,50 @@ NUSTitle::NUSTitle(std::shared_ptr<TitleMetaData> pTMD,
|
||||
dataProvider(std::move(pDataProvider)) {
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<NUSTitle>>
|
||||
NUSTitle::loadTitleFromGMPartition(const std::shared_ptr<WiiUGMPartition> &pPartition, const std::shared_ptr<DiscReader> &pDrive, const std::array<uint8_t, 16> &commonKey) {
|
||||
return loadTitle(std::shared_ptr<NUSDataProvider>(new NUSDataProviderWUD(pPartition, pDrive)), commonKey);
|
||||
std::optional<std::unique_ptr<NUSTitle>>
|
||||
NUSTitle::loadTitleFromGMPartition(std::shared_ptr<WiiUGMPartition> pPartition, std::shared_ptr<DiscReader> pDiscReader, const std::array<uint8_t, 16> &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;
|
||||
|
@ -22,34 +22,43 @@
|
||||
#include "NUSDataProviderWUD.h"
|
||||
#include "NUSDecryption.h"
|
||||
#include "Ticket.h"
|
||||
#include "utils/StringTools.h"
|
||||
#include <WUD/NUSDataProvider.h>
|
||||
#include <WUD/content/partitions/WiiUGMPartition.h>
|
||||
#include <WUD/entities/TMD/TitleMetaData.h>
|
||||
#include <nn/acp/title.h>
|
||||
|
||||
class NUSTitle {
|
||||
|
||||
public:
|
||||
~NUSTitle();
|
||||
|
||||
std::shared_ptr<NUSDataProcessor> dataProcessor;
|
||||
std::shared_ptr<TitleMetaData> tmd;
|
||||
std::shared_ptr<Ticket> ticket;
|
||||
std::unique_ptr<NUSDataProcessor> dataProcessor;
|
||||
std::unique_ptr<TitleMetaData> tmd;
|
||||
std::unique_ptr<Ticket> ticket;
|
||||
std::shared_ptr<FST> fst;
|
||||
std::shared_ptr<NUSDecryption> decryption;
|
||||
std::shared_ptr<NUSDataProvider> dataProvider;
|
||||
|
||||
static std::optional<std::shared_ptr<NUSTitle>> loadTitleFromGMPartition(
|
||||
const std::shared_ptr<WiiUGMPartition> &pPartition,
|
||||
const std::shared_ptr<DiscReader> &pDrive,
|
||||
static std::optional<std::unique_ptr<NUSTitle>> loadTitleFromGMPartition(
|
||||
std::shared_ptr<WiiUGMPartition> pPartition,
|
||||
std::shared_ptr<DiscReader> pDiscReader,
|
||||
const std::array<uint8_t, 16> &commonKey);
|
||||
|
||||
private:
|
||||
static std::optional<std::shared_ptr<NUSTitle>> loadTitle(const std::shared_ptr<NUSDataProvider> &dataProvider, const std::array<uint8_t, 16> &commonKey);
|
||||
std::string getLongnameEn();
|
||||
|
||||
NUSTitle(std::shared_ptr<TitleMetaData> pTMD,
|
||||
std::shared_ptr<NUSDataProcessor> pProcessor,
|
||||
std::string getShortnameEn();
|
||||
|
||||
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<NUSDecryption> pDecryption,
|
||||
std::shared_ptr<Ticket> pTicket,
|
||||
std::unique_ptr<Ticket> pTicket,
|
||||
std::shared_ptr<FST> pFST);
|
||||
};
|
@ -22,9 +22,9 @@ Ticket::Ticket(const std::array<uint8_t, 16> &pEncryptedKey, const std::array<ui
|
||||
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) {
|
||||
DEBUG_FUNCTION_LINE("Not enough data to parse a ticket");
|
||||
DEBUG_FUNCTION_LINE_ERR("Not enough data to parse a ticket");
|
||||
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_decrypt(IV, encryptedKey.data(), decryptedKey.data(), 16);
|
||||
}
|
||||
|
||||
return std::shared_ptr<Ticket>(new Ticket(encryptedKey, decryptedKey));
|
||||
auto ticket = new (std::nothrow) 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> 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:
|
||||
Ticket(const std::array<uint8_t, 16> &encryptedKey, const std::array<uint8_t, 16> &decryptedKey);
|
||||
|
@ -19,24 +19,24 @@
|
||||
|
||||
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;
|
||||
auto discContentHeaderOpt = WiiUDiscContentsHeader::make_unique(discReader, curOffset);
|
||||
if (!discContentHeaderOpt.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to read WiiUDiscContentsHeader");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to read WiiUDiscContentsHeader");
|
||||
return {};
|
||||
}
|
||||
curOffset += WiiUDiscContentsHeader::LENGTH;
|
||||
|
||||
auto partitionsOpt = WiiUPartitions::make_unique(discReader, curOffset, discContentHeaderOpt.value()->numberOfPartition, discContentHeaderOpt.value()->blockSize);
|
||||
if (!partitionsOpt.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to read Partitions");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to read Partitions");
|
||||
return {};
|
||||
}
|
||||
curOffset += WiiUPartitions::LENGTH;
|
||||
|
||||
if (curOffset - offset != LENGTH) {
|
||||
DEBUG_FUNCTION_LINE("Unexpected offset");
|
||||
DEBUG_FUNCTION_LINE_ERR("Unexpected offset");
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -45,9 +45,7 @@ std::optional<std::unique_ptr<WiiUContentsInformation>> WiiUContentsInformation:
|
||||
std::move(partitionsOpt.value())));
|
||||
}
|
||||
|
||||
|
||||
WiiUContentsInformation::WiiUContentsInformation(std::unique_ptr<WiiUDiscContentsHeader> 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 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:
|
||||
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/>.
|
||||
****************************************************************************/
|
||||
#include "WiiUDiscContentsHeader.h"
|
||||
#include "utils/utils.h"
|
||||
#include <coreinit/debug.h>
|
||||
#include <utils/blocksize/DiscBlockSize.h>
|
||||
|
||||
std::optional<std::unique_ptr<WiiUDiscContentsHeader>> WiiUDiscContentsHeader::make_unique(const std::shared_ptr<DiscReader> &discReader, uint32_t offset) {
|
||||
auto *buffer = (uint8_t *) malloc(LENGTH);
|
||||
std::optional<std::unique_ptr<WiiUDiscContentsHeader>> WiiUDiscContentsHeader::make_unique(std::shared_ptr<DiscReader> &discReader, uint32_t offset) {
|
||||
auto buffer = make_unique_nothrow<uint8_t[]>(LENGTH);
|
||||
if (!buffer) {
|
||||
DEBUG_FUNCTION_LINE("Failed to alloc buffer");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc buffer");
|
||||
return {};
|
||||
}
|
||||
if (!discReader->hasDiscKey) {
|
||||
if (!discReader->readEncrypted(buffer, offset, LENGTH)) {
|
||||
DEBUG_FUNCTION_LINE("Failed to read data");
|
||||
DEBUG_FUNCTION_LINE_ERR();
|
||||
if (!discReader->readEncrypted(buffer.get(), offset, LENGTH)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to read data");
|
||||
return {};
|
||||
}
|
||||
} else {
|
||||
if (!discReader->readDecrypted(buffer, offset, 0, LENGTH, discReader->discKey, nullptr, true)) {
|
||||
DEBUG_FUNCTION_LINE("Failed to read data");
|
||||
if (!discReader->readDecrypted(buffer.get(), offset, 0, LENGTH, discReader->discKey, nullptr, true)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to read data");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
if (((uint32_t *) buffer)[0] != MAGIC) {
|
||||
DEBUG_FUNCTION_LINE("MAGIC mismatch");
|
||||
if (((uint32_t *) buffer.get())[0] != MAGIC) {
|
||||
DEBUG_FUNCTION_LINE_ERR("MAGIC mismatch");
|
||||
return {};
|
||||
}
|
||||
auto blockSize = DiscBlockSize(((uint32_t *) buffer)[1]);
|
||||
auto blockSize = DiscBlockSize(((uint32_t *) buffer.get())[1]);
|
||||
std::array<uint8_t, 20> tocHash{};
|
||||
memcpy(tocHash.data(), &buffer[8], 20);
|
||||
auto numberOfPartition = ((uint32_t *) buffer)[7];
|
||||
free(buffer);
|
||||
auto numberOfPartition = ((uint32_t *) buffer.get())[7];
|
||||
|
||||
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 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:
|
||||
WiiUDiscContentsHeader(DiscBlockSize pSize, const std::array<uint8_t, 20> &pTocHash, uint32_t pNumberOfPartitions);
|
||||
|
@ -26,11 +26,11 @@ WiiUDataPartition::WiiUDataPartition(
|
||||
basePartition(std::move(pPartition)) {
|
||||
}
|
||||
|
||||
std::string WiiUDataPartition::getVolumeId() const & {
|
||||
const std::string &WiiUDataPartition::getVolumeId() const {
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -29,17 +29,15 @@ public:
|
||||
|
||||
~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]] uint64_t getSectionOffsetOnDefaultPartition() override;
|
||||
|
||||
std::shared_ptr<FST> fst;
|
||||
|
||||
private:
|
||||
std::shared_ptr<FST> fst;
|
||||
std::shared_ptr<WiiUPartition> basePartition;
|
||||
};
|
||||
|
@ -15,23 +15,27 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#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> pRawTMD,
|
||||
std::vector<uint8_t> pRawCert)
|
||||
std::vector<uint8_t> pRawCert,
|
||||
std::string pathOnSIPartition)
|
||||
: WiiUPartition(),
|
||||
rawTicket(std::move(pRawTicket)),
|
||||
rawTMD(std::move(pRawTMD)),
|
||||
rawCert(std::move(pRawCert)),
|
||||
pathOnSIPartition(std::move(pathOnSIPartition)),
|
||||
basePartition(std::move(partition)) {
|
||||
}
|
||||
|
||||
std::string WiiUGMPartition::getVolumeId() const & {
|
||||
const std::string &WiiUGMPartition::getVolumeId() const {
|
||||
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();
|
||||
}
|
||||
|
||||
@ -41,4 +45,4 @@ uint16_t WiiUGMPartition::getFileSystemDescriptor() const {
|
||||
|
||||
uint64_t WiiUGMPartition::getSectionOffsetOnDefaultPartition() {
|
||||
return basePartition->getSectionOffsetOnDefaultPartition();
|
||||
}
|
||||
}
|
@ -23,23 +23,40 @@
|
||||
|
||||
class WiiUGMPartition : public WiiUPartition {
|
||||
public:
|
||||
WiiUGMPartition(std::shared_ptr<WiiUPartition> partition,
|
||||
WiiUGMPartition(std::unique_ptr<WiiUPartition> partition,
|
||||
std::vector<uint8_t> pRawTicket,
|
||||
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]] 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> rawTMD;
|
||||
std::vector<uint8_t> rawCert;
|
||||
|
||||
private:
|
||||
std::shared_ptr<WiiUPartition> basePartition;
|
||||
std::string pathOnSIPartition;
|
||||
std::unique_ptr<WiiUPartition> basePartition;
|
||||
};
|
||||
|
@ -25,63 +25,61 @@ uint64_t WiiUPartition::getSectionOffsetOnDefaultPartition() {
|
||||
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) {
|
||||
auto buffer = (uint8_t *) malloc(LENGTH);
|
||||
if (buffer == nullptr) {
|
||||
std::optional<std::unique_ptr<WiiUPartition>> WiiUPartition::make_unique(std::shared_ptr<DiscReader> &discReader, uint32_t offset, const DiscBlockSize &blockSize) {
|
||||
// If we have the discKey, the content is encrypted but we don't know the IV.
|
||||
// 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 {};
|
||||
}
|
||||
uint8_t *buffer = bufferReal.get();
|
||||
if (!discReader->hasDiscKey) {
|
||||
if (!discReader->readEncrypted(buffer, offset, LENGTH)) {
|
||||
if (!discReader->readEncrypted(bufferReal.get(), offset, LENGTH)) {
|
||||
return {};
|
||||
}
|
||||
} else {
|
||||
auto bufferBigger = (uint8_t *) malloc(LENGTH + 0x10);
|
||||
if (bufferBigger == nullptr) {
|
||||
if (offset < 0x10) {
|
||||
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 {};
|
||||
}
|
||||
if (!discReader->readDecrypted(bufferBigger, offset - 0x10, 0, LENGTH + 0x10, discReader->discKey, nullptr, true)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
memcpy(buffer, bufferBigger + 0x10, LENGTH);
|
||||
|
||||
free(bufferBigger);
|
||||
buffer = bufferReal.get() + 0x10;
|
||||
}
|
||||
|
||||
char name[32];
|
||||
memset(name, 0, sizeof(name));
|
||||
memcpy(name, buffer, 31);
|
||||
auto volumeId = name;
|
||||
uint8_t num = buffer[31];
|
||||
std::string volumeId = name;
|
||||
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++) {
|
||||
auto address = *((uint32_t *) &buffer[32 + (i * 4)]);
|
||||
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()) {
|
||||
free(buffer);
|
||||
return {};
|
||||
}
|
||||
volumes[discLbaAddress] = vh.value();
|
||||
volumes[discLbaAddress] = std::move(vh.value());
|
||||
}
|
||||
|
||||
auto fileSystemDescriptor = ((uint16_t *) &buffer[64])[0];
|
||||
|
||||
free(buffer);
|
||||
|
||||
return std::unique_ptr<WiiUPartition>(new WiiUPartition(
|
||||
volumeId,
|
||||
volumes,
|
||||
std::move(volumes),
|
||||
fileSystemDescriptor));
|
||||
}
|
||||
|
||||
std::string WiiUPartition::getVolumeId() const & {
|
||||
const std::string &WiiUPartition::getVolumeId() const {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,6 @@
|
||||
|
||||
#include "volumes/VolumeHeader.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <utils/blocksize/AddressInDiscBlocks.h>
|
||||
#include <utils/blocksize/DiscBlockSize.h>
|
||||
@ -32,23 +31,23 @@ public:
|
||||
|
||||
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;
|
||||
|
||||
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:
|
||||
WiiUPartition() = default;
|
||||
|
||||
private:
|
||||
WiiUPartition(char *pVolumeId, std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> pVolumes, uint16_t pFileSystemDescriptor)
|
||||
: volumeId(pVolumeId), volumes(std::move(pVolumes)), fileSystemDescriptor(pFileSystemDescriptor) {
|
||||
WiiUPartition(std::string pVolumeId, std::map<AddressInDiscBlocks, std::unique_ptr<VolumeHeader>> pVolumes, uint16_t pFileSystemDescriptor)
|
||||
: volumeId(std::move(pVolumeId)), volumes(std::move(pVolumes)), fileSystemDescriptor(pFileSystemDescriptor) {
|
||||
}
|
||||
|
||||
std::string volumeId;
|
||||
std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> volumes;
|
||||
const std::string volumeId;
|
||||
std::map<AddressInDiscBlocks, std::unique_ptr<VolumeHeader>> volumes;
|
||||
uint16_t fileSystemDescriptor{};
|
||||
};
|
@ -14,18 +14,18 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#include <coreinit/debug.h>
|
||||
#include <utils/FSTUtils.h>
|
||||
|
||||
#include "WiiUPartitions.h"
|
||||
#include "WiiUDataPartition.h"
|
||||
#include "WiiUGMPartition.h"
|
||||
#include "WiiUPartitions.h"
|
||||
#include <algorithm>
|
||||
#include <coreinit/debug.h>
|
||||
#include <utility>
|
||||
#include <utils/FSTUtils.h>
|
||||
|
||||
bool WiiUPartitions::getFSTEntryAsByte(std::string &filePath,
|
||||
const std::shared_ptr<FST> &fst,
|
||||
const AddressInDiscBlocks &volumeAddress,
|
||||
const std::shared_ptr<DiscReader> &discReader,
|
||||
std::shared_ptr<DiscReader> &discReader,
|
||||
std::vector<uint8_t> &out_data) {
|
||||
auto entryOpt = FSTUtils::getFSTEntryByFullPath(fst->getRootEntry(), filePath);
|
||||
if (!entryOpt.has_value()) {
|
||||
@ -56,136 +56,148 @@ bool WiiUPartitions::getFSTEntryAsByte(std::string &filePath,
|
||||
}
|
||||
|
||||
std::optional<std::unique_ptr<WiiUPartitions>>
|
||||
WiiUPartitions::make_unique(const std::shared_ptr<DiscReader> &discReader, uint32_t offset, uint32_t numberOfPartitions, const DiscBlockSize &blockSize) {
|
||||
std::vector<std::shared_ptr<WiiUPartition>> tmp;
|
||||
std::vector<std::shared_ptr<WiiUPartition>> partitions;
|
||||
partitions.reserve(numberOfPartitions);
|
||||
WiiUPartitions::make_unique(std::shared_ptr<DiscReader> &discReader, uint32_t offset, uint32_t numberOfPartitions, const DiscBlockSize &blockSize) {
|
||||
std::vector<std::unique_ptr<WiiUPartition>> tmp;
|
||||
std::vector<std::shared_ptr<WiiUPartition>> result;
|
||||
result.reserve(numberOfPartitions);
|
||||
tmp.reserve(numberOfPartitions);
|
||||
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()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to read partition");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to read partition");
|
||||
return {};
|
||||
}
|
||||
tmp.push_back(partitionOpt.value());
|
||||
}
|
||||
std::optional<std::shared_ptr<WiiUPartition>> SIPartition;
|
||||
for (auto &partition : tmp) {
|
||||
if (partition->getVolumeId().starts_with("SI")) {
|
||||
SIPartition = partition;
|
||||
break;
|
||||
}
|
||||
tmp.push_back(std::move(partitionOpt.value()));
|
||||
}
|
||||
|
||||
if (SIPartition.has_value()) {
|
||||
for (auto const &[key, val] : SIPartition.value()->getVolumes()) {
|
||||
auto volumeAddress = key;
|
||||
auto volumeAddressInBytes = volumeAddress.getAddressInBytes();
|
||||
auto volumeHeader = val;
|
||||
auto SIPartitionOpt = movePartitionFromList(tmp, "SI");
|
||||
|
||||
std::vector<uint8_t> fstData;
|
||||
fstData.resize(volumeHeader->FSTSize);
|
||||
if (!SIPartitionOpt) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to find SI partition");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!discReader->hasDiscKey) {
|
||||
if (!discReader->readEncrypted(fstData.data(), volumeAddressInBytes + volumeHeader->FSTAddress.getAddressInBytes(),
|
||||
volumeHeader->FSTSize)) {
|
||||
DEBUG_FUNCTION_LINE("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("Failed to read FST");
|
||||
return {};
|
||||
}
|
||||
auto SIPartition = std::move(SIPartitionOpt.value());
|
||||
|
||||
for (auto const &[key, val] : SIPartition->getVolumes()) {
|
||||
auto volumeAddress = key;
|
||||
auto volumeAddressInBytes = volumeAddress.getAddressInBytes();
|
||||
auto &volumeHeader = val;
|
||||
|
||||
std::vector<uint8_t> fstData;
|
||||
fstData.resize(volumeHeader->FSTSize);
|
||||
|
||||
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);
|
||||
if (!siFST.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to parse FST");
|
||||
auto siFST = FST::make_shared(fstData, 0, volumeHeader->blockSize);
|
||||
if (!siFST.has_value()) {
|
||||
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 {};
|
||||
}
|
||||
|
||||
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("Failted to read FSTEntry");
|
||||
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> bufferTMD;
|
||||
std::string tmdFilePath = std::string(child->getFullPath() + '/' + WUD_TMD_FILENAME);
|
||||
if (!getFSTEntryAsByte(tmdFilePath, siFST.value(), volumeAddress, discReader, bufferTMD)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed 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_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")) {
|
||||
continue;
|
||||
}
|
||||
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 vh = partition->getVolumes().begin()->second;
|
||||
auto &volumeAddress = partition->getVolumes().begin()->first;
|
||||
auto &vh = partition->getVolumes().begin()->second;
|
||||
|
||||
std::vector<uint8_t> fstData;
|
||||
fstData.resize(vh->FSTSize);
|
||||
|
||||
if (!discReader->hasDiscKey) {
|
||||
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");
|
||||
}
|
||||
} else {
|
||||
if (!discReader->readDecrypted(fstData.data(), volumeAddress.getAddressInBytes() + vh->FSTAddress.getAddressInBytes(), 0, vh->FSTSize,
|
||||
discReader->discKey, nullptr, true)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("WiiUPartition: Failed to read encrypted");
|
||||
OSFatal("WiiUPartition: Failed to read encrypted");
|
||||
}
|
||||
}
|
||||
|
||||
auto fstOpt = FST::make_shared(fstData, 0, vh->blockSize);
|
||||
if (!fstOpt.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to parse FST");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to parse FST");
|
||||
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)) {
|
||||
}
|
||||
|
||||
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,
|
||||
const std::shared_ptr<FST> &fst,
|
||||
const AddressInDiscBlocks &volumeAddress,
|
||||
const std::shared_ptr<DiscReader> &discReader,
|
||||
std::shared_ptr<DiscReader> &discReader,
|
||||
std::vector<uint8_t> &out_data);
|
||||
|
||||
std::vector<std::shared_ptr<WiiUPartition>> partitions;
|
||||
static constexpr uint32_t LENGTH = 30720;
|
||||
|
||||
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 numberOfPartitions,
|
||||
const DiscBlockSize &blockSize);
|
||||
|
||||
private:
|
||||
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/>.
|
||||
****************************************************************************/
|
||||
#include "H3HashArray.h"
|
||||
#include "utils/utils.h"
|
||||
#include <coreinit/debug.h>
|
||||
#include <cstring>
|
||||
|
||||
@ -22,16 +23,12 @@ H3HashArray::H3HashArray(uint8_t *pData, uint32_t pSize) {
|
||||
size = pSize;
|
||||
data = nullptr;
|
||||
if (pSize > 0) {
|
||||
data = (uint8_t *) malloc(pSize);
|
||||
if (data == nullptr) {
|
||||
data = make_unique_nothrow<uint8_t[]>(pSize);
|
||||
if (!data) {
|
||||
OSFatal("H3HashArray: Failed to alloc");
|
||||
}
|
||||
memcpy(data, pData, pSize);
|
||||
memcpy(data.get(), pData, pSize);
|
||||
}
|
||||
}
|
||||
|
||||
H3HashArray::~H3HashArray() {
|
||||
if (data) {
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
H3HashArray::~H3HashArray() = default;
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <malloc.h>
|
||||
#include <memory>
|
||||
|
||||
class H3HashArray {
|
||||
|
||||
@ -26,6 +27,6 @@ public:
|
||||
|
||||
~H3HashArray();
|
||||
|
||||
uint8_t *data = nullptr;
|
||||
std::unique_ptr<uint8_t[]> data;
|
||||
uint8_t size;
|
||||
};
|
||||
|
@ -22,8 +22,8 @@
|
||||
|
||||
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::shared_ptr<H3HashArray>> arrayList;
|
||||
std::vector<std::unique_ptr<H3HashArray>> VolumeHeader::getH3HashArray(uint8_t *h3Data, uint32_t pNumberOfH3HashArray, uint32_t pH3HashArrayListSize) {
|
||||
std::vector<std::unique_ptr<H3HashArray>> arrayList;
|
||||
if (pNumberOfH3HashArray == 0) {
|
||||
return arrayList;
|
||||
}
|
||||
@ -37,30 +37,28 @@ std::vector<std::shared_ptr<H3HashArray>> VolumeHeader::getH3HashArray(uint8_t *
|
||||
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;
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<VolumeHeader>> VolumeHeader::make_shared(const std::shared_ptr<DiscReader> &discReader, uint64_t offset) {
|
||||
auto buffer = (uint8_t *) malloc(64);
|
||||
if (buffer == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Failed to alloc buffer");
|
||||
std::optional<std::unique_ptr<VolumeHeader>> VolumeHeader::make_unique(std::shared_ptr<DiscReader> &discReader, uint64_t offset) {
|
||||
auto buffer = make_unique_nothrow<uint8_t[]>((size_t) 64);
|
||||
if (!buffer) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc buffer");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!discReader->readEncrypted(buffer, offset, 64)) {
|
||||
free(buffer);
|
||||
DEBUG_FUNCTION_LINE("Failed to read data");
|
||||
if (!discReader->readEncrypted(buffer.get(), offset, 64)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to read data");
|
||||
return {};
|
||||
}
|
||||
|
||||
auto *bufferUint = (uint32_t *) buffer;
|
||||
auto *bufferUint = (uint32_t *) buffer.get();
|
||||
|
||||
if (bufferUint[0] != MAGIC) {
|
||||
DEBUG_FUNCTION_LINE("MAGIC mismatch");
|
||||
free(buffer);
|
||||
DEBUG_FUNCTION_LINE_ERR("MAGIC mismatch");
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -76,26 +74,22 @@ std::optional<std::shared_ptr<VolumeHeader>> VolumeHeader::make_shared(const std
|
||||
auto minorVersion = buffer[39];
|
||||
auto expiringMajorVersion = buffer[40];
|
||||
|
||||
free(buffer);
|
||||
|
||||
auto bufferH3 = (uint8_t *) malloc(ROUNDUP(h3HashArrayListSize, 16));
|
||||
if (bufferH3 == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Failed to alloc h3 buffer");
|
||||
auto alignedH3ArrayListSize = ROUNDUP(h3HashArrayListSize, 16);
|
||||
auto bufferH3 = make_unique_nothrow<uint8_t[]>(alignedH3ArrayListSize);
|
||||
if (!bufferH3) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc h3 buffer");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!discReader->readEncrypted(bufferH3, offset + 64, ROUNDUP(h3HashArrayListSize, 16))) {
|
||||
DEBUG_FUNCTION_LINE("Failed to read h3 data");
|
||||
free(bufferH3);
|
||||
if (!discReader->readEncrypted(bufferH3.get(), offset + 64, alignedH3ArrayListSize)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to read h3 data");
|
||||
return {};
|
||||
}
|
||||
|
||||
auto h3HashArrayList = getH3HashArray(bufferH3, numberOfH3HashArray, h3HashArrayListSize);
|
||||
|
||||
free(bufferH3);
|
||||
auto h3HashArrayList = getH3HashArray(bufferH3.get(), numberOfH3HashArray, h3HashArrayListSize);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@ -108,7 +102,7 @@ VolumeHeader::VolumeHeader(const VolumeBlockSize &pBlockSize,
|
||||
uint8_t pMajorVersion,
|
||||
uint8_t pMinorVersion,
|
||||
uint8_t pExpiringMajorVersion,
|
||||
std::vector<std::shared_ptr<H3HashArray>> pH3HashArrayList,
|
||||
std::vector<std::unique_ptr<H3HashArray>> pH3HashArrayList,
|
||||
uint32_t pH3HashArrayListSize,
|
||||
uint32_t pNumberOfH3HashArray) : blockSize(pBlockSize),
|
||||
volumeSize(std::move(pVolumeSize)),
|
||||
|
@ -31,7 +31,7 @@
|
||||
class VolumeHeader {
|
||||
|
||||
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;
|
||||
VolumeBlockSize blockSize;
|
||||
@ -43,12 +43,12 @@ public:
|
||||
uint8_t majorVersion;
|
||||
uint8_t minorVersion;
|
||||
uint8_t expiringMajorVersion;
|
||||
std::vector<std::shared_ptr<H3HashArray>> h3HashArrayList;
|
||||
std::vector<std::unique_ptr<H3HashArray>> h3HashArrayList;
|
||||
|
||||
uint32_t h3HashArrayListSize;
|
||||
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:
|
||||
VolumeHeader(
|
||||
@ -61,7 +61,7 @@ private:
|
||||
uint8_t pMajorVersion,
|
||||
uint8_t pMinorVersion,
|
||||
uint8_t pExpiringMajorVersion,
|
||||
std::vector<std::shared_ptr<H3HashArray>> pH3HashArrayList,
|
||||
std::vector<std::unique_ptr<H3HashArray>> pH3HashArrayList,
|
||||
uint32_t pH3HashArrayListSize,
|
||||
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;
|
||||
|
||||
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 {};
|
||||
}
|
||||
|
||||
@ -34,14 +34,14 @@ std::optional<std::shared_ptr<FST>> FST::make_shared(const std::vector<uint8_t>
|
||||
|
||||
auto headerOpt = FSTHeader::make_unique(fstData);
|
||||
if (!headerOpt.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to parse FSTHeader");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to parse FSTHeader");
|
||||
return {};
|
||||
}
|
||||
curOffset += FSTHeader::LENGTH;
|
||||
|
||||
uint32_t sectionEntriesDataSize = headerOpt.value()->numberOfSections * SectionEntry::LENGTH;
|
||||
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 {};
|
||||
}
|
||||
|
||||
@ -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);
|
||||
if (!sectionEntriesOpt.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to parse FSTHeader");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to parse FSTHeader");
|
||||
return {};
|
||||
}
|
||||
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);
|
||||
if (!stringTableOpt.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to parse StringTable");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to parse StringTable");
|
||||
return {};
|
||||
}
|
||||
|
||||
auto nodeEntriesOpt = NodeEntries::make_unique(data, curOffset, sectionEntriesOpt.value(), stringTableOpt.value(), headerOpt.value()->blockSize);
|
||||
if (!nodeEntriesOpt.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to parse NodeEntries");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to parse NodeEntries");
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
std::optional<std::unique_ptr<FSTHeader>> FSTHeader::make_unique(const std::array<uint8_t, FSTHeader::LENGTH> &data) {
|
||||
auto *dataAsUint = (uint32_t *) data.data();
|
||||
if ((dataAsUint[0] & 0xFFFFFF00) != 0x46535400) {
|
||||
DEBUG_FUNCTION_LINE("FST Header magic was wrong");
|
||||
DEBUG_FUNCTION_LINE_ERR("FST Header magic was wrong");
|
||||
return {};
|
||||
}
|
||||
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 stringNameOpt = stringTable->getStringEntry(param.uint24);
|
||||
if (!stringNameOpt.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to get string name");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to get string name");
|
||||
return {};
|
||||
}
|
||||
|
||||
auto sectionEntryOpt = sectionEntries->getSection(param.sectionNumber);
|
||||
if (!sectionEntryOpt.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to get section entry");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to get section entry");
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -32,13 +32,13 @@ FileEntry::parseData(const std::array<uint8_t, NodeEntry::LENGTH> &data,
|
||||
|
||||
auto stringNameOpt = stringTable->getStringEntry(param.uint24);
|
||||
if (!stringNameOpt.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to get string name");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to get string name");
|
||||
return {};
|
||||
}
|
||||
|
||||
auto sectionEntryOpt = sectionEntries->getSection(param.sectionNumber);
|
||||
if (!sectionEntryOpt.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to get section entry");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to get section entry");
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ std::optional<std::shared_ptr<NodeEntry>> NodeEntries::DeserializeImpl(const std
|
||||
const SectionBlockSize &pBlockSize) {
|
||||
auto nodeEntry = NodeEntry::AutoDeserialize(pData, pOffset, pParent, pEntryNumber, pSectionEntries, pStringTable, pBlockSize);
|
||||
if (!nodeEntry.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to AutoDeserialize NodeEntry");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to AutoDeserialize NodeEntry");
|
||||
return {};
|
||||
}
|
||||
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,
|
||||
asDirEntry, curEntryNumber, pSectionEntries, pStringTable, pBlockSize);
|
||||
if (!entry.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to Deserialize child of NodeEntry");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to Deserialize child of NodeEntry");
|
||||
return {};
|
||||
}
|
||||
asDirEntry->addChild(entry.value());
|
||||
@ -56,14 +56,14 @@ NodeEntries::make_unique(const std::vector<uint8_t> &data, uint32_t offset, cons
|
||||
const SectionBlockSize &blockSize) {
|
||||
auto rootEntry = NodeEntries::DeserializeImpl(data, offset, std::nullopt, 0, pSectionEntries, pStringTable, blockSize);
|
||||
if (!rootEntry.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("DeserializeImpl for root entry has failed");
|
||||
DEBUG_FUNCTION_LINE_ERR("DeserializeImpl for root entry has failed");
|
||||
return {};
|
||||
}
|
||||
auto rootEntryCasted = std::dynamic_pointer_cast<RootEntry>(rootEntry.value());
|
||||
if (rootEntryCasted != nullptr) {
|
||||
return std::unique_ptr<NodeEntries>(new NodeEntries(rootEntryCasted));
|
||||
}
|
||||
DEBUG_FUNCTION_LINE("Failed to parse Root");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to parse Root");
|
||||
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
|
||||
auto res = RootEntry::parseData(curEntryData, param, sectionEntries, stringTable);
|
||||
if (!res.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to parse node");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to parse node");
|
||||
return {};
|
||||
}
|
||||
return res;
|
||||
} else if ((param.type & ENTRY_TYPE_Directory) == ENTRY_TYPE_Directory) {
|
||||
auto res = DirectoryEntry::parseData(curEntryData, param, sectionEntries, stringTable);
|
||||
if (!res.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to parse node");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to parse node");
|
||||
return {};
|
||||
}
|
||||
auto resAsNodeEntry = std::dynamic_pointer_cast<NodeEntry>(res.value());
|
||||
if (resAsNodeEntry == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Failed to cast to NodeEntry");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to cast to NodeEntry");
|
||||
return {};
|
||||
}
|
||||
return resAsNodeEntry;
|
||||
@ -69,18 +69,18 @@ NodeEntry::AutoDeserialize(const std::vector<uint8_t> &data,
|
||||
auto res = FileEntry::parseData(curEntryData, param, sectionEntries, stringTable, blockSize);
|
||||
|
||||
if (!res.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to parse node");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to parse node");
|
||||
return {};
|
||||
}
|
||||
auto resAsNodeEntry = std::dynamic_pointer_cast<NodeEntry>(res.value());
|
||||
if (resAsNodeEntry == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Failed to cast to NodeEntry");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to cast to NodeEntry");
|
||||
return {};
|
||||
}
|
||||
return resAsNodeEntry;
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE("FST Unknown Node Type");
|
||||
DEBUG_FUNCTION_LINE_ERR("FST Unknown Node Type");
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -32,11 +32,11 @@ RootEntry::parseData(const std::array<uint8_t, NodeEntry::LENGTH> &data,
|
||||
auto dir = DirectoryEntry::parseData(data, param, sectionEntries, stringTable);
|
||||
if (dir.has_value()) {
|
||||
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 std::shared_ptr<NodeEntry>(new RootEntry(dir.value()));
|
||||
}
|
||||
DEBUG_FUNCTION_LINE("Failed to parse dir");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to parse dir");
|
||||
return {};
|
||||
}
|
||||
|
@ -37,13 +37,12 @@ std::optional<std::shared_ptr<SectionEntries>> SectionEntries::make_shared(const
|
||||
std::vector<std::shared_ptr<SectionEntry>> list;
|
||||
for (uint32_t i = 0; i < numberOfSections; i++) {
|
||||
if (data.size() < (i + 1) * SectionEntry::LENGTH) {
|
||||
DEBUG_FUNCTION_LINE("Failed to parse SectionEntries");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to parse SectionEntries");
|
||||
return {};
|
||||
}
|
||||
std::array<uint8_t, SectionEntry::LENGTH> sectionEntryData{};
|
||||
memcpy(sectionEntryData.data(), data.data() + (i * SectionEntry::LENGTH), SectionEntry::LENGTH);
|
||||
list.push_back(std::make_shared<SectionEntry>(sectionEntryData, i, pBlockSize));
|
||||
;
|
||||
}
|
||||
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) {
|
||||
if (offset >= data.size()) {
|
||||
DEBUG_FUNCTION_LINE("Invalid offset for reading StringTable");
|
||||
DEBUG_FUNCTION_LINE_ERR("Invalid offset for reading StringTable");
|
||||
return {};
|
||||
}
|
||||
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) {
|
||||
DEBUG_FUNCTION_LINE("stringtable is broken");
|
||||
DEBUG_FUNCTION_LINE_ERR("StringTable is broken");
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -19,9 +19,8 @@
|
||||
#include <utility>
|
||||
#include <utils/logger.h>
|
||||
|
||||
TitleMetaData::TitleMetaData(std::vector<std::shared_ptr<Content>> pContentList) : contentList(std::move(pContentList)) {
|
||||
|
||||
// Get Contents
|
||||
TitleMetaData::TitleMetaData(uint64_t titleId, std::vector<std::shared_ptr<Content>> pContentList) : contentList(std::move(pContentList)) {
|
||||
this->titleId = titleId;
|
||||
}
|
||||
|
||||
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 {};
|
||||
}
|
||||
|
||||
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) {
|
||||
return {};
|
||||
}
|
||||
std::vector<std::shared_ptr<Content>> contentList;
|
||||
auto contentCount = ((uint16_t *) &data[0x1DE])[0];
|
||||
auto titleID = ((uint64_t *) &data[0x18C])[0];
|
||||
for (uint16_t i = 0; i < contentCount; i++) {
|
||||
auto curOffset = 0xB04 + (i * Content::LENGTH);
|
||||
if (data.size() < curOffset + Content::LENGTH) {
|
||||
DEBUG_FUNCTION_LINE("Failed to parse TitleMetaData");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to parse TitleMetaData");
|
||||
return {};
|
||||
}
|
||||
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);
|
||||
if (!curContentOpt.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to parse Content");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to parse Content");
|
||||
return {};
|
||||
}
|
||||
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);
|
||||
|
||||
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:
|
||||
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;
|
||||
|
||||
WiiUDiscHeader::WiiUDiscHeader(std::unique_ptr<WiiUManufactorDiscId> pManufactorDiscId,
|
||||
WiiUDiscHeader::WiiUDiscHeader(std::unique_ptr<WiiUManufacturerDiscId> pManufacturerDiscId,
|
||||
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)),
|
||||
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()) {
|
||||
DEBUG_FUNCTION_LINE("DiscReader is not ready");
|
||||
DEBUG_FUNCTION_LINE_ERR("DiscReader is not ready");
|
||||
return {};
|
||||
}
|
||||
uint32_t offset = 0;
|
||||
uint32_t curOffset = offset;
|
||||
auto manufactorDiscIDOpt = WiiUManufactorDiscId::make_unique(discReader);
|
||||
auto manufactorDiscIDOpt = WiiUManufacturerDiscId::make_unique(discReader);
|
||||
if (!manufactorDiscIDOpt.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to read ManufactorDiscId");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to read ManufactorDiscId");
|
||||
return {};
|
||||
}
|
||||
|
||||
curOffset += WiiUManufactorDiscId::LENGTH;
|
||||
curOffset += WiiUManufacturerDiscId::LENGTH;
|
||||
auto discIdOpt = WiiUDiscId::make_unique(discReader, curOffset);
|
||||
if (!discIdOpt.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to read DiscId");
|
||||
if (!discIdOpt) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to read DiscId");
|
||||
return {};
|
||||
}
|
||||
curOffset += WiiUDiscId::LENGTH;
|
||||
auto wiiUContentsInformationOpt = WiiUContentsInformation::make_unique(discReader, curOffset);
|
||||
if (!wiiUContentsInformationOpt.has_value()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to read WiiUContentsInformation");
|
||||
if (!wiiUContentsInformationOpt) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to read WiiUContentsInformation");
|
||||
return {};
|
||||
}
|
||||
curOffset += WiiUContentsInformation::LENGTH;
|
||||
|
||||
if (curOffset - offset != LENGTH) {
|
||||
DEBUG_FUNCTION_LINE("Unexpected offset");
|
||||
DEBUG_FUNCTION_LINE_ERR("Unexpected offset");
|
||||
return {};
|
||||
}
|
||||
return std::unique_ptr<WiiUDiscHeader>(new WiiUDiscHeader(
|
||||
|
@ -17,7 +17,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "WiiUDiscId.h"
|
||||
#include "WiiUManufactorDiscId.h"
|
||||
#include "WiiUManufacturerDiscId.h"
|
||||
#include <WUD/DiscReader.h>
|
||||
#include <WUD/DiscReaderDiscDrive.h>
|
||||
#include <WUD/content/WiiUContentsInformation.h>
|
||||
@ -26,9 +26,9 @@
|
||||
|
||||
class WiiUDiscHeader {
|
||||
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<WiiUContentsInformation> wiiUContentsInformation;
|
||||
|
||||
@ -36,7 +36,7 @@ public:
|
||||
|
||||
private:
|
||||
explicit WiiUDiscHeader(
|
||||
std::unique_ptr<WiiUManufactorDiscId> pManufactorDiscId,
|
||||
std::unique_ptr<WiiUManufacturerDiscId> pManufacturerDiscId,
|
||||
std::unique_ptr<WiiUDiscId> pDiscId,
|
||||
std::unique_ptr<WiiUContentsInformation> pWiiUContentsInformation);
|
||||
};
|
@ -15,24 +15,26 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#include "WiiUDiscId.h"
|
||||
#include "utils/utils.h"
|
||||
#include <coreinit/debug.h>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <utils/logger.h>
|
||||
|
||||
std::optional<std::unique_ptr<WiiUDiscId>> WiiUDiscId::make_unique(const std::shared_ptr<DiscReader> &discReader, uint32_t offset) {
|
||||
auto data = (uint8_t *) malloc(WiiUDiscId::LENGTH);
|
||||
std::optional<std::unique_ptr<WiiUDiscId>> WiiUDiscId::make_unique(std::shared_ptr<DiscReader> &discReader, uint32_t offset) {
|
||||
auto data = make_unique_nothrow<uint8_t[]>(WiiUDiscId::LENGTH);
|
||||
if (data == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Failed to alloc memory");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!discReader->readEncrypted(data, offset, WiiUDiscId::LENGTH)) {
|
||||
DEBUG_FUNCTION_LINE("Failed to read data");
|
||||
if (!discReader->readEncrypted(data.get(), offset, WiiUDiscId::LENGTH)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to read data");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (((uint32_t *) data)[0] != WiiUDiscId::MAGIC) {
|
||||
DEBUG_FUNCTION_LINE("MAGIC mismatch");
|
||||
if (((uint32_t *) data.get())[0] != WiiUDiscId::MAGIC) {
|
||||
DEBUG_FUNCTION_LINE_ERR("MAGIC mismatch");
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -41,12 +43,10 @@ std::optional<std::unique_ptr<WiiUDiscId>> WiiUDiscId::make_unique(const std::sh
|
||||
|
||||
auto footprint = std::string((char *) &data[32]);
|
||||
|
||||
free(data);
|
||||
|
||||
return std::unique_ptr<WiiUDiscId>(new WiiUDiscId(minorVersion, majorVersion, footprint));
|
||||
}
|
||||
|
||||
WiiUDiscId::WiiUDiscId(uint8_t pMinorVersion, uint8_t pMajorVersion, const std::string &pFootprint) : minorVersion(pMinorVersion),
|
||||
majorVersion(pMajorVersion),
|
||||
footprint(pFootprint) {
|
||||
WiiUDiscId::WiiUDiscId(uint8_t pMinorVersion, uint8_t pMajorVersion, std::string pFootprint) : minorVersion(pMinorVersion),
|
||||
majorVersion(pMajorVersion),
|
||||
footprint(std::move(pFootprint)) {
|
||||
}
|
||||
|
@ -31,8 +31,8 @@ public:
|
||||
uint8_t majorVersion;
|
||||
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:
|
||||
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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#include "WiiUManufactorDiscId.h"
|
||||
#include "WiiUManufacturerDiscId.h"
|
||||
#include <coreinit/debug.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()) {
|
||||
DEBUG_FUNCTION_LINE("DiscReader is not ready");
|
||||
DEBUG_FUNCTION_LINE_ERR("DiscReader is not ready");
|
||||
return {};
|
||||
}
|
||||
std::array<uint8_t, WiiUManufactorDiscId::LENGTH> data{};
|
||||
std::array<uint8_t, WiiUManufacturerDiscId::LENGTH> data{};
|
||||
|
||||
if (!discReader->readEncrypted(data.data(), 0, WiiUManufactorDiscId::LENGTH)) {
|
||||
DEBUG_FUNCTION_LINE("Failed to read data");
|
||||
if (!discReader->readEncrypted(data.data(), 0, WiiUManufacturerDiscId::LENGTH)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to read data");
|
||||
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;
|
||||
}
|
@ -22,15 +22,15 @@
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
class WiiUManufactorDiscId {
|
||||
class WiiUManufacturerDiscId {
|
||||
|
||||
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;
|
||||
|
||||
std::array<uint8_t, WiiUManufactorDiscId::LENGTH> data;
|
||||
std::array<uint8_t, WiiUManufacturerDiscId::LENGTH> data;
|
||||
|
||||
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 <common/common.h>
|
||||
#include <fs/FSUtils.h>
|
||||
#include <iosuhax.h>
|
||||
#include <malloc.h>
|
||||
#include <mocha/fsa.h>
|
||||
#include <mocha/mocha.h>
|
||||
#include <utils/StringTools.h>
|
||||
#include <utils/WiiUScreen.h>
|
||||
#include <utils/utils.h>
|
||||
@ -28,14 +29,16 @@ WUDDumperState::WUDDumperState(WUDDumperState::eDumpTargetFormat pTargetFormat,
|
||||
: targetFormat(pTargetFormat), targetDevice(pTargetDevice) {
|
||||
this->sectorBufSize = READ_SECTOR_SIZE * READ_NUM_SECTORS;
|
||||
this->state = STATE_OPEN_ODD1;
|
||||
gBlockHomeButton = true;
|
||||
}
|
||||
|
||||
WUDDumperState::~WUDDumperState() {
|
||||
if (this->oddFd >= 0) {
|
||||
IOSUHAX_FSA_RawClose(gFSAfd, oddFd);
|
||||
FSAEx_RawClose(__wut_devoptab_fs_client, oddFd);
|
||||
}
|
||||
free(sectorBuf);
|
||||
free(emptySector);
|
||||
gBlockHomeButton = false;
|
||||
}
|
||||
|
||||
ApplicationState::eSubState WUDDumperState::update(Input *input) {
|
||||
@ -47,7 +50,7 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
|
||||
}
|
||||
if (this->state == STATE_OPEN_ODD1) {
|
||||
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) {
|
||||
// continue!
|
||||
this->state = STATE_DUMP_DISC;
|
||||
@ -61,7 +64,7 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
|
||||
this->state = STATE_PLEASE_INSERT_DISC;
|
||||
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 (this->sectorBuf == nullptr) {
|
||||
this->sectorBuf = (void *) memalign(0x100, this->sectorBufSize);
|
||||
@ -79,7 +82,7 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
|
||||
return SUBSTATE_RETURN;
|
||||
}
|
||||
} else if (this->state == STATE_READ_DISC_INFO) {
|
||||
if (IOSUHAX_FSA_RawRead(gFSAfd, this->sectorBuf, READ_SECTOR_SIZE, 1, 0, this->oddFd) >= 0) {
|
||||
if (FSAEx_RawRead(__wut_devoptab_fs_client, this->sectorBuf, READ_SECTOR_SIZE, 1, 0, this->oddFd) >= 0) {
|
||||
this->discId[10] = '\0';
|
||||
memcpy(this->discId.data(), sectorBuf, 10);
|
||||
if (this->discId[0] == 0) {
|
||||
@ -96,39 +99,39 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
|
||||
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.
|
||||
auto res = IOSUHAX_FSA_RawRead(gFSAfd, this->sectorBuf, READ_SECTOR_SIZE, 1, 3, this->oddFd);
|
||||
uint8_t discKey[16];
|
||||
auto res = FSAEx_RawRead(__wut_devoptab_fs_client, this->sectorBuf, READ_SECTOR_SIZE, 1, 3, this->oddFd);
|
||||
WUDDiscKey discKey;
|
||||
bool hasDiscKey = false;
|
||||
if (res >= 0) {
|
||||
if (((uint32_t *) this->sectorBuf)[0] != WiiUDiscContentsHeader::MAGIC) {
|
||||
auto discKeyRes = IOSUHAX_ODM_GetDiscKey(discKey);
|
||||
if (discKeyRes >= 0) {
|
||||
auto discKeyRes = Mocha_ODMGetDiscKey(&discKey);
|
||||
if (discKeyRes == MOCHA_RESULT_SUCCESS) {
|
||||
hasDiscKey = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
return SUBSTATE_RUNNING;
|
||||
}
|
||||
}
|
||||
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);
|
||||
return ApplicationState::SUBSTATE_RUNNING;
|
||||
}
|
||||
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);
|
||||
} 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);
|
||||
}
|
||||
if (!this->fileHandle->isOpen()) {
|
||||
@ -145,8 +148,13 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
|
||||
this->writtenSectors = 0;
|
||||
this->retryCount = 10;
|
||||
} 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;
|
||||
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);
|
||||
if (curWrittenSectors < 0) {
|
||||
this->setError(ERROR_WRITE_FAILED);
|
||||
@ -171,15 +179,30 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
|
||||
} else {
|
||||
this->state = STATE_WAIT_USER_ERROR_CONFIRM;
|
||||
if (this->oddFd >= 0) {
|
||||
IOSUHAX_FSA_RawClose(gFSAfd, this->oddFd);
|
||||
FSAEx_RawClose(__wut_devoptab_fs_client, this->oddFd);
|
||||
this->oddFd = -1;
|
||||
}
|
||||
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) {
|
||||
if (this->autoSkipOnError) {
|
||||
if (this->oddFd >= 0) {
|
||||
IOSUHAX_FSA_RawClose(gFSAfd, this->oddFd);
|
||||
FSAEx_RawClose(__wut_devoptab_fs_client, this->oddFd);
|
||||
this->oddFd = -1;
|
||||
}
|
||||
}
|
||||
@ -206,10 +229,10 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
|
||||
this->currentSector += 1;
|
||||
this->writtenSectors += curWrittenSectors;
|
||||
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->readResult = 0;
|
||||
} else if (input->data.buttons_d & Input::BUTTON_Y) {
|
||||
} else if (buttonPressed(input, Input::BUTTON_Y)) {
|
||||
this->autoSkipOnError = true;
|
||||
}
|
||||
} else if (this->state == STATE_DUMP_DISC_DONE) {
|
||||
@ -278,9 +301,19 @@ void WUDDumperState::render() {
|
||||
WiiUScreen::drawLine();
|
||||
if (!this->skippedSectors.empty()) {
|
||||
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) {
|
||||
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();
|
||||
|
@ -49,6 +49,7 @@ public:
|
||||
STATE_DUMP_DISC_DONE,
|
||||
STATE_WAIT_USER_ERROR_CONFIRM,
|
||||
STATE_DUMP_DISC,
|
||||
STATE_ABORT_CONFIRMATION,
|
||||
};
|
||||
|
||||
enum eErrorState {
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include "common.h"
|
||||
|
||||
int32_t gFSAfd = -1;
|
||||
|
||||
ntfs_md *ntfs_mounts = nullptr;
|
||||
int ntfs_mount_count = 0;
|
||||
BOOL gRunFromHBL = false;
|
||||
ntfs_md *ntfs_mounts = nullptr;
|
||||
int ntfs_mount_count = 0;
|
||||
BOOL gRunFromHBL = false;
|
||||
BOOL gBlockHomeButton = false;
|
||||
uint32_t gBlockHomeButtonCooldown = 0;
|
||||
|
@ -3,15 +3,17 @@
|
||||
#include <ntfs.h>
|
||||
#include <wut.h>
|
||||
|
||||
extern int32_t gFSAfd;
|
||||
|
||||
#define SECTOR_SIZE 0x8000
|
||||
#define READ_SECTOR_SIZE SECTOR_SIZE
|
||||
|
||||
extern ntfs_md *ntfs_mounts;
|
||||
extern int ntfs_mount_count;
|
||||
|
||||
extern "C" FSClient *__wut_devoptab_fs_client;
|
||||
|
||||
extern BOOL gRunFromHBL;
|
||||
extern BOOL gBlockHomeButton;
|
||||
extern uint32_t gBlockHomeButtonCooldown;
|
||||
|
||||
enum eDumpTarget {
|
||||
TARGET_SD,
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "FSUtils.h"
|
||||
#include "CFile.hpp"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/utils.h"
|
||||
#include <fcntl.h>
|
||||
#include <malloc.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);
|
||||
lseek(iFd, 0, SEEK_SET);
|
||||
|
||||
auto *buffer = (uint8_t *) malloc(filesize);
|
||||
auto *buffer = (uint8_t *) memalign(0x40, ROUNDUP(filesize, 0x40));
|
||||
if (buffer == nullptr) {
|
||||
close(iFd);
|
||||
return -2;
|
||||
@ -146,7 +147,7 @@ bool FSUtils::copyFile(const std::string &in, const std::string &out) {
|
||||
}
|
||||
|
||||
auto bufferSize = 1024 * 1024;
|
||||
char *buf = (char *) malloc(bufferSize);
|
||||
char *buf = (char *) memalign(0x40, ROUNDUP(bufferSize, 0x40));
|
||||
if (buf == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
****************************************************************************/
|
||||
#include "WUXFileWriter.h"
|
||||
#include "WUDDumperState.h"
|
||||
#include "utils/StringTools.h"
|
||||
#include <utils/logger.h>
|
||||
|
||||
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->totalSectorCount = WUD_FILE_SIZE / this->sectorSize;
|
||||
|
||||
this->sectorIndexTable = (void *) malloc(totalSectorCount * 4);
|
||||
this->sectorIndexTable = (void *) memalign(0x40, ROUNDUP(totalSectorCount * 4, 0x40));
|
||||
if (sectorIndexTable == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Failed to alloc");
|
||||
WUDFileWriter::close();
|
||||
@ -50,7 +51,7 @@ WUXFileWriter::WUXFileWriter(const char *path, int32_t cacheSize, int32_t sector
|
||||
this->sectorTableEnd -= (this->sectorTableEnd % this->sectorSize);
|
||||
|
||||
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);
|
||||
this->write(reinterpret_cast<const uint8_t *>(paddingData), padding);
|
||||
free(paddingData);
|
||||
@ -58,25 +59,22 @@ WUXFileWriter::WUXFileWriter(const char *path, int32_t cacheSize, int32_t sector
|
||||
flush();
|
||||
}
|
||||
|
||||
|
||||
int32_t WUXFileWriter::writeSector(const uint8_t *buffer, uint32_t numberOfSectors) {
|
||||
char hashOut[32];
|
||||
int32_t curWrittenSectors = 0;
|
||||
for (uint32_t i = 0; i < numberOfSectors; i++) {
|
||||
uint32_t addr = ((uint32_t) buffer) + (i * this->sectorSize);
|
||||
calculateHash256(reinterpret_cast<unsigned char *>(addr), this->sectorSize, reinterpret_cast<unsigned char *>(hashOut));
|
||||
char tmp[34];
|
||||
auto *test = (uint32_t *) hashOut;
|
||||
snprintf(tmp, 33, "%08X%08X%08X%08X", test[0], test[1], test[2], test[3]);
|
||||
std::string hash(tmp);
|
||||
std::array<uint8_t, 32> hashOut{};
|
||||
calculateHash256(reinterpret_cast<unsigned char *>(addr), this->sectorSize, reinterpret_cast<unsigned char *>(hashOut.data()));
|
||||
|
||||
auto *indexTable = (uint32_t *) this->sectorIndexTable;
|
||||
|
||||
auto it = hashMap.find(hash);
|
||||
auto it = hashMap.find(hashOut);
|
||||
if (it != hashMap.end()) {
|
||||
indexTable[this->currentSector] = swap_uint32(this->hashMap[hash]);
|
||||
indexTable[this->currentSector] = swap_uint32(this->hashMap[hashOut]);
|
||||
} else {
|
||||
indexTable[this->currentSector] = swap_uint32(this->writtenSector);
|
||||
hashMap[hash] = writtenSector;
|
||||
hashMap[hashOut] = writtenSector;
|
||||
if (isOpen()) {
|
||||
if (!write((uint8_t *) addr, this->sectorSize)) {
|
||||
DEBUG_FUNCTION_LINE("Write failed");
|
||||
|
@ -50,7 +50,7 @@ private:
|
||||
uint64_t sectorTableEnd;
|
||||
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 writtenSector = 0;
|
||||
};
|
@ -23,8 +23,8 @@
|
||||
#define SPLIT_SIZE (0x80000000)
|
||||
|
||||
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()) {
|
||||
return;
|
||||
}
|
||||
@ -81,8 +81,8 @@ int32_t WriteOnlyFileWithCache::write(const uint8_t *addr, size_t writeSize) {
|
||||
CFile::close();
|
||||
|
||||
// open the next part
|
||||
DEBUG_FUNCTION_LINE("Open %s", StringTools::strfmt("%s.part%d", originalPath.c_str(), part).c_str());
|
||||
this->open(StringTools::strfmt("%s.part%d", originalPath.c_str(), part), WriteOnly);
|
||||
DEBUG_FUNCTION_LINE("Open %s", string_format("%s.part%d", originalPath.c_str(), part).c_str());
|
||||
this->open(string_format("%s.part%d", originalPath.c_str(), part), WriteOnly);
|
||||
}
|
||||
if (finalWriteSize == 0) {
|
||||
return (int32_t) writeSize;
|
||||
@ -134,8 +134,8 @@ int32_t WriteOnlyFileWithCache::seek(int64_t offset, int32_t origin) {
|
||||
flush();
|
||||
close();
|
||||
part = (offset / SPLIT_SIZE) + 1;
|
||||
DEBUG_FUNCTION_LINE("Open %s", StringTools::strfmt("%s.part%d", originalPath.c_str(), part).c_str());
|
||||
this->open(StringTools::strfmt("%s.part%d", originalPath.c_str(), part), ReadWrite);
|
||||
DEBUG_FUNCTION_LINE("Open %s", string_format("%s.part%d", originalPath.c_str(), part).c_str());
|
||||
this->open(string_format("%s.part%d", originalPath.c_str(), part), ReadWrite);
|
||||
}
|
||||
return CFile::seek(offset % SPLIT_SIZE, SEEK_SET);
|
||||
}
|
||||
|
@ -1,39 +1,48 @@
|
||||
#include <whb/log.h>
|
||||
#include <whb/log_udp.h>
|
||||
#include <whb/proc.h>
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "MainApplicationState.h"
|
||||
#include "input/VPADInput.h"
|
||||
#include "utils/WiiUScreen.h"
|
||||
#include "utils/logger.h"
|
||||
#include <coreinit/debug.h>
|
||||
#include <coreinit/energysaver.h>
|
||||
#include <coreinit/title.h>
|
||||
#include <input/CombinedInput.h>
|
||||
#include <input/WPADInput.h>
|
||||
#include <iosuhax.h>
|
||||
#include <mocha/disc_interface.h>
|
||||
#include <mocha/mocha.h>
|
||||
#include <ntfs.h>
|
||||
#include <padscore/kpad.h>
|
||||
#include <thread>
|
||||
#include <whb/log.h>
|
||||
#include <whb/proc.h>
|
||||
|
||||
#include "MainApplicationState.h"
|
||||
#include "input/VPADInput.h"
|
||||
#include "utils/WiiUScreen.h"
|
||||
#include "utils/logger.h"
|
||||
void initMochaLib();
|
||||
|
||||
|
||||
void initIOSUHax();
|
||||
|
||||
void deInitIOSUHax();
|
||||
void deInitMochaLib();
|
||||
|
||||
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) {
|
||||
WHBLogUdpInit();
|
||||
initLogging();
|
||||
DEBUG_FUNCTION_LINE("Hello from wudump!");
|
||||
WHBProcInit();
|
||||
WiiUScreen::Init();
|
||||
|
||||
initIOSUHax();
|
||||
initMochaLib();
|
||||
ACPInitialize();
|
||||
|
||||
uint64_t titleID = OSGetTitleID();
|
||||
if (titleID == 0x0005000013374842 ||
|
||||
@ -41,6 +50,12 @@ int main(int argc, char **argv) {
|
||||
titleID == 0x000500101004A100 ||
|
||||
titleID == 0x000500101004A200) {
|
||||
gRunFromHBL = true;
|
||||
|
||||
ProcUIClearCallbacks();
|
||||
ProcUIRegisterCallback(PROCUI_CALLBACK_HOME_BUTTON_DENIED,
|
||||
&procHomeButtonDeniedCustom, NULL, 100);
|
||||
|
||||
|
||||
} else {
|
||||
gRunFromHBL = false;
|
||||
}
|
||||
@ -66,7 +81,7 @@ int main(int argc, char **argv) {
|
||||
WPADInput::close();
|
||||
|
||||
if (ntfs_mounts != nullptr) {
|
||||
int i = 0;
|
||||
int i;
|
||||
for (i = 0; i < ntfs_mount_count; i++) {
|
||||
ntfsUnmount(ntfs_mounts[i].name, true);
|
||||
}
|
||||
@ -78,7 +93,7 @@ int main(int argc, char **argv) {
|
||||
IMEnableAPD();
|
||||
}
|
||||
|
||||
deInitIOSUHax();
|
||||
deInitMochaLib();
|
||||
|
||||
WiiUScreen::DeInit();
|
||||
WHBProcShutdown();
|
||||
@ -97,11 +112,6 @@ void main_loop() {
|
||||
WPAD_CHAN_2,
|
||||
WPAD_CHAN_3};
|
||||
|
||||
if (gFSAfd < 0 || !sIosuhaxMount) {
|
||||
// state.setError(MainApplicationState::eErrorState::ERROR_IOSUHAX_FAILED);
|
||||
OSFatal("IOSUHAX Failed");
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE("Entering main loop");
|
||||
while (WHBProcIsRunning()) {
|
||||
baseInput.reset();
|
||||
@ -119,27 +129,22 @@ void main_loop() {
|
||||
}
|
||||
}
|
||||
|
||||
void initIOSUHax() {
|
||||
sIosuhaxMount = false;
|
||||
int res = IOSUHAX_Open(nullptr);
|
||||
if (res < 0) {
|
||||
DEBUG_FUNCTION_LINE("IOSUHAX_open failed");
|
||||
void initMochaLib() {
|
||||
slibMochaMount = false;
|
||||
MochaUtilsStatus res = Mocha_InitLibrary();
|
||||
if (res != MOCHA_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Mocha_InitLibrary failed: %s", Mocha_GetStatusStr(res));
|
||||
OSFatal("Failed to init libmocha. Please update MochaPayload.");
|
||||
} else {
|
||||
sIosuhaxMount = true;
|
||||
gFSAfd = IOSUHAX_FSA_Open();
|
||||
if (gFSAfd < 0) {
|
||||
DEBUG_FUNCTION_LINE("IOSUHAX_FSA_Open failed");
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("IOSUHAX done");
|
||||
}
|
||||
slibMochaMount = true;
|
||||
}
|
||||
}
|
||||
|
||||
void deInitIOSUHax() {
|
||||
if (sIosuhaxMount) {
|
||||
if (gFSAfd >= 0) {
|
||||
IOSUHAX_FSA_Close(gFSAfd);
|
||||
}
|
||||
IOSUHAX_Close();
|
||||
void deInitMochaLib() {
|
||||
if (slibMochaMount) {
|
||||
Mocha_DeinitLibrary();
|
||||
}
|
||||
|
||||
Mocha_sdio_disc_interface.shutdown();
|
||||
Mocha_usb_disc_interface.shutdown();
|
||||
}
|
@ -17,7 +17,7 @@
|
||||
#include "ScreenUtils.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) {
|
||||
return;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
//! 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 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
|
||||
|
@ -24,209 +24,15 @@
|
||||
* for WiiXplorer 2010
|
||||
***************************************************************************/
|
||||
#include "StringTools.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <strings.h>
|
||||
#include <vector>
|
||||
#include <wchar.h>
|
||||
#include <wut_types.h>
|
||||
|
||||
|
||||
BOOL StringTools::EndsWith(const std::string &a, const std::string &b) {
|
||||
if (b.size() > a.size())
|
||||
return false;
|
||||
return std::equal(a.begin() + a.size() - b.size(), a.end(), b.begin());
|
||||
bool invalidChar(unsigned char c) {
|
||||
return !(c >= 0 && c < 128) || c == 0x0A || c == 0x0D;
|
||||
}
|
||||
|
||||
const char *StringTools::byte_to_binary(int32_t x) {
|
||||
static char b[9];
|
||||
b[0] = '\0';
|
||||
|
||||
int32_t z;
|
||||
for (z = 128; z > 0; z >>= 1) {
|
||||
strcat(b, ((x & z) == z) ? "1" : "0");
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
std::string StringTools::removeCharFromString(std::string &input, char toBeRemoved) {
|
||||
std::string output = input;
|
||||
size_t position;
|
||||
while (1) {
|
||||
position = output.find(toBeRemoved);
|
||||
if (position == std::string::npos)
|
||||
break;
|
||||
output.erase(position, 1);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
const char *StringTools::fmt(const char *format, ...) {
|
||||
static char strChar[512];
|
||||
strChar[0] = 0;
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if ((vsprintf(strChar, format, va) >= 0)) {
|
||||
va_end(va);
|
||||
return (const char *) strChar;
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const wchar_t *StringTools::wfmt(const char *format, ...) {
|
||||
static char tmp[512];
|
||||
static wchar_t strWChar[512];
|
||||
strWChar[0] = 0;
|
||||
tmp[0] = 0;
|
||||
|
||||
if (!format)
|
||||
return (const wchar_t *) strWChar;
|
||||
|
||||
if (strcmp(format, "") == 0)
|
||||
return (const wchar_t *) strWChar;
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||
int32_t bt;
|
||||
int32_t strlength = strlen(tmp);
|
||||
bt = mbstowcs(strWChar, tmp, (strlength < 512) ? strlength : 512);
|
||||
|
||||
if (bt > 0) {
|
||||
strWChar[bt] = 0;
|
||||
return (const wchar_t *) strWChar;
|
||||
}
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32_t StringTools::strprintf(std::string &str, const char *format, ...) {
|
||||
static char tmp[512];
|
||||
tmp[0] = 0;
|
||||
int32_t result = 0;
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||
str = tmp;
|
||||
result = str.size();
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string StringTools::strfmt(const char *format, ...) {
|
||||
std::string str;
|
||||
static char tmp[512];
|
||||
tmp[0] = 0;
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||
str = tmp;
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
BOOL StringTools::char2wchar_t(const char *strChar, wchar_t *dest) {
|
||||
if (!strChar || !dest)
|
||||
return false;
|
||||
|
||||
int32_t bt;
|
||||
bt = mbstowcs(dest, strChar, strlen(strChar));
|
||||
if (bt > 0) {
|
||||
dest[bt] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t StringTools::strtokcmp(const char *string, const char *compare, const char *separator) {
|
||||
if (!string || !compare)
|
||||
return -1;
|
||||
|
||||
char TokCopy[512];
|
||||
strncpy(TokCopy, compare, sizeof(TokCopy));
|
||||
TokCopy[511] = '\0';
|
||||
|
||||
char *strTok = strtok(TokCopy, separator);
|
||||
|
||||
while (strTok != NULL) {
|
||||
if (strcasecmp(string, strTok) == 0) {
|
||||
return 0;
|
||||
}
|
||||
strTok = strtok(NULL, separator);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t StringTools::strextcmp(const char *string, const char *extension, char seperator) {
|
||||
if (!string || !extension)
|
||||
return -1;
|
||||
|
||||
char *ptr = strrchr(string, seperator);
|
||||
if (!ptr)
|
||||
return -1;
|
||||
|
||||
return strcasecmp(ptr + 1, extension);
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> StringTools::stringSplit(const std::string &inValue, const std::string &splitter) {
|
||||
std::string value = inValue;
|
||||
std::vector<std::string> result;
|
||||
while (true) {
|
||||
uint32_t index = value.find(splitter);
|
||||
if (index == std::string::npos) {
|
||||
result.push_back(value);
|
||||
break;
|
||||
}
|
||||
std::string first = value.substr(0, index);
|
||||
result.push_back(first);
|
||||
if (index + splitter.size() == value.length()) {
|
||||
result.push_back("");
|
||||
break;
|
||||
}
|
||||
if (index + splitter.size() > value.length()) {
|
||||
break;
|
||||
}
|
||||
value = value.substr(index + splitter.size(), value.length());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool StringTools::findStringIC(const std::string &strHaystack, const std::string &strNeedle) {
|
||||
auto it = std::search(
|
||||
strHaystack.begin(), strHaystack.end(),
|
||||
strNeedle.begin(), strNeedle.end(),
|
||||
[](char ch1, char ch2) { return std::toupper(ch1) == std::toupper(ch2); });
|
||||
return (it != strHaystack.end());
|
||||
}
|
||||
|
||||
bool StringTools::replace(std::string &str, const std::string &from, const std::string &to) {
|
||||
size_t start_pos = str.find(from);
|
||||
if (start_pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
str.replace(start_pos, from.length(), to);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool StringTools::strCompareIC(const std::string &str1, const std::string &str2) {
|
||||
return str1.size() == str2.size() && std::equal(str1.begin(), str1.end(), str2.begin(), [](auto a, auto b) { return std::tolower(a) == std::tolower(b); });
|
||||
void StringTools::StripUnicodeAndLineBreak(std::string &str) {
|
||||
std::replace(str.begin(), str.end(), (char) 0x0A, ' '); // replace LF with space
|
||||
std::replace(str.begin(), str.end(), (char) 0x0D, ' '); // replace CR with space
|
||||
str.erase(remove_if(str.begin(), str.end(), invalidChar), str.end());
|
||||
}
|
@ -25,71 +25,31 @@
|
||||
***************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include "logger.h"
|
||||
#include "utils.h"
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <coreinit/debug.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#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 {
|
||||
public:
|
||||
static BOOL EndsWith(const std::string &a, const std::string &b);
|
||||
|
||||
static const char *byte_to_binary(int32_t x);
|
||||
|
||||
static std::string removeCharFromString(std::string &input, char toBeRemoved);
|
||||
|
||||
static const char *fmt(const char *format, ...);
|
||||
|
||||
static const wchar_t *wfmt(const char *format, ...);
|
||||
|
||||
static int32_t strprintf(std::string &str, const char *format, ...);
|
||||
|
||||
static std::string strfmt(const char *format, ...);
|
||||
|
||||
static BOOL char2wchar_t(const char *src, wchar_t *dest);
|
||||
|
||||
static int32_t strtokcmp(const char *string, const char *compare, const char *separator);
|
||||
|
||||
static int32_t strextcmp(const char *string, const char *extension, char seperator);
|
||||
|
||||
static const char *FullpathToFilename(const char *path) {
|
||||
if (!path)
|
||||
return path;
|
||||
|
||||
const char *ptr = path;
|
||||
const char *Filename = ptr;
|
||||
|
||||
while (*ptr != '\0') {
|
||||
if (ptr[0] == '/' && ptr[1] != '\0')
|
||||
Filename = ptr + 1;
|
||||
|
||||
++ptr;
|
||||
}
|
||||
|
||||
return Filename;
|
||||
}
|
||||
|
||||
static void RemoveDoubleSlashs(std::string &str) {
|
||||
uint32_t length = str.size();
|
||||
|
||||
//! clear path of double slashes
|
||||
for (uint32_t i = 1; i < length; ++i) {
|
||||
if (str[i - 1] == '/' && str[i] == '/') {
|
||||
str.erase(i, 1);
|
||||
i--;
|
||||
length--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<std::string> stringSplit(const std::string &value, const std::string &splitter);
|
||||
|
||||
// https://stackoverflow.com/a/19839371
|
||||
static bool findStringIC(const std::string &strHaystack, const std::string &strNeedle);
|
||||
|
||||
// https://stackoverflow.com/a/3418285
|
||||
static bool replace(std::string &str, const std::string &from, const std::string &to);
|
||||
|
||||
static bool strCompareIC(const std::string &str1, const std::string &str2);
|
||||
static void StripUnicodeAndLineBreak(std::string &str);
|
||||
};
|
||||
|
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::ProcCallbackAcquired(void *context) {
|
||||
uint32_t WiiUScreen::ProcCallbackAcquired([[maybe_unused]] void *context) {
|
||||
MEMHeapHandle heap = MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM1);
|
||||
if (sBufferSizeTV) {
|
||||
sBufferTV = MEMAllocFromFrmHeapEx(heap, sBufferSizeTV, 4);
|
||||
@ -29,7 +29,7 @@ uint32_t WiiUScreen::ProcCallbackAcquired(void *context) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t WiiUScreen::ProcCallbackReleased(void *context) {
|
||||
uint32_t WiiUScreen::ProcCallbackReleased([[maybe_unused]] void *context) {
|
||||
MEMHeapHandle heap = MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM1);
|
||||
MEMFreeByStateToFrmHeap(heap, CONSOLE_FRAME_HEAP_TAG);
|
||||
sConsoleHasForeground = FALSE;
|
||||
|
@ -27,9 +27,9 @@
|
||||
class WiiUScreen {
|
||||
|
||||
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();
|
||||
|
||||
|
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,25 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <coreinit/debug.h>
|
||||
#include <string.h>
|
||||
#include <whb/log.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
#include <whb/log.h>
|
||||
#define LOG_APP_TYPE "H"
|
||||
#define LOG_APP_NAME "WUDD"
|
||||
|
||||
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
||||
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) \
|
||||
do { \
|
||||
WHBLogPrintf("[%23s]%30s@L%04d: " FMT, __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
||||
#define LOG(LOG_FUNC, FMT, ARGS...) LOG_EX(LOG_FUNC, "", "", FMT, ##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)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) \
|
||||
do { \
|
||||
WHBLogWritef("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
||||
} while (0)
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#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
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
@ -1,12 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <malloc.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define LIMIT(x, min, max) \
|
||||
({ \
|
||||
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);
|
||||
|
||||
#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 {
|
||||
public:
|
||||
|
Loading…
Reference in New Issue
Block a user