Various improvements including:

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

View File

@ -1,6 +1,6 @@
FROM wiiuenv/devkitppc:20220724
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

View File

@ -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
#-------------------------------------------------------------------------------

View File

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

View File

@ -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");

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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 *) &sector_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 *) &sector_buf[0], (uint8_t *) &sector_buf_decrypted[0], READ_SECTOR_SIZE);
if (((uint32_t *) sector_buf_decrypted.get())[0] == WiiUDiscContentsHeader::MAGIC) {
this->init_done = true;
} else {
DEBUG_FUNCTION_LINE_ERR("Invalid disc key");
}
} else {
DEBUG_FUNCTION_LINE_ERR("Failed to get the DiscKey");
this->init_done = false;
}
} else {
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;

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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();
}
}

View File

@ -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;
};

View File

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

View File

@ -21,9 +21,9 @@
class NUSDecryption {
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;
};

View File

@ -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;

View File

@ -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);
};

View File

@ -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);
}

View File

@ -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);

View File

@ -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)) {
}

View File

@ -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);

View File

@ -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));
}

View File

@ -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);

View File

@ -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();
}

View File

@ -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;
};

View File

@ -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();
}
}

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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{};
};

View File

@ -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;
}

View File

@ -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);
};

View File

@ -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;

View File

@ -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;
};

View File

@ -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)),

View File

@ -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);
};

View File

@ -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 {};
}

View File

@ -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];

View File

@ -24,13 +24,13 @@ DirectoryEntry::parseData(const std::array<uint8_t, NodeEntry::LENGTH> &data, co
auto lastEntryNumber = ((uint32_t *) &data[8])[0];
auto 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 {};
}

View File

@ -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 {};
}

View File

@ -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 {};
}

View File

@ -49,19 +49,19 @@ NodeEntry::AutoDeserialize(const std::vector<uint8_t> &data,
if ((param.type & ENTRY_TYPE_Directory) == ENTRY_TYPE_Directory && param.uint24 == 0) { // Root
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 {};
}

View File

@ -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 {};
}

View File

@ -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));
}

View File

@ -22,7 +22,7 @@
std::optional<std::shared_ptr<StringTable>> StringTable::make_shared(const std::vector<uint8_t> &data, uint32_t offset, uint32_t stringCount) {
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 {};
}

View File

@ -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));
}

View File

@ -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);
};

View File

@ -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(

View File

@ -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);
};

View File

@ -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)) {
}

View File

@ -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);
};

View File

@ -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;
}

View File

@ -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);
};

View File

@ -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();

View File

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

View File

@ -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;

View File

@ -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,

View File

@ -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;
}

View File

@ -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");

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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;
}

View File

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

View File

@ -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());
}

View File

@ -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
View File

@ -0,0 +1,15 @@
#include "WUDUtils.h"
#include "FSTUtils.h"
std::optional<uint64_t> WUDUtils::getOffsetOfContent(const std::shared_ptr<WiiUGMPartition> &gamePartition, const std::shared_ptr<FST> &fst, const std::shared_ptr<Content> &content) {
if (content->index == 0) { // Index 0 is the FST which is at the beginning of the partition;
auto &vh = gamePartition->getVolumes().begin()->second;
return gamePartition->getSectionOffsetOnDefaultPartition() + vh->FSTAddress.getAddressInBytes();
}
auto info = FSTUtils::getSectionEntryForIndex(fst, content->index);
if (!info.has_value()) {
DEBUG_FUNCTION_LINE_ERR("Failed to get section for Content");
return {};
}
return gamePartition->getSectionOffsetOnDefaultPartition() + info.value()->address.getAddressInBytes();
}

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

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

View File

@ -13,7 +13,7 @@ uint32_t WiiUScreen::consoleColor = 0x041F60FF;
uint32_t WiiUScreen::consoleCursorY = 0;
uint32_t WiiUScreen::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;

View File

@ -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
View File

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

View File

@ -1,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

View File

@ -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: