Use shared_ptr/unique_ptr in combination with std::optional instead of raw pointers

This commit is contained in:
Maschell 2021-10-11 22:02:35 +02:00
parent 6919bdb44f
commit fc2e994b72
67 changed files with 1410 additions and 853 deletions

View File

@ -22,6 +22,7 @@
#include <WUD/entities/TMD/TitleMetaData.h>
#include <WUD/NUSDataProviderWUD.h>
#include <WUD/NUSTitle.h>
#include <memory>
extern ntfs_md *ntfs_mounts;
extern int ntfs_mount_count;
@ -704,32 +705,36 @@ void ApplicationState::printDumpState(const char *fmt, ...) {
void ApplicationState::dumpAppFiles() {
uint8_t opt[0x400];
IOSUHAX_read_otp(opt, 0x400);
uint8_t cKey[0x10];
memcpy(cKey, opt + 0xE0, 0x10);
std::array<uint8_t, 0x10> cKey{};
memcpy(cKey.data(), opt + 0xE0, 0x10);
DEBUG_FUNCTION_LINE("Reading Partitions");
printDumpState("Reading Partitions...");
auto discReader = new DiscReaderDiscDrive();
auto discReader = std::make_shared<DiscReaderDiscDrive>();
if (!discReader->IsReady()) {
DEBUG_FUNCTION_LINE("!IsReady");
this->setError(ERROR_OPEN_ODD1);
delete discReader;
return;
}
DEBUG_FUNCTION_LINE("Read DiscHeader");
auto *discHeader = new WiiUDiscHeader(discReader);
auto discHeader = WiiUDiscHeader::make_unique(discReader);
if (!discHeader.has_value()) {
DEBUG_FUNCTION_LINE("Failed to read discheader");
return;
}
bool forceExit = false;
for (auto &partition: discHeader->wiiUContentsInformation->partitions->partitions) {
auto gmPartition = dynamic_cast<WiiUGMPartition *>(partition);
for (auto &partition: discHeader.value()->wiiUContentsInformation->partitions->partitions) {
auto gmPartition = std::dynamic_pointer_cast<WiiUGMPartition>(partition);
if (gmPartition != nullptr) {
auto *nusTitle = NUSTitle::loadTitleFromGMPartition(gmPartition, discReader, cKey);
if (nusTitle == nullptr) {
auto nusTitleOpt = NUSTitle::loadTitleFromGMPartition(gmPartition, discReader, cKey);
if (!nusTitleOpt.has_value()) {
DEBUG_FUNCTION_LINE("nusTitle was null");
continue;
}
auto *dataProvider = nusTitle->dataProcessor->getDataProvider();
auto nusTitle = nusTitleOpt.value();
auto dataProvider = nusTitle->dataProcessor->getDataProvider();
uint64_t partitionSize = 0;
uint64_t partitionSizeWritten = 0;
@ -745,26 +750,26 @@ void ApplicationState::dumpAppFiles() {
snprintf(buffer, 500, "%swudump/%s/%s", target.c_str(), this->discId, gmPartition->getVolumeId().c_str());
FSUtils::CreateSubfolder(buffer);
uint8_t *wBuffer = nullptr;
uint32_t wBufferLen = 0;
if (dataProvider->getRawTMD(&wBuffer, &wBufferLen)) {
std::vector<uint8_t> wBuffer;
if (dataProvider->getRawTMD(wBuffer)) {
std::string fileName = std::string(buffer).append("/").append(WUD_TMD_FILENAME);
printDumpState("%s\nSaving %s", partitionDumpInfo.c_str(), WUD_TMD_FILENAME);
FSUtils::saveBufferToFile(fileName.c_str(), wBuffer, wBufferLen);
free(wBuffer);
FSUtils::saveBufferToFile(fileName.c_str(), wBuffer.data(), wBuffer.size());
wBuffer.clear();
}
if (dataProvider->getRawTicket(&wBuffer, &wBufferLen)) {
if (dataProvider->getRawTicket(wBuffer)) {
std::string fileName = std::string(buffer).append("/").append(WUD_TICKET_FILENAME);
printDumpState("%s\nSaving %s", partitionDumpInfo.c_str(), WUD_TICKET_FILENAME);
FSUtils::saveBufferToFile(fileName.c_str(), wBuffer, wBufferLen);
free(wBuffer);
FSUtils::saveBufferToFile(fileName.c_str(), wBuffer.data(), wBuffer.size());
wBuffer.clear();
}
if (dataProvider->getRawCert(&wBuffer, &wBufferLen)) {
if (dataProvider->getRawCert(wBuffer)) {
std::string fileName = std::string(buffer).append("/").append(WUD_TICKET_FILENAME);
printDumpState("%s\nSaving %s", partitionDumpInfo.c_str(), WUD_CERT_FILENAME);
FSUtils::saveBufferToFile(fileName.c_str(), wBuffer, wBufferLen);
free(wBuffer);
FSUtils::saveBufferToFile(fileName.c_str(), wBuffer.data(), wBuffer.size());
wBuffer.clear();
}
auto contentCount = nusTitle->tmd->contentList.size();
@ -836,26 +841,20 @@ void ApplicationState::dumpAppFiles() {
break;
}
uint8_t *h3Data = nullptr;
uint32_t h3Length = 0;
if (dataProvider->getContentH3Hash(content, &h3Data, &h3Length)) {
std::vector<uint8_t> h3Data;
if (dataProvider->getContentH3Hash(content, h3Data)) {
char bufh3[32];
snprintf(bufh3, 31, "%08X.h3", content->ID);
std::string h3FileName = std::string(buffer) + "/" + bufh3;
printDumpState("%s\n%s", partitionDumpInfo.c_str(), contentDumpInfo.c_str());
FSUtils::saveBufferToFile(h3FileName.c_str(), h3Data, h3Length);
FSUtils::saveBufferToFile(h3FileName.c_str(), h3Data.data(), h3Data.size());
}
contentI++;
}
delete nusTitle;
if (forceExit) {
exit(0);
break;
}
}
}
delete discHeader;
delete discReader;
}

View File

@ -16,45 +16,45 @@
****************************************************************************/
#include "DefaultNUSDataProcessor.h"
bool DefaultNUSDataProcessor::readPlainDecryptedContent(Content *pContent, uint8_t **data, uint32_t *length) {
if (pContent == nullptr || data == nullptr || length == nullptr) {
return false;
}
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");
return false;
}
auto contentSize = ROUNDUP(pContent->encryptedFileSize, 16);
out_data.resize(contentSize);
*length = ROUNDUP(pContent->encryptedFileSize, 16);
*data = (uint8_t *) malloc(*length);
if (*data == nullptr) {
auto *inData = (uint8_t *) malloc(contentSize);
if (inData == nullptr) {
DEBUG_FUNCTION_LINE("Failed to alloc");
return false;
}
auto *inData = (uint8_t *) malloc(*length);
if (!dataProvider->readRawContent(pContent, inData, 0, *length)) {
free(*data);
if (!dataProvider->readRawContent(pContent, inData, 0, contentSize)) {
DEBUG_FUNCTION_LINE("Failed tor read content");
free(inData);
return false;
}
uint8_t IV[16];
memset(IV, 0, 16);
std::array<uint8_t, 16> IV{};
memset(IV.data(), 0, 16);
uint16_t content_index = pContent->index;
memcpy(IV, &content_index, 2);
memcpy(IV.data(), &content_index, 2);
nusDecryption->decryptData(IV, inData, *data, *length);
nusDecryption->decryptData(IV, inData, out_data.data(), contentSize);
free(inData);
return true;
}
NUSDataProvider *DefaultNUSDataProcessor::getDataProvider() {
std::shared_ptr<NUSDataProvider> DefaultNUSDataProcessor::getDataProvider() {
return dataProvider;
}
DefaultNUSDataProcessor::DefaultNUSDataProcessor(NUSDataProvider *pDataProvider, NUSDecryption *pNUSDecryption) {
dataProvider = pDataProvider;
nusDecryption = pNUSDecryption;
DefaultNUSDataProcessor::DefaultNUSDataProcessor(
std::shared_ptr<NUSDataProvider> pDataProvider,
std::shared_ptr<NUSDecryption> pNUSDecryption) :
dataProvider(std::move(pDataProvider)),
nusDecryption(std::move(pNUSDecryption)) {
DEBUG_FUNCTION_LINE();
}

View File

@ -21,15 +21,15 @@
class DefaultNUSDataProcessor : public NUSDataProcessor {
public:
DefaultNUSDataProcessor(NUSDataProvider *pDataProvider, NUSDecryption *pNUSDecryption);
DefaultNUSDataProcessor(std::shared_ptr<NUSDataProvider> pDataProvider, std::shared_ptr<NUSDecryption> pNUSDecryption);
~DefaultNUSDataProcessor() override = default;
bool readPlainDecryptedContent(Content *pContent, uint8_t **data, uint32_t *length) override;
bool readPlainDecryptedContent(const std::shared_ptr<Content> &pContent, std::vector<uint8_t> &out_data) override;
NUSDataProvider *getDataProvider() override;
std::shared_ptr<NUSDataProvider> getDataProvider() override;
private:
NUSDataProvider *dataProvider;
NUSDecryption *nusDecryption;
std::shared_ptr<NUSDataProvider> dataProvider;
std::shared_ptr<NUSDecryption> nusDecryption;
};

View File

@ -24,6 +24,7 @@
DiscReaderDiscDrive::DiscReaderDiscDrive() : DiscReader() {
DEBUG_FUNCTION_LINE();
auto *sector_buf = (uint8_t *) malloc(READ_SECTOR_SIZE);
if (sector_buf == nullptr) {
return;
@ -75,6 +76,7 @@ bool DiscReaderDiscDrive::IsReady() {
}
DiscReaderDiscDrive::~DiscReaderDiscDrive() {
DEBUG_FUNCTION_LINE();
if (device_handle != -1) {
IOSUHAX_FSA_RawOpen(gFSAfd, "/dev/odd01", &device_handle);
}
@ -95,3 +97,12 @@ bool DiscReaderDiscDrive::readEncrypted(uint8_t *buf, uint64_t offset, uint32_t
}
return true;
}
std::optional<DiscReaderDiscDrive *> DiscReaderDiscDrive::Create() {
auto discReader = new DiscReaderDiscDrive();
if (!discReader->IsReady()) {
delete discReader;
return {};
}
return discReader;
}

View File

@ -25,6 +25,8 @@ public:
~DiscReaderDiscDrive() override;
static std::optional<DiscReaderDiscDrive *> Create();
bool readEncryptedSector(uint8_t *buffer, uint32_t block_cnt, uint64_t offset_in_sector) const override;
bool IsReady() override;

View File

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

View File

@ -25,17 +25,17 @@ class NUSDataProvider {
public:
virtual ~NUSDataProvider() = default;
virtual bool readRawContent(Content *content, uint8_t *buffer, uint64_t offset, uint32_t size) = 0;
virtual bool readRawContent(const std::shared_ptr<Content> &content, uint8_t *buffer, uint64_t offset, uint32_t size) = 0;
virtual bool getContentH3Hash(Content *content, uint8_t **data, uint32_t *size) = 0;
virtual bool getContentH3Hash(const std::shared_ptr<Content> &content, std::vector<uint8_t> &out_data) = 0;
virtual bool getRawTMD(uint8_t **data, uint32_t *size) = 0;
virtual bool getRawTMD(std::vector<uint8_t> &out_data) = 0;
virtual bool getRawTicket(uint8_t **data, uint32_t *size) = 0;
virtual bool getRawTicket(std::vector<uint8_t> &out_data) = 0;
virtual bool getRawCert(uint8_t **data, uint32_t *size) = 0;
virtual bool getRawCert(std::vector<uint8_t> &out_data) = 0;
virtual void setFST(FST *fst) {
virtual void setFST(const std::shared_ptr<FST> &fst) {
}
};

View File

@ -16,41 +16,40 @@
****************************************************************************/
#include "NUSDataProviderWUD.h"
NUSDataProviderWUD::NUSDataProviderWUD(WiiUGMPartition *pGamePartition, DiscReader *pDiscReader) {
NUSDataProviderWUD::NUSDataProviderWUD(const std::shared_ptr<WiiUGMPartition> &pGamePartition, const std::shared_ptr<DiscReader> &pDiscReader) {
DEBUG_FUNCTION_LINE();
gamePartition = pGamePartition;
discReader = pDiscReader;
}
NUSDataProviderWUD::~NUSDataProviderWUD() {
delete fst;
DEBUG_FUNCTION_LINE();
}
bool NUSDataProviderWUD::readRawContent(Content *content, uint8_t *buffer, uint64_t offset, uint32_t size) {
bool NUSDataProviderWUD::readRawContent(const std::shared_ptr<Content> &content, uint8_t *buffer, uint64_t offset, uint32_t size) {
if (buffer == nullptr) {
DEBUG_FUNCTION_LINE();
return false;
}
auto offsetInWUD = getOffsetInWUD(content) + offset;
auto offsetInWUDOpt = getOffsetInWUD(content);
if (!offsetInWUDOpt.has_value()) {
return false;
}
auto offsetInWUD = offsetInWUDOpt.value() + offset;
return discReader->readEncrypted(buffer, offsetInWUD, size);
}
bool NUSDataProviderWUD::getContentH3Hash(Content *content, uint8_t **data, uint32_t *size) {
if (content == nullptr || data == nullptr || size == nullptr) {
DEBUG_FUNCTION_LINE();
return false;
}
bool NUSDataProviderWUD::getContentH3Hash(const std::shared_ptr<Content> &content, std::vector<uint8_t> &out_data) {
auto cur = gamePartition->getVolumes().begin()->second->h3HashArrayList[content->index];
if (cur == nullptr || cur->size == 0) {
DEBUG_FUNCTION_LINE();
return false;
}
*data = (uint8_t *) malloc(cur->size);
*size = cur->size;
memcpy(*data, cur->data, *size);
out_data.resize(cur->size);
memcpy(out_data.data(), cur->data, cur->size);
return true;
}
void NUSDataProviderWUD::setFST(FST *pFST) {
void NUSDataProviderWUD::setFST(const std::shared_ptr<FST> &pFST) {
// We need to set the correct blocksizes
auto blockSize = gamePartition->getVolumes().begin()->second->blockSize;
for (const auto &e: pFST->sectionEntries->getSections()) {
@ -60,55 +59,30 @@ void NUSDataProviderWUD::setFST(FST *pFST) {
fst = pFST;
}
bool NUSDataProviderWUD::getRawCert(uint8_t **data, uint32_t *size) {
if (data == nullptr || size == nullptr) {
return false;
}
*data = (uint8_t *) malloc(gamePartition->certLen);
if (*data == nullptr) {
return false;
}
*size = gamePartition->certLen;
memcpy(*data, gamePartition->rawCert, gamePartition->certLen);
bool NUSDataProviderWUD::getRawCert(std::vector<uint8_t> &out_data) {
out_data = gamePartition->rawCert;
return true;
}
bool NUSDataProviderWUD::getRawTicket(uint8_t **data, uint32_t *size) {
if (data == nullptr || size == nullptr) {
return false;
}
*data = (uint8_t *) malloc(gamePartition->tikLen);
if (*data == nullptr) {
return false;
}
*size = gamePartition->tikLen;
memcpy(*data, gamePartition->rawTicket, gamePartition->tikLen);
bool NUSDataProviderWUD::getRawTicket(std::vector<uint8_t> &out_data) {
out_data = gamePartition->rawTicket;
return true;
}
bool NUSDataProviderWUD::getRawTMD(uint8_t **data, uint32_t *size) {
if (data == nullptr || size == nullptr) {
DEBUG_FUNCTION_LINE("input was null");
return false;
}
*data = (uint8_t *) malloc(gamePartition->TMDLen);
if (*data == nullptr) {
DEBUG_FUNCTION_LINE("Failed to alloc memory");
return false;
}
*size = gamePartition->TMDLen;
memcpy(*data, gamePartition->rawTMD, gamePartition->TMDLen);
bool NUSDataProviderWUD::getRawTMD(std::vector<uint8_t> &out_data) {
out_data = gamePartition->rawTMD;
return true;
}
uint64_t NUSDataProviderWUD::getOffsetInWUD(Content *content) const {
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;
auto vh = gamePartition->getVolumes().begin()->second;
return gamePartition->getSectionOffsetOnDefaultPartition() + vh->FSTAddress.getAddressInBytes();
}
auto *info = FSTUtils::getSectionEntryForIndex(fst, content->index);
if (info == nullptr) {
OSFatal("Failed to get section for Content");
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->address.getAddressInBytes();
return gamePartition->getSectionOffsetOnDefaultPartition() + info.value()->address.getAddressInBytes();
}

View File

@ -25,26 +25,26 @@
class NUSDataProviderWUD : public NUSDataProvider {
public:
NUSDataProviderWUD(WiiUGMPartition *pGamePartition, DiscReader *pDiscReader);
NUSDataProviderWUD(const std::shared_ptr<WiiUGMPartition> &pPartition, const std::shared_ptr<DiscReader> &pDrive);
~NUSDataProviderWUD() override;
bool readRawContent(Content *content, uint8_t *buffer, uint64_t offset, uint32_t size) override;
bool readRawContent(const std::shared_ptr<Content> &content, uint8_t *buffer, uint64_t offset, uint32_t size) override;
bool getContentH3Hash(Content *content, uint8_t **data, uint32_t *size) override;
bool getContentH3Hash(const std::shared_ptr<Content> &content, std::vector<uint8_t> &out_data) override;
void setFST(FST *pFST) override;
void setFST(const std::shared_ptr<FST> &pFST) override;
bool getRawCert(uint8_t **data, uint32_t *size) override;
bool getRawCert(std::vector<uint8_t> &out_data) override;
bool getRawTicket(uint8_t **data, uint32_t *size) override;
bool getRawTicket(std::vector<uint8_t> &data) override;
bool getRawTMD(uint8_t **data, uint32_t *size) override;
bool getRawTMD(std::vector<uint8_t> &out_data) override;
FST *fst{};
WiiUGMPartition *gamePartition;
DiscReader *discReader;
std::shared_ptr<FST> fst;
std::shared_ptr<WiiUGMPartition> gamePartition;
std::shared_ptr<DiscReader> discReader;
private:
uint64_t getOffsetInWUD(Content *content) const;
[[nodiscard]] std::optional<uint64_t> getOffsetInWUD(const std::shared_ptr<Content> &content) const;
};

View File

@ -16,11 +16,14 @@
****************************************************************************/
#include "NUSDecryption.h"
void NUSDecryption::decryptData(uint8_t *IV, uint8_t *inData, uint8_t *outData, uint32_t size) const {
aes_set_key(ticket->ticketKeyDec);
aes_decrypt(IV, inData, outData, size);
#include <utility>
#include <utils/logger.h>
void NUSDecryption::decryptData(const std::array<uint8_t, 0x10> &IV, uint8_t *inData, uint8_t *outData, uint32_t size) const {
aes_set_key(ticket->ticketKeyDec.data());
aes_decrypt((uint8_t *) IV.data(), inData, outData, size);
}
NUSDecryption::NUSDecryption(Ticket *pTicket) {
ticket = pTicket;
NUSDecryption::NUSDecryption(std::shared_ptr<Ticket> pTicket) : ticket(std::move(pTicket)) {
DEBUG_FUNCTION_LINE();
}

View File

@ -17,12 +17,13 @@
#pragma once
#include "Ticket.h"
#include <array>
class NUSDecryption {
public:
explicit NUSDecryption(Ticket *pTicket);
explicit NUSDecryption(std::shared_ptr<Ticket> pTicket);
void decryptData(uint8_t *IV, uint8_t *inData, uint8_t *outData, uint32_t size) const;
void decryptData(const std::array<uint8_t, 0x10> &IV, uint8_t *inData, uint8_t *outData, uint32_t size) const;
Ticket *ticket;
std::shared_ptr<Ticket> ticket;
};

View File

@ -16,68 +16,81 @@
****************************************************************************/
#include "NUSTitle.h"
NUSTitle *NUSTitle::loadTitle(NUSDataProvider *dataProvider, uint8_t *commonKey) {
uint8_t *data = nullptr;
uint32_t dataLen = 0;
if (!dataProvider->getRawTMD(&data, &dataLen)) {
#include <utility>
std::optional<std::shared_ptr<NUSTitle>> NUSTitle::loadTitle(const std::shared_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");
delete dataProvider;
return nullptr;
return {};
}
auto *tmd = new TitleMetaData(data);
free(data);
auto tmdOpt = TitleMetaData::make_shared(dataBuffer);
if (!tmdOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse TMD");
return {};
}
dataBuffer.clear();
if (!dataProvider->getRawTicket(&data, &dataLen)) {
DEBUG_FUNCTION_LINE("Failed to read ticket");
delete tmd;
delete dataProvider;
return nullptr;
if (!dataProvider->getRawTicket(dataBuffer)) {
DEBUG_FUNCTION_LINE("Failed to read ticket data");
return {};
}
auto *ticket = new Ticket(data, commonKey);
free(data);
auto *decryption = new NUSDecryption(ticket);
auto *dpp = new DefaultNUSDataProcessor(dataProvider, decryption);
auto ticketOpt = Ticket::make_shared(dataBuffer, commonKey);
if (!ticketOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse ticket");
return {};
}
dataBuffer.clear();
auto decryption = std::make_shared<NUSDecryption>(std::move(ticketOpt.value()));
auto dpp = std::shared_ptr<NUSDataProcessor>(new DefaultNUSDataProcessor(dataProvider, decryption));
// If we have more than one content, the index 0 is the FST.
Content *fstContent = tmd->getContentByIndex(0);
if (!dpp->readPlainDecryptedContent(fstContent, &data, &dataLen)) {
DEBUG_FUNCTION_LINE("Failed to read decrypted content");
delete dataProvider;
delete dpp;
delete decryption;
delete ticket;
delete tmd;
return nullptr;
auto fstContentOpt = tmdOpt.value()->getContentByIndex(0);
if (!fstContentOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to get content for index 0");
return {};
}
if (!dpp->readPlainDecryptedContent(fstContentOpt.value(), dataBuffer)) {
DEBUG_FUNCTION_LINE("Failed to read decrypted content");
return {};
}
auto fstOpt = FST::make_shared(dataBuffer, 0, VolumeBlockSize(1));
if (!fstOpt.has_value()) {
DEBUG_FUNCTION_LINE();
return {};
}
FST *fst = new FST(data, dataLen, 0, VolumeBlockSize(1));
// The dataprovider may need the FST to calculate the offset of a content
// on the partition.
dataProvider->setFST(fst);
return new NUSTitle(tmd, dpp, dataProvider, decryption, ticket, fst);
dataProvider->setFST(fstOpt.value());
return std::shared_ptr<NUSTitle>(new NUSTitle(tmdOpt.value(), dpp, dataProvider, decryption, ticketOpt.value(), fstOpt.value()));
}
NUSTitle::NUSTitle(TitleMetaData *pTMD, NUSDataProcessor *pProcessor, NUSDataProvider *pDataProvider, NUSDecryption *pDecryption, Ticket *pTicket, FST *pFST) {
tmd = pTMD;
dataProcessor = pProcessor;
ticket = pTicket;
fst = pFST;
decryption = pDecryption;
dataProvider = pDataProvider;
NUSTitle::NUSTitle(std::shared_ptr<TitleMetaData> pTMD,
std::shared_ptr<NUSDataProcessor> pProcessor,
std::shared_ptr<NUSDataProvider> pDataProvider,
std::shared_ptr<NUSDecryption> pDecryption,
std::shared_ptr<Ticket> pTicket,
std::shared_ptr<FST> pFST) :
dataProcessor(std::move(pProcessor)),
tmd(std::move(pTMD)),
ticket(std::move(pTicket)),
fst(std::move(pFST)),
decryption(std::move(pDecryption)),
dataProvider(std::move(pDataProvider)) {
}
NUSTitle::~NUSTitle() {
delete dataProvider;
delete dataProcessor;
delete decryption;
delete ticket;
delete tmd;
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) {
DEBUG_FUNCTION_LINE();
return loadTitle(std::shared_ptr<NUSDataProvider>(new NUSDataProviderWUD(pPartition, pDrive)), commonKey);
}
NUSTitle *NUSTitle::loadTitleFromGMPartition(WiiUGMPartition *pPartition, DiscReaderDiscDrive *pDrive, uint8_t *commonKey) {
return loadTitle(new NUSDataProviderWUD(pPartition, pDrive), commonKey);
}
NUSTitle::~NUSTitle() = default;

View File

@ -31,18 +31,26 @@ class NUSTitle {
public:
~NUSTitle();
NUSDataProcessor *dataProcessor;
TitleMetaData *tmd;
Ticket *ticket;
FST *fst;
NUSDecryption *decryption;
NUSDataProvider *dataProvider;
std::shared_ptr<NUSDataProcessor> dataProcessor;
std::shared_ptr<TitleMetaData> tmd;
std::shared_ptr<Ticket> ticket;
std::shared_ptr<FST> fst;
std::shared_ptr<NUSDecryption> decryption;
std::shared_ptr<NUSDataProvider> dataProvider;
static NUSTitle *loadTitleFromGMPartition(WiiUGMPartition *pPartition, DiscReaderDiscDrive *pDrive, uint8_t commonKey[16]);
static std::optional<std::shared_ptr<NUSTitle>> loadTitleFromGMPartition(
const std::shared_ptr<WiiUGMPartition> &pPartition,
const std::shared_ptr<DiscReader> &pDrive,
const std::array<uint8_t, 16> &commonKey);
private:
static NUSTitle *loadTitle(NUSDataProvider *dataProvider, uint8_t commonKey[16]);
static std::optional<std::shared_ptr<NUSTitle>> loadTitle(const std::shared_ptr<NUSDataProvider> &dataProvider, const std::array<uint8_t, 16> &commonKey);
NUSTitle(TitleMetaData *pTMD, NUSDataProcessor *pProcessor, NUSDataProvider *pDataProvider, NUSDecryption *pDecryption, Ticket *pTicket, FST *pFST);
NUSTitle(std::shared_ptr<TitleMetaData> pTMD,
std::shared_ptr<NUSDataProcessor> pProcessor,
std::shared_ptr<NUSDataProvider> pDataProvider,
std::shared_ptr<NUSDecryption> pDecryption,
std::shared_ptr<Ticket> pTicket,
std::shared_ptr<FST> pFST);
};

View File

@ -15,19 +15,40 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "Ticket.h"
#include <algorithm>
#include <utils/logger.h>
Ticket::Ticket(uint8_t *data, uint8_t *commonKey) {
uint8_t *tikKeyEnc = data + 0x1BF;
uint8_t *title_id = data + 0x1DC;
uint8_t IV[0x10];
Ticket::Ticket(const std::array<uint8_t, 16> &pEncryptedKey, const std::array<uint8_t, 16> &pDecryptedKey) :
ticketKeyEnc(pEncryptedKey),
ticketKeyDec(pDecryptedKey) {
DEBUG_FUNCTION_LINE();
int k;
for (k = 0; k < 8; k++) {
IV[k] = title_id[k];
IV[k + 8] = 0x00;
}
std::optional<std::shared_ptr<Ticket>> Ticket::make_shared(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");
return {};
}
aes_set_key(commonKey);
aes_decrypt(IV, tikKeyEnc, ticketKeyDec, 16);
memcpy(ticketKeyEnc, tikKeyEnc, 16);
std::array<uint8_t, 16> title_id{};
std::array<uint8_t, 16> decryptedKey{};
std::array<uint8_t, 16> encryptedKey{};
std::copy_n(data.begin() + 0x1BF, 0x10, decryptedKey.begin());
std::copy_n(data.begin() + 0x1BF, 0x10, encryptedKey.begin());
std::copy_n(data.begin() + 0x1DC, 0x10, title_id.begin());
uint8_t IV[0x10];
for (int i = 0; i < 8; i++) {
IV[i] = title_id[i];
IV[i + 8] = 0x00;
}
if (commonKey.has_value()) {
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));
}

View File

@ -19,11 +19,17 @@
#include <cstdint>
#include <utils/rijndael.h>
#include <cstring>
#include <optional>
#include <memory>
#include <vector>
class Ticket {
public:
Ticket(uint8_t *data, uint8_t commonKey[16]);
std::array<uint8_t, 16> ticketKeyEnc;
std::array<uint8_t, 16> ticketKeyDec;
uint8_t ticketKeyEnc[16]{};
uint8_t ticketKeyDec[16]{};
static std::optional<std::shared_ptr<Ticket>> make_shared(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,20 +19,37 @@
uint32_t WiiUContentsInformation::LENGTH = 32768;
WiiUContentsInformation::WiiUContentsInformation(DiscReader *reader, uint32_t offset) {
std::optional<std::unique_ptr<WiiUContentsInformation>> WiiUContentsInformation::make_unique(const std::shared_ptr<DiscReader> &discReader, uint32_t offset) {
uint32_t curOffset = offset;
discContentHeader = new WiiUDiscContentsHeader(reader, curOffset);
auto discContentHeaderOpt = WiiUDiscContentsHeader::make_unique(discReader, curOffset);
if (!discContentHeaderOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to read WiiUDiscContentsHeader");
return {};
}
curOffset += WiiUDiscContentsHeader::LENGTH;
partitions = new WiiUPartitions(reader, curOffset, discContentHeader->numberOfPartition, discContentHeader->blockSize);
auto partitionsOpt = WiiUPartitions::make_unique(discReader, curOffset, discContentHeaderOpt.value()->numberOfPartition, discContentHeaderOpt.value()->blockSize);
if (!partitionsOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to read Partitions");
return {};
}
curOffset += WiiUPartitions::LENGTH;
if (curOffset - offset != LENGTH) {
OSFatal("Length mismatch");
DEBUG_FUNCTION_LINE("Unexpected offset");
return {};
}
return std::unique_ptr<WiiUContentsInformation>(new WiiUContentsInformation(
std::move(discContentHeaderOpt.value()),
std::move(partitionsOpt.value())));
}
WiiUContentsInformation::~WiiUContentsInformation() {
delete partitions;
delete discContentHeader;
}
WiiUContentsInformation::WiiUContentsInformation(std::unique_ptr<WiiUDiscContentsHeader> pDiscContentHeader,
std::unique_ptr<WiiUPartitions> pPartitions) :
discContentHeader(std::move(pDiscContentHeader)),
partitions(std::move(pPartitions)) {
};

View File

@ -16,20 +16,22 @@
****************************************************************************/
#pragma once
#include "../DiscReader.h"
#include <memory>
#include <WUD/DiscReader.h>
#include "WiiUDiscContentsHeader.h"
#include "partitions/WiiUPartitions.h"
class WiiUContentsInformation {
public:
WiiUContentsInformation(DiscReader *reader, uint32_t offset);
std::unique_ptr<WiiUDiscContentsHeader> discContentHeader;
~WiiUContentsInformation();
WiiUDiscContentsHeader *discContentHeader;
WiiUPartitions *partitions;
std::unique_ptr<WiiUPartitions> partitions;
static uint32_t LENGTH;
static std::optional<std::unique_ptr<WiiUContentsInformation>> make_unique(const std::shared_ptr<DiscReader> &discReader, uint32_t offset);
private:
WiiUContentsInformation(std::unique_ptr<WiiUDiscContentsHeader> pDiscContentsHeader, std::unique_ptr<WiiUPartitions> pPartitions);
};

View File

@ -16,29 +16,43 @@
****************************************************************************/
#include <utils/blocksize/DiscBlockSize.h>
#include <coreinit/debug.h>
#include <cstdlib>
#include "WiiUDiscContentsHeader.h"
uint32_t WiiUDiscContentsHeader::LENGTH = 2048;
uint32_t WiiUDiscContentsHeader::MAGIC = 0xCCA6E67B;
WiiUDiscContentsHeader::WiiUDiscContentsHeader(DiscReader *reader, uint32_t offset) {
std::optional<std::unique_ptr<WiiUDiscContentsHeader>> WiiUDiscContentsHeader::make_unique(const std::shared_ptr<DiscReader> &discReader, uint32_t offset) {
auto *buffer = (uint8_t *) malloc(LENGTH);
if (!reader->hasDiscKey) {
if (!reader->readEncrypted(buffer, offset, LENGTH)) {
OSFatal("WiiUDiscContentsHeader: Failed to read encrypted");
if (!buffer) {
DEBUG_FUNCTION_LINE("Failed to alloc buffer");
return {};
}
if (!discReader->hasDiscKey) {
if (!discReader->readEncrypted(buffer, offset, LENGTH)) {
DEBUG_FUNCTION_LINE("Failed to read data");
return {};
}
} else {
if (!reader->readDecrypted(buffer, offset, 0, LENGTH, reader->discKey, nullptr, true)) {
OSFatal("WiiUDiscContentsHeader: Failed to read decrypted");
if (!discReader->readDecrypted(buffer, offset, 0, LENGTH, discReader->discKey, nullptr, true)) {
DEBUG_FUNCTION_LINE("Failed to read data");
return {};
}
}
if (((uint32_t *) buffer)[0] != MAGIC) {
OSFatal("WiiUDiscContentsHeader MAGIC mismatch.");
DEBUG_FUNCTION_LINE("MAGIC mismatch");
return {};
}
blockSize = DiscBlockSize(((uint32_t *) buffer)[1]);
memcpy(tocHash, &buffer[8], 20);
numberOfPartition = ((uint32_t *) buffer)[7];
auto blockSize = DiscBlockSize(((uint32_t *) buffer)[1]);
std::array<uint8_t, 20> tocHash{};
memcpy(tocHash.data(), &buffer[8], 20);
auto numberOfPartition = ((uint32_t *) buffer)[7];
free(buffer);
return std::unique_ptr<WiiUDiscContentsHeader>(new WiiUDiscContentsHeader(blockSize, tocHash, numberOfPartition));
}
WiiUDiscContentsHeader::WiiUDiscContentsHeader(DiscBlockSize pSize, const std::array<uint8_t, 20> &pTocHash, uint32_t pNumberOfPartitions) :
blockSize(pSize),
numberOfPartition(pNumberOfPartitions),
tocHash(pTocHash) {
}

View File

@ -16,21 +16,24 @@
****************************************************************************/
#pragma once
#include <algorithm>
#include <memory>
#include <WUD/DiscReader.h>
#include <utils/blocksize/DiscBlockSize.h>
#include <optional>
class WiiUDiscContentsHeader {
public:
WiiUDiscContentsHeader(DiscReader *reader, uint32_t offset);
~WiiUDiscContentsHeader() = default;
DiscBlockSize blockSize{};
uint8_t tocHash[20]{};
uint32_t numberOfPartition;
std::array<uint8_t, 20> tocHash;
static uint32_t LENGTH;
static constexpr uint32_t LENGTH = 2048;
static constexpr uint32_t MAGIC = 0xCCA6E67B;
static uint32_t MAGIC;
static std::optional<std::unique_ptr<WiiUDiscContentsHeader>> make_unique(const std::shared_ptr<DiscReader> &discReader, uint32_t offset);
private:
WiiUDiscContentsHeader(DiscBlockSize pSize, const std::array<uint8_t, 20> &pTocHash, uint32_t pNumberOfPartitions);
};

View File

@ -16,21 +16,23 @@
****************************************************************************/
#include "WiiUDataPartition.h"
WiiUDataPartition::~WiiUDataPartition() {
delete basePartition;
delete fst;
}
#include <utility>
WiiUDataPartition::~WiiUDataPartition() = default;
WiiUDataPartition::WiiUDataPartition(
std::shared_ptr<WiiUPartition> pPartition,
std::shared_ptr<FST> pFST) :
fst(std::move(pFST)),
basePartition(std::move(pPartition)) {
WiiUDataPartition::WiiUDataPartition(WiiUPartition *partition, FST *pFST) {
basePartition = partition;
fst = pFST;
}
std::string WiiUDataPartition::getVolumeId() const &{
return basePartition->getVolumeId();
}
std::map<AddressInDiscBlocks, VolumeHeader *> WiiUDataPartition::getVolumes() const &{
std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> WiiUDataPartition::getVolumes() const &{
return basePartition->getVolumes();
}

View File

@ -25,22 +25,22 @@
class WiiUDataPartition : public WiiUPartition {
public:
WiiUDataPartition(WiiUPartition *partition, FST *pFST);
WiiUDataPartition(std::shared_ptr<WiiUPartition> pPartition, std::shared_ptr<FST> pFST);
~WiiUDataPartition() override;
[[nodiscard]] std::string getVolumeId() const & override;
[[nodiscard]] std::map<AddressInDiscBlocks, VolumeHeader *> getVolumes() const & override;
[[nodiscard]] std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> getVolumes() const & override;
[[nodiscard]] uint16_t getFileSystemDescriptor() const override;
[[nodiscard]] uint64_t getSectionOffsetOnDefaultPartition() override;
FST *fst{};
std::shared_ptr<FST> fst;
private:
WiiUPartition *basePartition;
std::shared_ptr<WiiUPartition> basePartition;
};

View File

@ -16,28 +16,22 @@
****************************************************************************/
#include "WiiUGMPartition.h"
WiiUGMPartition::~WiiUGMPartition() {
free(rawCert);
free(rawTMD);
free(rawTicket);
delete basePartition;
}
WiiUGMPartition::WiiUGMPartition(WiiUPartition *partition, uint8_t *pRawTIK, uint32_t pTikLen, uint8_t *pRawTMD, uint32_t pTMDLen, uint8_t *pRawCert, uint32_t pCertLen) {
basePartition = partition;
rawCert = pRawCert;
rawTMD = pRawTMD;
rawTicket = pRawTIK;
tikLen = pTikLen;
TMDLen = pTMDLen;
certLen = pCertLen;
WiiUGMPartition::WiiUGMPartition(std::shared_ptr<WiiUPartition> partition,
std::vector<uint8_t> pRawTicket,
std::vector<uint8_t> pRawTMD,
std::vector<uint8_t> pRawCert)
: WiiUPartition(),
rawTicket(std::move(pRawTicket)),
rawTMD(std::move(pRawTMD)),
rawCert(std::move(pRawCert)),
basePartition(std::move(partition)) {
}
std::string WiiUGMPartition::getVolumeId() const &{
return basePartition->getVolumeId();
}
std::map<AddressInDiscBlocks, VolumeHeader *> WiiUGMPartition::getVolumes() const &{
std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> WiiUGMPartition::getVolumes() const &{
return basePartition->getVolumes();
}

View File

@ -16,32 +16,31 @@
****************************************************************************/
#pragma once
#include <memory>
#include <cstdint>
#include <cstdlib>
#include "WiiUPartition.h"
class WiiUGMPartition : public WiiUPartition {
public:
WiiUGMPartition(WiiUPartition *partition, uint8_t *pRawTIK, uint32_t pTikLen, uint8_t *pRawTMD, uint32_t pTMDLen, uint8_t *pRawCert, uint32_t pCertLen);
~WiiUGMPartition() override;
WiiUGMPartition(std::shared_ptr<WiiUPartition> partition,
std::vector<uint8_t> pRawTicket,
std::vector<uint8_t> pRawTMD,
std::vector<uint8_t> pRawCert);
[[nodiscard]] std::string getVolumeId() const & override;
[[nodiscard]] std::map<AddressInDiscBlocks, VolumeHeader *> getVolumes() const & override;
[[nodiscard]] std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> getVolumes() const & override;
[[nodiscard]] uint16_t getFileSystemDescriptor() const override;
[[nodiscard]] uint64_t getSectionOffsetOnDefaultPartition() override;
uint8_t *rawTicket;
uint8_t *rawTMD;
uint8_t *rawCert;
uint32_t tikLen;
uint32_t TMDLen;
uint32_t certLen;
std::vector<uint8_t> rawTicket;
std::vector<uint8_t> rawTMD;
std::vector<uint8_t> rawCert;
private:
WiiUPartition *basePartition;
std::shared_ptr<WiiUPartition> basePartition;
};

View File

@ -14,36 +14,33 @@
* 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 <memory>
#include <coreinit/debug.h>
#include "WiiUPartition.h"
uint32_t WiiUPartition::LENGTH = 128;
WiiUPartition::WiiUPartition() = default;
WiiUPartition::~WiiUPartition() {
for (auto const&[key, val]: volumes) {
delete val;
uint64_t WiiUPartition::getSectionOffsetOnDefaultPartition() {
if (volumes.size() != 1) {
OSFatal("We have more or less than 1 volume header.");
}
volumes.clear();
return volumes.begin()->first.getAddressInBytes();
}
WiiUPartition::WiiUPartition(DiscReader *reader, uint32_t offset, const DiscBlockSize &blockSize) {
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) {
OSFatal("WiiUPartition: alloc buffer failed");
return {};
}
if (!reader->hasDiscKey) {
if (!reader->readEncrypted(buffer, offset, LENGTH)) {
OSFatal("WiiUPartition: Failed to read encrypted");
if (!discReader->hasDiscKey) {
if (!discReader->readEncrypted(buffer, offset, LENGTH)) {
return {};
}
} else {
auto bufferBigger = (uint8_t *) malloc(LENGTH + 0x10);
if (bufferBigger == nullptr) {
OSFatal("WiiUPartition: alloc bufferBigger failed");
return {};
}
if (!reader->readDecrypted(bufferBigger, offset - 0x10, 0, LENGTH + 0x10, reader->discKey, nullptr, true)) {
OSFatal("WiiUPartition: Failed to read encrypted");
if (!discReader->readDecrypted(bufferBigger, offset - 0x10, 0, LENGTH + 0x10, discReader->discKey, nullptr, true)) {
return {};
}
memcpy(buffer, bufferBigger + 0x10, LENGTH);
@ -54,26 +51,46 @@ WiiUPartition::WiiUPartition(DiscReader *reader, uint32_t offset, const DiscBloc
char name[32];
memset(name, 0, sizeof(name));
memcpy(name, buffer, 31);
volumeId = name;
auto volumeId = name;
uint8_t num = buffer[31];
std::map<AddressInDiscBlocks, std::shared_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 = new VolumeHeader(reader, discLbaAddress.getAddressInBytes());
volumes[discLbaAddress] = vh;
auto vh = VolumeHeader::make_shared(discReader, discLbaAddress.getAddressInBytes());
if (!vh.has_value()) {
free(buffer);
return {};
}
volumes[discLbaAddress] = vh.value();
}
fileSystemDescriptor = ((uint16_t *) &buffer[64])[0];
auto fileSystemDescriptor = ((uint16_t *) &buffer[64])[0];
free(buffer);
return std::unique_ptr<WiiUPartition>(new WiiUPartition(
volumeId,
volumes,
fileSystemDescriptor));
}
uint64_t WiiUPartition::getSectionOffsetOnDefaultPartition() {
if (volumes.size() != 1) {
OSFatal("We have more or less than 1 volume header.");
}
return volumes.begin()->first.getAddressInBytes();
std::string WiiUPartition::getVolumeId() const &{
return volumeId;
}
std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> WiiUPartition::getVolumes() const &{
return volumes;
}
uint16_t WiiUPartition::getFileSystemDescriptor() const {
return fileSystemDescriptor;
}
WiiUPartition::~WiiUPartition() = default;

View File

@ -17,6 +17,7 @@
#pragma once
#include <map>
#include <utility>
#include <utils/blocksize/DiscBlockSize.h>
#include <utils/blocksize/AddressInDiscBlocks.h>
#include "volumes/VolumeHeader.h"
@ -24,29 +25,29 @@
class WiiUPartition {
public:
WiiUPartition();
virtual ~WiiUPartition();
explicit WiiUPartition(DiscReader *reader, uint32_t offset, const DiscBlockSize &blockSize);
static constexpr uint32_t LENGTH = 128;
virtual uint64_t getSectionOffsetOnDefaultPartition();
virtual ~WiiUPartition();
[[nodiscard]] virtual std::string getVolumeId() const &;
[[nodiscard]] virtual std::string getVolumeId() const &{
return volumeId;
}
[[nodiscard]] virtual std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> getVolumes() const &;
[[nodiscard]] virtual std::map<AddressInDiscBlocks, VolumeHeader *> getVolumes() const &{
return volumes;
}
[[nodiscard]] virtual uint16_t getFileSystemDescriptor() const;
[[nodiscard]] virtual uint16_t getFileSystemDescriptor() const {
return fileSystemDescriptor;
}
static std::optional<std::shared_ptr<WiiUPartition>> make_shared(const 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) {
}
std::string volumeId;
std::map<AddressInDiscBlocks, VolumeHeader *> volumes;
std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> volumes;
uint16_t fileSystemDescriptor{};
static uint32_t LENGTH;
};

View File

@ -16,94 +16,140 @@
****************************************************************************/
#include <utils/FSTUtils.h>
#include <coreinit/debug.h>
#include <utility>
#include "WiiUPartitions.h"
#include "WiiUGMPartition.h"
#include "WiiUDataPartition.h"
uint32_t WiiUPartitions::LENGTH = 30720;
bool WiiUPartitions::getFSTEntryAsByte(std::string &filePath,
const std::shared_ptr<FST> &fst,
const AddressInDiscBlocks &volumeAddress,
const std::shared_ptr<DiscReader> &discReader,
std::vector<uint8_t> &out_data) {
auto entryOpt = FSTUtils::getFSTEntryByFullPath(fst->getRootEntry(), filePath);
if (!entryOpt.has_value()) {
return false;
}
WiiUPartitions::WiiUPartitions(DiscReader *reader, uint32_t offset, uint32_t numberOfPartitions, const DiscBlockSize &blockSize) {
std::vector<WiiUPartition *> tmp;
auto asFileEntry = std::dynamic_pointer_cast<FileEntry>(entryOpt.value());
if (asFileEntry == nullptr) {
return false;
}
auto info = asFileEntry->getSectionEntry();
uint64_t sectionOffsetOnDisc = volumeAddress.getAddressInBytes() + info->address.getAddressInBytes();
out_data.resize(asFileEntry->getSize());
if (!discReader->hasDiscKey) {
return discReader->readEncrypted(out_data.data(), sectionOffsetOnDisc + asFileEntry->getOffset(), asFileEntry->getSize());
}
// Calculating the IV
uint8_t IV[16];
memset(IV, 0, 16);
uint64_t ivTemp = asFileEntry->getOffset() >> 16;
memcpy(IV + 8, &ivTemp, 8);
return discReader->readDecrypted(out_data.data(), sectionOffsetOnDisc, asFileEntry->getOffset(), asFileEntry->getSize(), discReader->discKey, IV, false);
}
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);
tmp.reserve(numberOfPartitions);
for (uint32_t i = 0; i < numberOfPartitions; i++) {
tmp.push_back(new WiiUPartition(reader, offset + (i * 128), blockSize));
auto partitionOpt = WiiUPartition::make_shared(discReader, offset + (i * 128), blockSize);
if (!partitionOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to read partition");
return {};
}
tmp.push_back(partitionOpt.value());
}
WiiUPartition *SIPartition = nullptr;
std::optional<std::shared_ptr<WiiUPartition>> SIPartition;
for (auto &partition: tmp) {
if (partition->getVolumeId().starts_with("SI")) {
SIPartition = partition;
break;
}
}
if (SIPartition != nullptr) {
for (auto const&[key, val]: SIPartition->getVolumes()) {
if (SIPartition.has_value()) {
for (auto const&[key, val]: SIPartition.value()->getVolumes()) {
auto volumeAddress = key;
auto volumeAddressInBytes = volumeAddress.getAddressInBytes();
auto volumeHeader = val;
auto fst = (uint8_t *) malloc(volumeHeader->FSTSize);
if (fst == nullptr) {
OSFatal("WiiUPartitions: Failed to alloc FST buffer");
}
std::vector<uint8_t> fstData;
fstData.resize(volumeHeader->FSTSize);
if (!reader->hasDiscKey) {
if (!reader->readEncrypted(fst, volumeAddressInBytes + volumeHeader->FSTAddress.getAddressInBytes(),
volumeHeader->FSTSize)) {
OSFatal("WiiUPartitions: Failed to read encrypted");
if (!discReader->hasDiscKey) {
if (!discReader->readEncrypted(fstData.data(), volumeAddressInBytes + volumeHeader->FSTAddress.getAddressInBytes(),
volumeHeader->FSTSize)) {
DEBUG_FUNCTION_LINE("Failed to read FST");
return {};
}
} else {
if (!reader->readDecrypted(fst, volumeAddressInBytes + volumeHeader->FSTAddress.getAddressInBytes(), 0, volumeHeader->FSTSize,
reader->discKey, nullptr, true)) {
OSFatal("WiiUPartitions: Failed to read decrypted");
if (!discReader->readDecrypted(fstData.data(), volumeAddressInBytes + volumeHeader->FSTAddress.getAddressInBytes(), 0, volumeHeader->FSTSize,
discReader->discKey, nullptr, true)) {
DEBUG_FUNCTION_LINE("Failed to read FST");
return {};
}
}
FST *siFST = new FST(fst, volumeHeader->FSTSize, 0, volumeHeader->blockSize);
free(fst);
auto siFST = FST::make_shared(fstData, 0, volumeHeader->blockSize);
if (!siFST.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse FST");
return {};
}
for (auto &child: siFST->getRootEntry()->getDirChildren()) {
uint8_t *tikRaw = nullptr;
uint32_t tikRawLen = 0;
for (auto &child: siFST.value()->getRootEntry()->getDirChildren()) {
std::vector<uint8_t> bufferTicket;
std::string tikFilePath = std::string(child->getFullPath() + '/' + WUD_TICKET_FILENAME);
if (!getFSTEntryAsByte(&tikRaw, &tikRawLen, tikFilePath, siFST, volumeAddress, reader)) {
OSFatal("tikRaw");
if (!getFSTEntryAsByte(tikFilePath, siFST.value(), volumeAddress, discReader, bufferTicket)) {
DEBUG_FUNCTION_LINE("Failted to read FSTEntry");
return {};
}
uint8_t *tmdRaw = nullptr;
uint32_t tmdRawLen = 0;
std::vector<uint8_t> bufferTMD;
std::string tmdFilePath = std::string(child->getFullPath() + '/' + WUD_TMD_FILENAME);
if (!getFSTEntryAsByte(&tmdRaw, &tmdRawLen, tmdFilePath, siFST, volumeAddress, reader)) {
OSFatal("tmdRaw");
if (!getFSTEntryAsByte(tmdFilePath, siFST.value(), volumeAddress, discReader, bufferTMD)) {
DEBUG_FUNCTION_LINE("Failted to read FSTEntry");
return {};
}
uint8_t *certRaw = nullptr;
uint32_t certRawLen = 0;
std::vector<uint8_t> bufferCert;
std::string certFilePath = std::string(child->getFullPath() + '/' + WUD_CERT_FILENAME);
if (!getFSTEntryAsByte(&certRaw, &certRawLen, certFilePath, siFST, volumeAddress, reader)) {
OSFatal("certRaw");
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 *) &tikRaw[0x1DC]));
snprintf(partitionNameRaw, 0x11, "%016llX", *((uint64_t *) &bufferTicket[0x1DC]));
std::string partitionName = std::string("GM") + partitionNameRaw;
WiiUPartition *curPartition = nullptr;
std::optional<std::shared_ptr<WiiUPartition>> curPartition;
for (auto &partition: tmp) {
if (partition->getVolumeId().starts_with(partitionName)) {
curPartition = partition;
break;
}
}
if (curPartition == nullptr) {
OSFatal("Failed to get partition");
if (!curPartition.has_value()) {
DEBUG_FUNCTION_LINE("Failed to find partition");
return {};
}
auto *gmPartition = new WiiUGMPartition(curPartition, tikRaw, tikRawLen, tmdRaw, tmdRawLen, certRaw, certRawLen);
auto gmPartition = std::shared_ptr<WiiUPartition>(new WiiUGMPartition(curPartition.value(), bufferTicket, bufferTMD, bufferCert));
partitions.push_back(gmPartition);
}
delete siFST;
}
}
@ -117,65 +163,32 @@ WiiUPartitions::WiiUPartitions(DiscReader *reader, uint32_t offset, uint32_t num
}
auto volumeAddress = partition->getVolumes().begin()->first;
auto vh = partition->getVolumes().begin()->second;
auto *rawFST = (uint8_t *) malloc(vh->FSTSize);
if (rawFST == nullptr) {
OSFatal("Failed to alloc rawFST");
}
if (!reader->hasDiscKey) {
if (!reader->readEncrypted(rawFST, volumeAddress.getAddressInBytes() + vh->FSTAddress.getAddressInBytes(), vh->FSTSize)) {
std::vector<uint8_t> fstData;
fstData.resize(vh->FSTSize);
if (!discReader->hasDiscKey) {
if (!discReader->readEncrypted(fstData.data(), volumeAddress.getAddressInBytes() + vh->FSTAddress.getAddressInBytes(), vh->FSTSize)) {
OSFatal("WiiUPartition: Failed to read encrypted");
}
} else {
if (!reader->readDecrypted(rawFST, volumeAddress.getAddressInBytes() + vh->FSTAddress.getAddressInBytes(), 0, vh->FSTSize,
reader->discKey, nullptr, true)) {
if (!discReader->readDecrypted(fstData.data(), volumeAddress.getAddressInBytes() + vh->FSTAddress.getAddressInBytes(), 0, vh->FSTSize,
discReader->discKey, nullptr, true)) {
OSFatal("WiiUPartition: Failed to read encrypted");
}
}
FST *fst = new FST(rawFST, vh->FSTSize, 0, vh->blockSize);
free(rawFST);
partitions.push_back(new WiiUDataPartition(partition, fst));
auto fstOpt = FST::make_shared(fstData, 0, vh->blockSize);
if (!fstOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse FST");
return {};
}
partitions.push_back(std::shared_ptr<WiiUPartition>(new WiiUDataPartition(partition, fstOpt.value())));
}
return std::unique_ptr<WiiUPartitions>(new WiiUPartitions(partitions));
}
WiiUPartitions::~WiiUPartitions() {
for (auto &partition: partitions) {
delete partition;
}
}
bool WiiUPartitions::getFSTEntryAsByte(uint8_t **buffer_out, uint32_t *outSize, std::string &filePath, FST *fst, const AddressInDiscBlocks &volumeAddress, DiscReader *discReader) {
NodeEntry *entry = FSTUtils::getFSTEntryByFullPath(fst->nodeEntries->rootEntry, filePath);
auto asFileEntry = dynamic_cast<FileEntry *>(entry);
if (asFileEntry == nullptr) {
return false;
}
SectionEntry *info = asFileEntry->getSectionEntry();
if (info == nullptr) {
OSFatal("WiiUPartitions::getFSTEntryAsByte, section info was null");
}
uint64_t sectionOffsetOnDisc = volumeAddress.getAddressInBytes() + info->address.getAddressInBytes();
auto *buffer = (uint8_t *) malloc(asFileEntry->getSize());
if (buffer == nullptr) {
return false;
}
*buffer_out = buffer;
*outSize = asFileEntry->getSize();
if (!discReader->hasDiscKey) {
return discReader->readEncrypted(buffer, sectionOffsetOnDisc + asFileEntry->getOffset(), asFileEntry->getSize());
}
// Calculating the IV
uint8_t IV[16];
memset(IV, 0, 16);
uint64_t ivTemp = asFileEntry->getOffset() >> 16;
memcpy(IV + 8, &ivTemp, 8);
return discReader->readDecrypted(buffer, sectionOffsetOnDisc, asFileEntry->getOffset(), asFileEntry->getSize(), discReader->discKey, IV, false);
WiiUPartitions::WiiUPartitions(std::vector<std::shared_ptr<WiiUPartition>> pPartitions) : partitions(std::move(pPartitions)) {
DEBUG_FUNCTION_LINE();
}

View File

@ -16,6 +16,7 @@
****************************************************************************/
#pragma once
#include <memory>
#include <cstdint>
#include <utils/blocksize/DiscBlockSize.h>
#include <utils/blocksize/AddressInDiscBlocks.h>
@ -30,13 +31,21 @@
class WiiUPartitions {
public:
static bool getFSTEntryAsByte(uint8_t **buffer_out, uint32_t *outSize, std::string &filePath, FST *fst, const AddressInDiscBlocks &volumeAddress, DiscReader *discReader);
static bool getFSTEntryAsByte(std::string &filePath,
const std::shared_ptr<FST> &fst,
const AddressInDiscBlocks &volumeAddress,
const std::shared_ptr<DiscReader> &discReader,
std::vector<uint8_t> &out_data);
WiiUPartitions(DiscReader *reader, uint32_t offset, uint32_t numberOfPartitions, const DiscBlockSize &blockSize);
std::vector<std::shared_ptr<WiiUPartition>> partitions;
static constexpr uint32_t LENGTH = 30720;
~WiiUPartitions();
std::vector<WiiUPartition *> partitions;
static uint32_t LENGTH;
static std::optional<std::unique_ptr<WiiUPartitions>> make_unique(
const std::shared_ptr<DiscReader> &discReader,
uint32_t offset,
uint32_t numberOfPartitions,
const DiscBlockSize &blockSize);
private:
explicit WiiUPartitions(std::vector<std::shared_ptr<WiiUPartition>> pPartitions);
};

View File

@ -15,58 +15,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <memory>
#include "VolumeHeader.h"
#include <utils/utils.h>
#include <coreinit/debug.h>
#include <utils/logger.h>
uint32_t VolumeHeader::MAGIC = 0xCC93A4F5;
VolumeHeader::VolumeHeader(DiscReader *reader, uint64_t offset) {
auto buffer = (uint8_t *) malloc(64);
if (buffer == nullptr) {
OSFatal("VolumeHeader: failed to alloc buffer");
}
if (!reader->readEncrypted(buffer, offset, 64)) {
OSFatal("VolumeHeader: failed to read");
}
auto *bufferUint = (uint32_t *) buffer;
if (bufferUint[0] != MAGIC) {
OSFatal("VolumeHeader MAGIC mismatch.");
}
blockSize = VolumeBlockSize(bufferUint[1]);
volumeSize = SizeInVolumeBlocks(blockSize, bufferUint[2]);
h3HashArrayListSize = bufferUint[3];
numberOfH3HashArray = bufferUint[4];
FSTSize = bufferUint[5];
FSTAddress = AddressInVolumeBlocks(blockSize, bufferUint[6]);
FSTHashMode = buffer[36];
encryptType = buffer[37];
majorVersion = buffer[38];
minorVersion = buffer[39];
expiringMajorVersion = buffer[40];
free(buffer);
auto bufferH3 = (uint8_t *) malloc(ROUNDUP(h3HashArrayListSize, 16));
if (bufferH3 == nullptr) {
OSFatal("VolumeHeader: failed to alloc h3 buffer");
}
if (!reader->readEncrypted(bufferH3, offset + 64, ROUNDUP(h3HashArrayListSize, 16))) {
OSFatal("VolumeHeader: failed to read h3");
}
h3HashArrayList = getH3HashArray(bufferH3, numberOfH3HashArray, h3HashArrayListSize);
free(bufferH3);
}
std::vector<H3HashArray *> VolumeHeader::getH3HashArray(uint8_t *h3Data, uint32_t pNumberOfH3HashArray, uint32_t pH3HashArrayListSize) {
std::vector<H3HashArray *> arrayList;
std::vector<std::shared_ptr<H3HashArray>> VolumeHeader::getH3HashArray(uint8_t *h3Data, uint32_t pNumberOfH3HashArray, uint32_t pH3HashArrayListSize) {
std::vector<std::shared_ptr<H3HashArray>> arrayList;
if (pNumberOfH3HashArray == 0) {
return arrayList;
}
@ -80,15 +37,93 @@ std::vector<H3HashArray *> VolumeHeader::getH3HashArray(uint8_t *h3Data, uint32_
curEnd = offsetPtr[1];
}
arrayList.push_back(new H3HashArray(h3Data + curOffset, curEnd - curOffset));
arrayList.push_back(std::make_shared<H3HashArray>(h3Data + curOffset, curEnd - curOffset));
}
return arrayList;
}
VolumeHeader::~VolumeHeader() {
for (auto &h3: h3HashArrayList) {
delete h3;
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");
return {};
}
if (!discReader->readEncrypted(buffer, offset, 64)) {
free(buffer);
DEBUG_FUNCTION_LINE("Failed to read data");
return {};
}
auto *bufferUint = (uint32_t *) buffer;
if (bufferUint[0] != MAGIC) {
DEBUG_FUNCTION_LINE("MAGIC mismatch");
free(buffer);
return {};
}
auto blockSize = VolumeBlockSize(bufferUint[1]);
auto volumeSize = SizeInVolumeBlocks(blockSize, bufferUint[2]);
auto h3HashArrayListSize = bufferUint[3];
auto numberOfH3HashArray = bufferUint[4];
auto FSTSize = bufferUint[5];
auto FSTAddress = AddressInVolumeBlocks(blockSize, bufferUint[6]);
auto FSTHashMode = buffer[36];
auto encryptType = buffer[37];
auto majorVersion = buffer[38];
auto minorVersion = buffer[39];
auto expiringMajorVersion = buffer[40];
DEBUG_FUNCTION_LINE("FSTSize: %08X", FSTSize);
free(buffer);
auto bufferH3 = (uint8_t *) malloc(ROUNDUP(h3HashArrayListSize, 16));
if (bufferH3 == nullptr) {
DEBUG_FUNCTION_LINE("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);
return {};
}
auto h3HashArrayList = getH3HashArray(bufferH3, numberOfH3HashArray, h3HashArrayListSize);
free(bufferH3);
return std::unique_ptr<VolumeHeader>(
new VolumeHeader(blockSize, volumeSize, FSTSize, FSTAddress, FSTHashMode, encryptType, majorVersion, minorVersion, expiringMajorVersion, h3HashArrayList, h3HashArrayListSize,
numberOfH3HashArray));
}
VolumeHeader::VolumeHeader(const VolumeBlockSize &pBlockSize,
SizeInVolumeBlocks pVolumeSize,
uint32_t pFSTSize,
AddressInVolumeBlocks pFSTAddress,
uint8_t pFSTHashMode,
uint8_t pEncryptType,
uint8_t pMajorVersion,
uint8_t pMinorVersion,
uint8_t pExpiringMajorVersion,
std::vector<std::shared_ptr<H3HashArray>> pH3HashArrayList,
uint32_t pH3HashArrayListSize,
uint32_t pNumberOfH3HashArray) : blockSize(pBlockSize),
volumeSize(std::move(pVolumeSize)),
FSTSize(pFSTSize),
FSTAddress(std::move(pFSTAddress)),
FSTHashMode(pFSTHashMode),
encryptType(pEncryptType),
majorVersion(pMajorVersion),
minorVersion(pMinorVersion),
expiringMajorVersion(pExpiringMajorVersion),
h3HashArrayList(std::move(pH3HashArrayList)),
h3HashArrayListSize(pH3HashArrayListSize),
numberOfH3HashArray(pNumberOfH3HashArray) {
}

View File

@ -16,22 +16,21 @@
****************************************************************************/
#pragma once
#include <utility>
#include <vector>
#include <cstdint>
#include <WUD/DiscReader.h>
#include <utils/blocksize/VolumeBlockSize.h>
#include <utils/blocksize/AddressInVolumeBlocks.h>
#include <utils/blocksize/SizeInVolumeBlocks.h>
#include <optional>
#include <utils/utils.h>
#include "H3HashArray.h"
class VolumeHeader {
public:
static std::vector<H3HashArray *> getH3HashArray(uint8_t *h3Data, uint32_t numberOfH3HashArray, uint32_t h3HashArrayListSize);
VolumeHeader(DiscReader *reader, uint64_t offset);
~VolumeHeader();
static std::vector<std::shared_ptr<H3HashArray>> getH3HashArray(uint8_t *h3Data, uint32_t numberOfH3HashArray, uint32_t h3HashArrayListSize);
static uint32_t MAGIC;
VolumeBlockSize blockSize;
@ -43,8 +42,26 @@ public:
uint8_t majorVersion;
uint8_t minorVersion;
uint8_t expiringMajorVersion;
std::vector<H3HashArray *> h3HashArrayList;
std::vector<std::shared_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);
private:
VolumeHeader(
const VolumeBlockSize &pBlockSize,
SizeInVolumeBlocks pVolumeSize,
uint32_t pFSTSize,
AddressInVolumeBlocks pFSTAddress,
uint8_t pFSTHashMode,
uint8_t pEncryptType,
uint8_t pMajorVersion,
uint8_t pMinorVersion,
uint8_t pExpiringMajorVersion,
std::vector<std::shared_ptr<H3HashArray>> pH3HashArrayList,
uint32_t pH3HashArrayListSize,
uint32_t pNumberOfH3HashArray);
};

View File

@ -15,33 +15,80 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "FST.h"
#include <algorithm>
FST::FST(uint8_t *data, uint32_t fstSize, uint32_t offset, const VolumeBlockSize &blockSize) {
std::shared_ptr<RootEntry> FST::getRootEntry() const {
return nodeEntries->getRootEntry();
}
std::optional<std::shared_ptr<FST>> FST::make_shared(const std::vector<uint8_t> &data, uint32_t offset, const VolumeBlockSize &blockSize) {
uint32_t curOffset = offset;
header = new FSTHeader(data + curOffset);
curOffset += header->LENGTH;
if (curOffset + FSTHeader::LENGTH > data.size()) {
DEBUG_FUNCTION_LINE("Not enough data to parse the FSTHeader");
return {};
}
sectionEntries = new SectionEntries(data + curOffset, header->numberOfSections, blockSize);
curOffset += sectionEntries->getSizeInBytes();
std::array<uint8_t, FSTHeader::LENGTH> fstData{};
std::copy_n(data.begin() + (int) curOffset, FSTHeader::LENGTH, fstData.begin());
uint32_t lastEntryNumber = RootEntry::parseLastEntryNumber(data, curOffset);
auto headerOpt = FSTHeader::make_unique(fstData);
if (!headerOpt.has_value()) {
DEBUG_FUNCTION_LINE("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");
return {};
}
std::vector<uint8_t> sectionEntriesData;
sectionEntriesData.resize(sectionEntriesDataSize);
std::copy_n(data.begin() + (int) curOffset, sectionEntriesDataSize, sectionEntriesData.begin());
auto sectionEntriesOpt = SectionEntries::make_shared(sectionEntriesData, headerOpt.value()->numberOfSections, blockSize);
if (!sectionEntriesOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse FSTHeader");
return {};
}
curOffset += sectionEntriesOpt.value()->getSizeInBytes();
std::array<uint8_t, NodeEntry::LENGTH> rootEntry{};
std::copy_n(data.begin() + (int) curOffset, NodeEntry::LENGTH, rootEntry.begin());
uint32_t lastEntryNumber = RootEntry::parseLastEntryNumber(rootEntry);
auto stringTableOffset = curOffset + (lastEntryNumber * 16);
stringTable = StringTable::parseData(data, fstSize - stringTableOffset, stringTableOffset, lastEntryNumber);
auto stringTableOpt = StringTable::make_shared(data, stringTableOffset, lastEntryNumber);
if (!stringTableOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse StringTable");
return {};
}
nodeEntries = NodeEntries::parseData(data, curOffset, sectionEntries, stringTable, header->blockSize);
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");
return {};
}
return std::shared_ptr<FST>(new FST(
std::move(headerOpt.value()),
std::move(sectionEntriesOpt.value()),
std::move(stringTableOpt.value()),
std::move(nodeEntriesOpt.value())));
}
FST::~FST() {
delete nodeEntries;
delete stringTable;
delete sectionEntries;
delete header;
}
FST::FST(std::unique_ptr<FSTHeader> pHeader,
std::shared_ptr<SectionEntries> pSectionEntries,
std::shared_ptr<StringTable> pStringTable,
std::unique_ptr<NodeEntries> pNodeEntries) :
sectionEntries(std::move(pSectionEntries)),
stringTable(std::move(pStringTable)),
nodeEntries(std::move(pNodeEntries)),
header(std::move(pHeader)) {
RootEntry *FST::getRootEntry() const {
return nodeEntries->rootEntry;
}

View File

@ -16,7 +16,10 @@
****************************************************************************/
#pragma once
#include <optional>
#include <memory>
#include <cstdint>
#include <utility>
#include <WUD/entities/FST/header/FSTHeader.h>
#include <WUD/entities/FST/sectionentry/SectionEntries.h>
#include <WUD/entities/FST/stringtable/StringTable.h>
@ -24,16 +27,20 @@
#include <WUD/entities/FST/nodeentry/RootEntry.h>
class FST {
public:
FST(uint8_t *data, uint32_t fstSize, uint32_t offset, const VolumeBlockSize &blockSize);
[[nodiscard]] std::shared_ptr<RootEntry> getRootEntry() const;
~FST();
static std::optional<std::shared_ptr<FST>> make_shared(const std::vector<uint8_t> &data, uint32_t offset, const VolumeBlockSize &blockSize);
FSTHeader *header;
SectionEntries *sectionEntries;
StringTable *stringTable;
NodeEntries *nodeEntries;
std::shared_ptr<SectionEntries> sectionEntries;
private:
FST(std::unique_ptr<FSTHeader> pHeader,
std::shared_ptr<SectionEntries> pSectionEntries,
std::shared_ptr<StringTable> pStringTable,
std::unique_ptr<NodeEntries> pNodeEntries
);
[[nodiscard]] RootEntry *getRootEntry() const;
std::shared_ptr<StringTable> stringTable;
std::unique_ptr<NodeEntries> nodeEntries;
std::unique_ptr<FSTHeader> header;
};

View File

@ -15,16 +15,31 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <utils/blocksize/SectionBlockSize.h>
#include <coreinit/debug.h>
#include <utils/logger.h>
#include "FSTHeader.h"
FSTHeader::FSTHeader(uint8_t *data) {
auto *dataAsUint = (uint32_t *) data;
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) {
OSFatal("FST Header magic was wrong");
DEBUG_FUNCTION_LINE("FST Header magic was wrong");
return {};
}
FSTVersion = data[3];
blockSize = SectionBlockSize(dataAsUint[1]);
numberOfSections = dataAsUint[2];
hashDisabled = data[12];
auto FSTVersion = data[3];
auto blockSize = SectionBlockSize(dataAsUint[1]);
auto numberOfSections = dataAsUint[2];
auto hashDisabled = data[12];
return std::unique_ptr<FSTHeader>(new FSTHeader(
FSTVersion,
blockSize,
numberOfSections,
hashDisabled
));
}
FSTHeader::FSTHeader(uint8_t pFSTVersion, SectionBlockSize pBlockSize, uint32_t pNumberOfSections, uint8_t pHashDisabled) : FSTVersion(pFSTVersion),
blockSize(pBlockSize),
numberOfSections(pNumberOfSections),
hashDisabled(pHashDisabled) {
}

View File

@ -16,20 +16,24 @@
****************************************************************************/
#pragma once
#include <optional>
#include <memory>
#include <cstdint>
#include <utils/blocksize/SectionBlockSize.h>
class FSTHeader {
public:
explicit FSTHeader(uint8_t *data);
static constexpr uint32_t LENGTH = 32;
~FSTHeader() = default;
static std::optional<std::unique_ptr<FSTHeader>> make_unique(const std::array<uint8_t, FSTHeader::LENGTH> &data);
uint8_t FSTVersion;
SectionBlockSize blockSize;
uint8_t hashDisabled;
uint32_t numberOfSections;
uint32_t LENGTH = 32;
uint8_t hashDisabled;
private:
FSTHeader(uint8_t pFSTVersion, SectionBlockSize pBlockSize, uint32_t pNumberOfSections, uint8_t pHashDisabled);
};

View File

@ -17,56 +17,48 @@
#include <coreinit/debug.h>
#include "DirectoryEntry.h"
DirectoryEntry *DirectoryEntry::parseData(const uint8_t *data, NodeEntryParam param, SectionEntries *sectionEntries, StringTable *stringTable) {
auto *directoryEntry = new DirectoryEntry();
directoryEntry->entryNumber = param.entryNumber;
directoryEntry->parent = param.parent;
directoryEntry->entryType = param.type;
directoryEntry->nameString = stringTable->getStringEntry(param.uint24);
if (directoryEntry->nameString == nullptr) {
OSFatal("Failed to find string for offset");
std::optional<std::shared_ptr<DirectoryEntry>>
DirectoryEntry::parseData(const std::array<uint8_t, NodeEntry::LENGTH> &data, const NodeEntryParam &param, const std::shared_ptr<SectionEntries> &sectionEntries,
const std::shared_ptr<StringTable> &stringTable) {
auto parentEntryNumber = ((uint32_t *) &data[4])[0];
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");
return {};
}
directoryEntry->parentEntryNumber = ((uint32_t *) &data[4])[0];
directoryEntry->lastEntryNumber = ((uint32_t *) &data[8])[0];
directoryEntry->permission = param.permission;
if (param.sectionNumber > sectionEntries->size()) {
OSFatal("section number does not match");
auto sectionEntryOpt = sectionEntries->getSection(param.sectionNumber);
if (!sectionEntryOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to get section entry");
return {};
}
directoryEntry->sectionEntry = sectionEntries->getSection(param.sectionNumber);
return directoryEntry;
return std::unique_ptr<DirectoryEntry>(new DirectoryEntry(param, stringNameOpt.value(), sectionEntryOpt.value(), parentEntryNumber, lastEntryNumber));
}
DirectoryEntry::~DirectoryEntry() {
for (auto &child: children) {
delete child;
}
}
std::vector<DirectoryEntry *> DirectoryEntry::getDirChildren() const {
std::vector<DirectoryEntry *> res;
std::vector<std::shared_ptr<DirectoryEntry>> DirectoryEntry::getDirChildren() const {
std::vector<std::shared_ptr<DirectoryEntry>> res;
for (auto &cur: children) {
if (cur->isDirectory()) {
res.push_back(dynamic_cast<DirectoryEntry *>(cur));
res.push_back(std::dynamic_pointer_cast<DirectoryEntry>(cur));
}
}
return res;
}
std::vector<FileEntry *> DirectoryEntry::getFileChildren() const {
std::vector<FileEntry *> res;
std::vector<std::shared_ptr<FileEntry>> DirectoryEntry::getFileChildren() const {
std::vector<std::shared_ptr<FileEntry>> res;
for (auto &cur: children) {
if (cur->isFile()) {
res.push_back(dynamic_cast<FileEntry *>(cur));
res.push_back(std::dynamic_pointer_cast<FileEntry>(cur));
}
}
return res;
}
std::vector<NodeEntry *> DirectoryEntry::getChildren() const {
std::vector<std::shared_ptr<NodeEntry>> DirectoryEntry::getChildren() const {
return children;
}
@ -77,6 +69,33 @@ void DirectoryEntry::printPathRecursive() {
}
}
void DirectoryEntry::addChild(NodeEntry *entry) {
void DirectoryEntry::addChild(const std::shared_ptr<NodeEntry> &entry) {
children.push_back(entry);
}
DirectoryEntry::DirectoryEntry(const NodeEntryParam &param,
const std::shared_ptr<StringEntry> &pStringEntry,
const std::shared_ptr<SectionEntry> &pSectionEntry,
uint32_t pParentEntryNumber,
uint32_t pLastEntryNumber) :
NodeEntry(param.permission,
pStringEntry,
pSectionEntry,
param.parent,
param.type,
param.entryNumber),
parentEntryNumber(pParentEntryNumber),
lastEntryNumber(pLastEntryNumber) {
}
DirectoryEntry::DirectoryEntry(const std::shared_ptr<DirectoryEntry> &input) :
NodeEntry(input->permission,
input->nameString,
input->sectionEntry,
input->parent,
input->entryType,
input->entryNumber),
parentEntryNumber(input->parentEntryNumber),
lastEntryNumber(input->lastEntryNumber) {
}

View File

@ -23,24 +23,35 @@
#include "FileEntry.h"
class DirectoryEntry : public NodeEntry {
public:
~DirectoryEntry() override;
static DirectoryEntry *parseData(const uint8_t *data, NodeEntryParam param, SectionEntries *sectionEntries, StringTable *stringTable);
static std::optional<std::shared_ptr<DirectoryEntry>>
parseData(const std::array<uint8_t, NodeEntry::LENGTH> &data,
const NodeEntryParam &param,
const std::shared_ptr<SectionEntries> &sectionEntries,
const std::shared_ptr<StringTable> &stringTable);
uint32_t parentEntryNumber{};
uint32_t lastEntryNumber{};
std::vector<NodeEntry *> children;
std::vector<std::shared_ptr<NodeEntry>> children;
void addChild(NodeEntry *entry);
void addChild(const std::shared_ptr<NodeEntry> &entry);
[[nodiscard]] std::vector<DirectoryEntry *> getDirChildren() const;
[[nodiscard]] std::vector<std::shared_ptr<DirectoryEntry>> getDirChildren() const;
[[nodiscard]] std::vector<FileEntry *> getFileChildren() const;
[[nodiscard]] std::vector<std::shared_ptr<FileEntry>> getFileChildren() const;
[[nodiscard]] std::vector<NodeEntry *> getChildren() const;
[[nodiscard]] std::vector<std::shared_ptr<NodeEntry>> getChildren() const;
void printPathRecursive() override;
protected:
explicit DirectoryEntry(const std::shared_ptr<DirectoryEntry> &input);
private:
DirectoryEntry(
const NodeEntryParam &param,
const std::shared_ptr<StringEntry> &stringEntry,
const std::shared_ptr<SectionEntry> &sectionEntry,
uint32_t parentEntryNumber,
uint32_t lastEntryNumber);
};

View File

@ -20,30 +20,32 @@
#include <utility>
FileEntry::FileEntry(SectionAddress address) : address(std::move(address)) {
}
std::optional<std::shared_ptr<NodeEntry>>
FileEntry::parseData(const std::array<uint8_t, NodeEntry::LENGTH> &data,
const NodeEntryParam &param,
const std::shared_ptr<SectionEntries> &sectionEntries,
const std::shared_ptr<StringTable> &stringTable,
const SectionBlockSize &blockSize) {
auto size = ((uint32_t *) &data[8])[0];
auto offset = SectionAddress(blockSize, ((uint32_t *) &data[4])[0]);
NodeEntry *FileEntry::parseData(uint8_t *data, NodeEntryParam param, SectionEntries *sectionEntries, StringTable *stringTable, const SectionBlockSize &blockSize) {
auto *entry = new FileEntry(SectionAddress(blockSize, ((uint32_t *) &data[4])[0]));
entry->entryNumber = param.entryNumber;
entry->parent = param.parent;
entry->entryType = param.type;
entry->nameString = stringTable->getStringEntry(param.uint24);
if (entry->nameString == nullptr) {
OSFatal("Failed to find string for offset");
auto stringNameOpt = stringTable->getStringEntry(param.uint24);
if (!stringNameOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to get string name");
return {};
}
entry->size = ((uint32_t *) &data[8])[0];
auto sectionEntryOpt = sectionEntries->getSection(param.sectionNumber);
if (!sectionEntryOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to get section entry");
return {};
}
entry->permission = param.permission;
entry->sectionEntry = sectionEntries->getSection(param.sectionNumber);
return entry;
return std::shared_ptr<FileEntry>(new FileEntry(param, stringNameOpt.value(), sectionEntryOpt.value(), size, offset));
}
SectionEntry *FileEntry::getSectionEntry() {
std::shared_ptr<SectionEntry> FileEntry::getSectionEntry() {
return sectionEntry;
}
@ -54,3 +56,19 @@ uint64_t FileEntry::getOffset() const {
uint32_t FileEntry::getSize() const {
return size;
}
FileEntry::FileEntry(
const NodeEntryParam &param,
const std::shared_ptr<StringEntry> &pStringEntry,
const std::shared_ptr<SectionEntry> &pSectionEntry,
uint32_t pSize, SectionAddress pAddress) :
NodeEntry(param.permission,
pStringEntry,
pSectionEntry,
param.parent,
param.type,
param.entryNumber),
address(std::move(pAddress)),
size(pSize) {
}

View File

@ -23,19 +23,29 @@
class FileEntry : public NodeEntry {
public:
explicit FileEntry(SectionAddress address);
static NodeEntry *parseData(uint8_t *data, NodeEntryParam param, SectionEntries *sectionEntries, StringTable *stringTable, const SectionBlockSize &blockSize);
static std::optional<std::shared_ptr<NodeEntry>>
parseData(const std::array<uint8_t, NodeEntry::LENGTH> &data,
const NodeEntryParam &param,
const std::shared_ptr<SectionEntries> &sectionEntries,
const std::shared_ptr<StringTable> &stringTable,
const SectionBlockSize &blockSize);
~FileEntry() override = default;
SectionEntry *getSectionEntry();
std::shared_ptr<SectionEntry> getSectionEntry();
[[nodiscard]] uint64_t getOffset() const;
[[nodiscard]] uint32_t getSize() const;
private:
FileEntry(const NodeEntryParam &param,
const std::shared_ptr<StringEntry> &pStringEntry,
const std::shared_ptr<SectionEntry> &pSectionEntry,
uint32_t pSize,
SectionAddress offset);
SectionAddress address;
uint32_t size{};
};

View File

@ -17,25 +17,30 @@
#include <coreinit/debug.h>
#include "NodeEntries.h"
NodeEntries::NodeEntries(RootEntry *pEntry) {
rootEntry = pEntry;
}
NodeEntries::~NodeEntries() {
delete rootEntry;
}
NodeEntry *NodeEntries::DeserializeImpl(uint8_t *data, uint32_t offset, DirectoryEntry *parent, uint32_t entryNumber, SectionEntries *sectionEntries, StringTable *stringTable,
const SectionBlockSize &blockSize) {
NodeEntry *nodeEntry = NodeEntry::AutoDeserialize(data, offset, parent, entryNumber, sectionEntries, stringTable, blockSize);
auto asDirEntry = dynamic_cast<DirectoryEntry *>(nodeEntry);
std::optional<std::shared_ptr<NodeEntry>> NodeEntries::DeserializeImpl(const std::vector<uint8_t> &pData,
uint32_t pOffset,
const std::optional<std::shared_ptr<DirectoryEntry>> &pParent,
uint32_t pEntryNumber,
const std::shared_ptr<SectionEntries> &pSectionEntries,
const std::shared_ptr<StringTable> &pStringTable,
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");
return {};
}
auto asDirEntry = std::dynamic_pointer_cast<DirectoryEntry>(nodeEntry.value());
if (asDirEntry != nullptr) {
uint32_t curEntryNumber = asDirEntry->entryNumber + 1;
while (curEntryNumber < asDirEntry->lastEntryNumber) {
NodeEntry *entry = NodeEntries::DeserializeImpl(data, offset + (curEntryNumber - asDirEntry->entryNumber) * NodeEntry::LENGTH,
asDirEntry, curEntryNumber, sectionEntries, stringTable, blockSize);
asDirEntry->addChild(entry);
auto *childAsDir = dynamic_cast<DirectoryEntry *>(entry);
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");
return {};
}
asDirEntry->addChild(entry.value());
auto childAsDir = std::dynamic_pointer_cast<DirectoryEntry>(entry.value());
if (childAsDir != nullptr) {
curEntryNumber = childAsDir->lastEntryNumber;
} else {
@ -46,12 +51,26 @@ NodeEntry *NodeEntries::DeserializeImpl(uint8_t *data, uint32_t offset, Director
return nodeEntry;
}
NodeEntries *NodeEntries::parseData(unsigned char *data, uint32_t offset, SectionEntries *sectionEntries, StringTable *stringTable, const SectionBlockSize &blockSize) {
NodeEntry *rootEntry = NodeEntries::DeserializeImpl(data, offset, (DirectoryEntry *) nullptr, 0, sectionEntries, stringTable, blockSize);
auto rootEntryCasted = dynamic_cast<RootEntry *>(rootEntry);
if (rootEntryCasted != nullptr) {
return new NodeEntries(rootEntryCasted);
std::optional<std::unique_ptr<NodeEntries>>
NodeEntries::make_unique(const std::vector<uint8_t> &data, uint32_t offset, const std::shared_ptr<SectionEntries> &pSectionEntries, const std::shared_ptr<StringTable> &pStringTable,
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");
return {};
}
OSFatal("Failed to parse Root");
return nullptr;
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");
return {};
}
std::shared_ptr<RootEntry> NodeEntries::getRootEntry() const {
return rootEntry;
}
NodeEntries::NodeEntries(const std::shared_ptr<RootEntry> &pEntry) {
rootEntry = pEntry;
}

View File

@ -19,6 +19,8 @@
#include <WUD/entities/FST/stringtable/StringTable.h>
#include <utils/blocksize/SectionBlockSize.h>
#include <WUD/entities/FST/sectionentry/SectionEntries.h>
#include <utility>
#include "DirectoryEntry.h"
#include "RootEntry.h"
#include "NodeEntry.h"
@ -27,14 +29,32 @@
class NodeEntries {
public:
explicit NodeEntries(RootEntry *pEntry);
~NodeEntries();
virtual ~NodeEntries() {
DEBUG_FUNCTION_LINE("Bye");
}
static NodeEntry *
DeserializeImpl(unsigned char *data, uint32_t offset, DirectoryEntry *parent, uint32_t entryNumber, SectionEntries *sectionEntries, StringTable *stringTable, const SectionBlockSize &blockSize);
static std::optional<std::shared_ptr<NodeEntry>>
DeserializeImpl(const std::vector<uint8_t> &data,
uint32_t offset,
const std::optional<std::shared_ptr<DirectoryEntry>> &pParent,
uint32_t entryNumber,
const std::shared_ptr<SectionEntries> &sectionEntries,
const std::shared_ptr<StringTable> &stringTable,
const SectionBlockSize &blockSize);
static NodeEntries *parseData(unsigned char *data, uint32_t offset, SectionEntries *sectionEntries, StringTable *stringTable, const SectionBlockSize &blockSize);
static std::optional<std::unique_ptr<NodeEntries>>
make_unique(const std::vector<uint8_t> &data,
uint32_t offset,
const std::shared_ptr<SectionEntries> &sectionEntries,
const std::shared_ptr<StringTable> &stringTable,
const SectionBlockSize &blockSize);
RootEntry *rootEntry;
[[nodiscard]] std::shared_ptr<RootEntry> getRootEntry() const;
private:
explicit NodeEntries(const std::shared_ptr<RootEntry> &pEntry);
std::shared_ptr<RootEntry> rootEntry;
};

View File

@ -17,16 +17,26 @@
#include <utils/blocksize/SectionBlockSize.h>
#include <WUD/entities/FST/stringtable/StringTable.h>
#include <WUD/entities/FST/sectionentry/SectionEntries.h>
#include <coreinit/debug.h>
#include <algorithm>
#include <utility>
#include "NodeEntry.h"
#include "DirectoryEntry.h"
#include "RootEntry.h"
uint32_t NodeEntry::LENGTH = 16;
NodeEntry *NodeEntry::AutoDeserialize(uint8_t *data, uint32_t offset, DirectoryEntry *pParent, uint32_t eEntryNumber, SectionEntries *sectionEntries,
StringTable *stringTable, const SectionBlockSize &blockSize) {
uint8_t *curEntryData = &data[offset];
std::optional<std::shared_ptr<NodeEntry>>
NodeEntry::AutoDeserialize(const std::vector<uint8_t> &data,
uint32_t offset,
const std::optional<std::shared_ptr<DirectoryEntry>> &pParent,
uint32_t eEntryNumber,
const std::shared_ptr<SectionEntries> &sectionEntries,
const std::shared_ptr<StringTable> &stringTable,
const SectionBlockSize &blockSize) {
if (offset + NodeEntry::LENGTH >= data.size()) {
return {};
}
std::array<uint8_t, NodeEntry::LENGTH> curEntryData{};
std::copy_n(data.begin() + (int) offset, NodeEntry::LENGTH, curEntryData.begin());
NodeEntryParam param{};
param.permission = ((uint16_t *) &curEntryData[12])[0];
@ -34,41 +44,68 @@ NodeEntry *NodeEntry::AutoDeserialize(uint8_t *data, uint32_t offset, DirectoryE
param.entryNumber = eEntryNumber;
param.parent = pParent;
param.type = curEntryData[0];
param.uint24 = ((uint32_t *) curEntryData)[0] & 0x00FFFFFF;
param.uint24 = ((uint32_t *) &curEntryData[0])[0] & 0x00FFFFFF;
if ((param.type & ENTRY_TYPE_Directory) == ENTRY_TYPE_Directory && param.uint24 == 0) { // Root
return (NodeEntry *) RootEntry::parseData(curEntryData, param, sectionEntries, stringTable);
auto res = RootEntry::parseData(curEntryData, param, sectionEntries, stringTable);
if (!res.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse node");
return {};
}
return res;
} else if ((param.type & ENTRY_TYPE_Directory) == ENTRY_TYPE_Directory) {
return (NodeEntry *) DirectoryEntry::parseData(curEntryData, param, sectionEntries, stringTable);
auto res = DirectoryEntry::parseData(curEntryData, param, sectionEntries, stringTable);
if (!res.has_value()) {
DEBUG_FUNCTION_LINE("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");
return {};
}
return resAsNodeEntry;
} else if ((param.type & ENTRY_TYPE_File) == ENTRY_TYPE_File) {
return (NodeEntry *) FileEntry::parseData(curEntryData, param, sectionEntries, stringTable, blockSize);
auto res = FileEntry::parseData(curEntryData, param, sectionEntries, stringTable, blockSize);
if (!res.has_value()) {
DEBUG_FUNCTION_LINE("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");
return {};
}
return resAsNodeEntry;
}
OSFatal("FST Unknown Node Type");
return nullptr;
DEBUG_FUNCTION_LINE("FST Unknown Node Type");
return {};
}
std::string NodeEntry::getName() const &{
if (nameString != nullptr) {
return nameString->toString();
std::string NodeEntry::getName() {
auto res = nameString->toString();
if (res.has_value()) {
return res.value();
}
return "ERROR";
return "[ERROR]";
}
std::string NodeEntry::getFullPathInternal() const &{
if (parent != nullptr) {
return parent->getFullPathInternal().append("/").append(getName());
std::string NodeEntry::getFullPathInternal() {
if (parent.has_value()) {
return parent.value()->getFullPathInternal().append("/").append(getName());
}
return getName();
}
std::string NodeEntry::getFullPath() const &{
std::string NodeEntry::getFullPath() {
return getFullPathInternal();
}
std::string NodeEntry::getPath() const &{
if (parent != nullptr) {
return parent->getFullPath().append("/");
std::string NodeEntry::getPath() {
if (parent.has_value()) {
return parent.value()->getFullPath().append("/");
}
return "/";
}
@ -81,3 +118,22 @@ bool NodeEntry::isDirectory() const {
bool NodeEntry::isFile() const {
return (entryType & ENTRY_TYPE_File) == ENTRY_TYPE_File;
}
NodeEntry::NodeEntry(const uint16_t pPermission,
std::shared_ptr<StringEntry> pNameString,
std::shared_ptr<SectionEntry> pSectionEntry,
std::optional<std::shared_ptr<DirectoryEntry>> pParent,
const uint8_t pType, const uint32_t pEntryNumber) :
permission(pPermission),
nameString(std::move(pNameString)),
sectionEntry(std::move(pSectionEntry)),
parent(std::move(pParent)),
entryType(pType),
entryNumber(pEntryNumber) {
}
void NodeEntry::printPathRecursive() {
DEBUG_FUNCTION_LINE("%s", getFullPath().c_str());
}

View File

@ -34,32 +34,43 @@ class NodeEntry {
public:
uint16_t permission{};
StringEntry *nameString{};
SectionEntry *sectionEntry{};
DirectoryEntry *parent{};
std::shared_ptr<StringEntry> nameString;
std::shared_ptr<SectionEntry> sectionEntry;
std::optional<std::shared_ptr<DirectoryEntry>> parent;
uint8_t entryType{};
uint32_t entryNumber{};
static NodeEntry *AutoDeserialize(uint8_t *data, uint32_t offset, DirectoryEntry *pParent, uint32_t eEntryNumber, SectionEntries *sectionEntries,
StringTable *stringTable, const SectionBlockSize &blockSize);
static std::optional<std::shared_ptr<NodeEntry>>
AutoDeserialize(const std::vector<uint8_t> &data,
uint32_t offset,
const std::optional<std::shared_ptr<DirectoryEntry>> &pParent,
uint32_t eEntryNumber,
const std::shared_ptr<SectionEntries> &sectionEntries,
const std::shared_ptr<StringTable> &stringTable, const SectionBlockSize &blockSize);
virtual ~NodeEntry() = default;
virtual void printPathRecursive() {
DEBUG_FUNCTION_LINE("%s", getFullPath().c_str());
}
virtual void printPathRecursive();
[[nodiscard]] std::string getFullPath() const &;
[[nodiscard]] std::string getFullPath();
[[nodiscard]] std::string getPath() const &;
[[nodiscard]] std::string getPath();
[[nodiscard]] std::string getName() const &;
[[nodiscard]] std::string getName();
[[nodiscard]] bool isDirectory() const;
[[nodiscard]] bool isFile() const;
static uint32_t LENGTH;
private:
[[nodiscard]] std::string getFullPathInternal() const &;
static constexpr uint32_t LENGTH = 16;
[[nodiscard]] std::string getFullPathInternal();
protected:
NodeEntry(uint16_t pPermission,
std::shared_ptr<StringEntry> pNameString,
std::shared_ptr<SectionEntry> pSectionEntry,
std::optional<std::shared_ptr<DirectoryEntry>> pParent,
uint8_t pType,
uint32_t pEntryNumber);
};

View File

@ -24,7 +24,7 @@ class NodeEntryParam {
public:
uint16_t sectionNumber;
uint32_t entryNumber;
DirectoryEntry *parent;
std::optional<std::shared_ptr<DirectoryEntry>> parent;
uint16_t permission;
uint8_t type;
uint32_t uint24;

View File

@ -17,29 +17,28 @@
#include <coreinit/debug.h>
#include "RootEntry.h"
RootEntry::RootEntry(DirectoryEntry *input) {
if ((input->entryType & ENTRY_TYPE_Directory) != ENTRY_TYPE_Directory || input->entryNumber != 0) {
OSFatal("Input is no root entry.");
RootEntry::RootEntry(const std::shared_ptr<DirectoryEntry> &input) : DirectoryEntry(input) {
}
uint32_t RootEntry::parseLastEntryNumber(const std::array<uint8_t, NodeEntry::LENGTH> &data) {
return ((uint32_t *) &data[8])[0];
}
std::optional<std::shared_ptr<NodeEntry>>
RootEntry::parseData
(const std::array<uint8_t, NodeEntry::LENGTH> &data,
const NodeEntryParam &param,
const std::shared_ptr<SectionEntries> &sectionEntries,
const std::shared_ptr<StringTable> &stringTable) {
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.");
return {};
}
return std::shared_ptr<NodeEntry>(new RootEntry(dir.value()));
}
entryNumber = input->entryNumber;
parent = input->parent;
nameString = input->nameString;
if (nameString == nullptr) {
OSFatal("nameString was null");
}
entryType = input->entryType;
parentEntryNumber = input->parentEntryNumber;
lastEntryNumber = input->lastEntryNumber;
permission = input->permission;
sectionEntry = input->sectionEntry;
}
uint32_t RootEntry::parseLastEntryNumber(uint8_t *data, uint32_t offset) {
return ((uint32_t *) &data[8 + offset])[0];
}
RootEntry *RootEntry::parseData(uint8_t *data, NodeEntryParam param, SectionEntries *sectionEntries, StringTable *stringTable) {
return new RootEntry(DirectoryEntry::parseData(data, param, sectionEntries, stringTable));
DEBUG_FUNCTION_LINE("Failed to parse dir");
return {};
}

View File

@ -24,13 +24,17 @@
class RootEntry : public DirectoryEntry {
explicit RootEntry(DirectoryEntry *input);
public:
~RootEntry() override = default;
static RootEntry *parseData(uint8_t *data, NodeEntryParam param, SectionEntries *sectionEntries, StringTable *stringTable);
static std::optional<std::shared_ptr<NodeEntry>>
parseData(const std::array<uint8_t, NodeEntry::LENGTH> &data,
const NodeEntryParam &param,
const std::shared_ptr<SectionEntries> &sectionEntries,
const std::shared_ptr<StringTable> &stringTable);
static uint32_t parseLastEntryNumber(uint8_t *data, uint32_t offset);
static uint32_t parseLastEntryNumber(const std::array<uint8_t, NodeEntry::LENGTH> &data);
private:
explicit RootEntry(const std::shared_ptr<DirectoryEntry> &input);
};

View File

@ -16,25 +16,41 @@
****************************************************************************/
#include "SectionEntries.h"
SectionEntries::SectionEntries(uint8_t *data, uint32_t numberOfSections, const VolumeBlockSize &pBlockSize) {
for (uint32_t i = 0; i < numberOfSections; i++) {
list.push_back(new SectionEntry(data + (i * 32), i, pBlockSize));
}
}
SectionEntry *SectionEntries::getSection(uint16_t sectionNumber) const {
std::optional<std::shared_ptr<SectionEntry>> SectionEntries::getSection(uint16_t sectionNumber) const {
for (auto const &e: list) {
if (e->sectionNumber == sectionNumber) {
return e;
}
}
return nullptr;
return {};
}
uint32_t SectionEntries::getSizeInBytes() const {
return list.size() * 32;
return list.size() * SectionEntry::LENGTH;
}
uint32_t SectionEntries::size() const {
return list.size();
}
std::optional<std::shared_ptr<SectionEntries>> SectionEntries::make_shared(const std::vector<uint8_t> &data, uint32_t numberOfSections, const VolumeBlockSize &pBlockSize) {
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");
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));
}
std::vector<std::shared_ptr<SectionEntry>> SectionEntries::getSections() const &{
return list;
}
SectionEntries::SectionEntries(std::vector<std::shared_ptr<SectionEntry>> pList) : list(std::move(pList)) {
}

View File

@ -16,26 +16,30 @@
****************************************************************************/
#pragma once
#include <optional>
#include <memory>
#include <cstdint>
#include <utility>
#include <vector>
#include <utils/blocksize/VolumeBlockSize.h>
#include <utils/logger.h>
#include "SectionEntry.h"
class SectionEntries {
public:
SectionEntries(uint8_t *data, uint32_t numberOfSections, const VolumeBlockSize &pBlockSize);
[[nodiscard]] uint32_t getSizeInBytes() const;
[[nodiscard]] uint32_t size() const;
[[nodiscard]] SectionEntry *getSection(uint16_t sectionNumber) const;
[[nodiscard]] std::optional<std::shared_ptr<SectionEntry>> getSection(uint16_t sectionNumber) const;
[[nodiscard]] std::vector<SectionEntry *> getSections() const &{
return list;
}
[[nodiscard]] std::vector<std::shared_ptr<SectionEntry>> getSections() const &;
static std::optional<std::shared_ptr<SectionEntries>> make_shared(const std::vector<uint8_t> &data, uint32_t numberOfSections, const VolumeBlockSize &pBlockSize);
private:
std::vector<SectionEntry *> list;
explicit SectionEntries(std::vector<std::shared_ptr<SectionEntry>> pList);
std::vector<std::shared_ptr<SectionEntry>> list;
};

View File

@ -16,8 +16,8 @@
****************************************************************************/
#include "SectionEntry.h"
SectionEntry::SectionEntry(uint8_t *data, uint32_t pSectionNumber, const VolumeBlockSize &pBlockSize) {
auto *dataAsUint = (uint32_t *) data;
SectionEntry::SectionEntry(const std::array<uint8_t, SectionEntry::LENGTH> &data, uint32_t pSectionNumber, const VolumeBlockSize &pBlockSize) {
auto *dataAsUint = (uint32_t *) data.data();
address = AddressInVolumeBlocks(pBlockSize, dataAsUint[0]);
size = SizeInVolumeBlocks(pBlockSize, dataAsUint[1]);

View File

@ -18,12 +18,15 @@
#include <cstdint>
#include <string>
#include <array>
#include <utils/blocksize/AddressInVolumeBlocks.h>
#include <utils/blocksize/SizeInVolumeBlocks.h>
class SectionEntry {
public:
SectionEntry(uint8_t *data, uint32_t pSectionNumber, const VolumeBlockSize &pBlockSize);
static constexpr uint32_t LENGTH = 32;
SectionEntry(const std::array<uint8_t, SectionEntry::LENGTH> &data, uint32_t pSectionNumber, const VolumeBlockSize &pBlockSize);
~SectionEntry() = default;

View File

@ -15,13 +15,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "StringEntry.h"
#include <utility>
#include <utils/logger.h>
#include "StringTable.h"
std::string StringEntry::toString() const {
std::optional<std::string> StringEntry::toString() const {
return stringTable->getByAddress(offset);
}
StringEntry::StringEntry(StringTable *pTable, uint32_t pOffset) {
stringTable = pTable;
offset = pOffset;
StringEntry::StringEntry(std::shared_ptr<StringTable> pTable, uint32_t pOffset) : stringTable(std::move(pTable)), offset(pOffset) {
}

View File

@ -18,16 +18,18 @@
#include <cstdint>
#include <string>
#include <memory>
#include <optional>
class StringTable;
class StringEntry {
public:
StringEntry(StringTable *pTable, uint32_t pOffset);
StringEntry(std::shared_ptr<StringTable> pTable, uint32_t pOffset);
[[nodiscard]] std::string toString() const;
[[nodiscard]] std::optional<std::string> toString() const;
StringTable *stringTable;
std::shared_ptr<StringTable> stringTable;
uint32_t offset;
};

View File

@ -16,26 +16,33 @@
****************************************************************************/
#include <cstring>
#include <coreinit/debug.h>
#include <utils/logger.h>
#include "StringTable.h"
StringTable *StringTable::parseData(uint8_t *data, uint32_t dataLength, uint32_t offset, uint32_t stringCount) {
auto *stringTable = new StringTable();
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");
return {};
}
auto stringTable = std::shared_ptr<StringTable>(new StringTable());
uint32_t curOffset = 0;
uint32_t i;
for (i = 0; curOffset < dataLength && i < stringCount; ++curOffset) {
for (i = 0; curOffset < data.size() && i < stringCount; ++curOffset) {
if (data[offset + curOffset] == (uint8_t) 0) {
++i;
}
}
if (i < stringCount) {
OSFatal("stringtable is broken");
DEBUG_FUNCTION_LINE("stringtable is broken");
return {};
}
uint32_t curLength = 0;
for (i = 0; i < stringCount; ++i) {
curOffset = offset + curLength;
stringTable->stringMap[curLength] = new StringEntry(stringTable, curLength);
stringTable->stringMap[curLength] = std::make_shared<StringEntry>(stringTable, curLength);
stringTable->strings[curLength] = (char *) &data[curOffset];
curLength += strlen((char *) &data[curOffset]) + 1;
@ -44,12 +51,18 @@ StringTable *StringTable::parseData(uint8_t *data, uint32_t dataLength, uint32_t
return stringTable;
}
std::string StringTable::getByAddress(uint32_t address) {
return strings[address];
std::optional<std::string> StringTable::getByAddress(uint32_t address) {
if (strings.count(address) > 0) {
return strings[address];
}
return {};
}
StringEntry *StringTable::getStringEntry(uint32_t address) {
return stringMap[address];
std::optional<std::shared_ptr<StringEntry>> StringTable::getStringEntry(uint32_t address) {
if (stringMap.count(address) > 0) {
return stringMap[address];
}
return {};
}
uint32_t StringTable::getSize() {
@ -60,12 +73,12 @@ uint32_t StringTable::getSize() {
return capacity;
}
StringEntry *StringTable::getEntry(std::string &str) {
std::optional<std::shared_ptr<StringEntry>> StringTable::getEntry(std::string &str) {
for (auto &cur: strings) {
if (cur.second == str) {
return stringMap[cur.first];
}
}
return nullptr;
return {};
}

View File

@ -16,6 +16,9 @@
****************************************************************************/
#pragma once
#include <optional>
#include <memory>
#include <vector>
#include <string>
#include <map>
#include "StringEntry.h"
@ -23,25 +26,19 @@
class StringTable {
public:
~StringTable() {
for (auto &cur: stringMap) {
delete cur.second;
}
stringMap.clear();
strings.clear();
}
static std::optional<std::shared_ptr<StringTable>> make_shared(const std::vector<uint8_t> &data, uint32_t offset, uint32_t stringCount);
static StringTable *parseData(uint8_t *data, uint32_t dataLength, uint32_t offset, uint32_t stringCount);
std::optional<std::string> getByAddress(uint32_t address);
std::string getByAddress(uint32_t address);
StringEntry *getStringEntry(uint32_t address);
std::optional<std::shared_ptr<StringEntry>> getStringEntry(uint32_t address);
uint32_t getSize();
StringEntry *getEntry(std::string &str);
std::optional<std::shared_ptr<StringEntry>> getEntry(std::string &str);
private:
std::map<uint32_t, StringEntry *> stringMap;
StringTable() = default;
std::map<uint32_t, std::shared_ptr<StringEntry>> stringMap;
std::map<uint32_t, std::string> strings;
};

View File

@ -17,12 +17,21 @@
#include <cstring>
#include "Content.h"
uint32_t Content::LENGTH = 0x30;
Content::Content(uint8_t *data) {
ID = ((uint32_t *) &data[0x00])[0];
index = ((uint16_t *) &data[0x04])[0];
type = ((uint16_t *) &data[0x06])[0];
encryptedFileSize = ((uint64_t *) &data[0x08])[0];
memcpy(hash, &data[0x10], 0x14);
Content::Content(uint32_t pId, uint16_t pIndex, uint16_t pType, uint64_t pEncryptedFileSize, const std::array<uint8_t, 0x14> &pHash) :
ID(pId),
index(pIndex),
type(pType),
encryptedFileSize(pEncryptedFileSize),
hash(pHash) {
}
std::optional<std::shared_ptr<Content>> Content::make_shared(const std::array<uint8_t, 0x30> &data) {
auto id = ((uint32_t *) &data[0x00])[0];
auto index = ((uint16_t *) &data[0x04])[0];
auto type = ((uint16_t *) &data[0x06])[0];
auto encryptedFileSize = ((uint64_t *) &data[0x08])[0];
std::array<uint8_t, 0x14> hash{};
memcpy(hash.data(), &data[0x10], 0x14);
return std::shared_ptr<Content>(new Content(id, index, type, encryptedFileSize, hash));
}

View File

@ -17,16 +17,21 @@
#pragma once
#include <cstdint>
#include <optional>
#include <memory>
class Content {
public:
static uint32_t LENGTH;
static constexpr uint32_t LENGTH = 0x30;
explicit Content(uint8_t *data);
uint16_t index;
uint32_t ID;
uint16_t index;
uint16_t type;
uint64_t encryptedFileSize;
uint8_t hash[0x14]{};
std::array<uint8_t, 0x14> hash;
static std::optional<std::shared_ptr<Content>> make_shared(const std::array<uint8_t, 0x30> &data);
private:
explicit Content(uint32_t pId, uint16_t pIndex, uint16_t pType, uint64_t pEncryptedFileSize, const std::array<uint8_t, 0x14> &pHash);
};

View File

@ -16,27 +16,46 @@
****************************************************************************/
#include "TitleMetaData.h"
TitleMetaData::TitleMetaData(uint8_t *data) {
contentCount = ((uint16_t *) &data[0x1DE])[0];
#include <utility>
#include <utils/logger.h>
TitleMetaData::TitleMetaData(std::vector<std::shared_ptr<Content>> pContentList) : contentList(std::move(pContentList)) {
// Get Contents
for (uint16_t i = 0; i < contentCount; i++) {
auto curOffset = 0xB04 + (i * Content::LENGTH);
auto *c = new Content((uint8_t *) &data[curOffset]);
contentList.push_back(c);
}
}
TitleMetaData::~TitleMetaData() {
for (auto &content: contentList) {
delete content;
}
}
Content *TitleMetaData::getContentByIndex(uint16_t i) {
std::optional<std::shared_ptr<Content>> TitleMetaData::getContentByIndex(uint16_t i) {
for (auto &content: contentList) {
if (content->index == i) {
return content;
}
}
return nullptr;
return {};
}
std::optional<std::shared_ptr<TitleMetaData>> TitleMetaData::make_shared(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];
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");
return {};
}
std::array<uint8_t, Content::LENGTH> contentData{};
std::copy(data.begin() + (int) curOffset, data.begin() + (int) curOffset + Content::LENGTH, contentData.begin());
auto curContentOpt = Content::make_shared(contentData);
if (!curContentOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse Content");
return {};
}
contentList.push_back(curContentOpt.value());
}
return std::shared_ptr<TitleMetaData>(new TitleMetaData(contentList));
}

View File

@ -16,20 +16,20 @@
****************************************************************************/
#pragma once
#include <optional>
#include <memory>
#include <cstdint>
#include <vector>
#include "Content.h"
class TitleMetaData {
public:
explicit TitleMetaData(uint8_t *data);
std::vector<std::shared_ptr<Content>> contentList;
~TitleMetaData();
std::optional<std::shared_ptr<Content>> getContentByIndex(uint16_t index);
std::vector<Content *> contentList;
Content *getContentByIndex(uint16_t index);
static std::optional<std::shared_ptr<TitleMetaData>> make_shared(const std::vector<uint8_t> &data);
private:
uint16_t contentCount;
explicit TitleMetaData(std::vector<std::shared_ptr<Content>> pContentList);
};

View File

@ -19,26 +19,48 @@
uint32_t WiiUDiscHeader::LENGTH = 131072L;
WiiUDiscHeader::WiiUDiscHeader(DiscReader *reader, uint32_t offset) {
WiiUDiscHeader::WiiUDiscHeader(std::unique_ptr<WiiUManufactorDiscId> pManufactorDiscId,
std::unique_ptr<WiiUDiscId> pDiscId,
std::unique_ptr<WiiUContentsInformation> pWiiUContentsInformation) :
manufactorDiscId(std::move(pManufactorDiscId)),
discId(std::move(pDiscId)),
wiiUContentsInformation(std::move(pWiiUContentsInformation)) {
}
std::optional<std::unique_ptr<WiiUDiscHeader>> WiiUDiscHeader::make_unique(const std::shared_ptr<DiscReader> &discReader) {
if (!discReader->IsReady()) {
DEBUG_FUNCTION_LINE("DiscReader is not ready");
return {};
}
uint32_t offset = 0;
uint32_t curOffset = offset;
manufactorDiscID = new WiiUManufactorDiscID(reader, 0);
curOffset += WiiUManufactorDiscID::LENGTH;
discId = new WiiUDiscID(reader, curOffset);
curOffset += WiiUDiscID::LENGTH;
wiiUContentsInformation = new WiiUContentsInformation(reader, curOffset);
auto manufactorDiscIDOpt = WiiUManufactorDiscId::make_unique(discReader);
if (!manufactorDiscIDOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to read ManufactorDiscId");
return {};
}
curOffset += WiiUManufactorDiscId::LENGTH;
auto discIdOpt = WiiUDiscId::make_unique(discReader, curOffset);
if (!discIdOpt.has_value()) {
DEBUG_FUNCTION_LINE("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");
return {};
}
curOffset += WiiUContentsInformation::LENGTH;
if (curOffset - offset != LENGTH) {
OSFatal("Length mismatch");
DEBUG_FUNCTION_LINE("Unexpected offset");
return {};
}
}
WiiUDiscHeader::~WiiUDiscHeader() {
delete manufactorDiscID;
delete discId;
delete wiiUContentsInformation;
}
WiiUDiscHeader::WiiUDiscHeader(DiscReaderDiscDrive *pDrive) : WiiUDiscHeader(pDrive, 0) {
DEBUG_FUNCTION_LINE();
return std::unique_ptr<WiiUDiscHeader>(new WiiUDiscHeader(
std::move(manufactorDiscIDOpt.value()),
std::move(discIdOpt.value()),
std::move(wiiUContentsInformationOpt.value())));
}

View File

@ -20,21 +20,25 @@
#include <WUD/DiscReader.h>
#include <WUD/content/WiiUContentsInformation.h>
#include <WUD/DiscReaderDiscDrive.h>
#include "WiiUManufactorDiscID.h"
#include "WiiUDiscID.h"
#include <memory>
#include "WiiUManufactorDiscId.h"
#include "WiiUDiscId.h"
class WiiUDiscHeader {
public:
explicit WiiUDiscHeader(DiscReaderDiscDrive *pDrive);
WiiUDiscHeader(DiscReader *reader, uint32_t offset);
static std::optional<std::unique_ptr<WiiUDiscHeader>> make_unique(const std::shared_ptr<DiscReader> &discReader);
~WiiUDiscHeader();
WiiUManufactorDiscID *manufactorDiscID = nullptr;
WiiUDiscID *discId = nullptr;
WiiUContentsInformation *wiiUContentsInformation = nullptr;
std::unique_ptr<WiiUManufactorDiscId> manufactorDiscId;
std::unique_ptr<WiiUDiscId> discId;
std::unique_ptr<WiiUContentsInformation> wiiUContentsInformation;
static uint32_t LENGTH;
private:
explicit WiiUDiscHeader(
std::unique_ptr<WiiUManufactorDiscId> pManufactorDiscId,
std::unique_ptr<WiiUDiscId> pDiscId,
std::unique_ptr<WiiUContentsInformation> pWiiUContentsInformation
);
};

View File

@ -0,0 +1,54 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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 "WiiUDiscId.h"
#include <memory>
#include <coreinit/debug.h>
#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);
if (data == nullptr) {
DEBUG_FUNCTION_LINE("Failed to alloc memory");
return {};
}
if (!discReader->readEncrypted(data, offset, WiiUDiscId::LENGTH)) {
DEBUG_FUNCTION_LINE("Failed to read data");
return {};
}
if (((uint32_t *) data)[0] != WiiUDiscId::MAGIC) {
DEBUG_FUNCTION_LINE("MAGIC mismatch");
return {};
}
auto majorVersion = data[5];
auto minorVersion = data[6];
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) {
}

View File

@ -16,17 +16,23 @@
****************************************************************************/
#pragma once
#include <memory>
#include <string>
#include <WUD/DiscReader.h>
#include <optional>
#include <utility>
class WiiUDiscID {
class WiiUDiscId {
public:
WiiUDiscID(DiscReader *reader, uint32_t offset);
static uint32_t LENGTH;
static uint32_t MAGIC;
uint8_t majorVersion;
static constexpr uint32_t LENGTH = 32768;
static constexpr uint32_t MAGIC = 0xCC549EB9;
uint8_t minorVersion;
uint8_t majorVersion;
std::string footprint;
static std::optional<std::unique_ptr<WiiUDiscId>> make_unique(const std::shared_ptr<DiscReader> &discReader, uint32_t offset);
private:
WiiUDiscId(uint8_t pMinorVersion, uint8_t pMajorVersion, const std::string &pFootprint);
};

View File

@ -1,26 +0,0 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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 <coreinit/debug.h>
uint32_t WiiUManufactorDiscID::LENGTH = 65536;
WiiUManufactorDiscID::WiiUManufactorDiscID(DiscReader *reader, uint32_t offset) {
if (!reader->readEncrypted(data, offset, LENGTH)) {
OSFatal("WiiUManufactorDiscID: read failed");
}
}

View File

@ -14,30 +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 "WiiUDiscID.h"
#include "WiiUManufactorDiscId.h"
#include <coreinit/debug.h>
#include <utils/logger.h>
uint32_t WiiUDiscID::LENGTH = 32768;
uint32_t WiiUDiscID::MAGIC = 0xCC549EB9;
WiiUDiscID::WiiUDiscID(DiscReader *reader, uint32_t offset) {
auto data = (uint8_t *) malloc(LENGTH);
if (data == nullptr) {
OSFatal("Failed to alloc for WiiUDiscID");
std::optional<std::unique_ptr<WiiUManufactorDiscId>> WiiUManufactorDiscId::make_unique(const std::shared_ptr<DiscReader> &discReader) {
if (!discReader->IsReady()) {
DEBUG_FUNCTION_LINE("DiscReader is not ready");
return {};
}
std::array<uint8_t, WiiUManufactorDiscId::LENGTH> data{};
if (!reader->readEncrypted(data, offset, LENGTH)) {
OSFatal("Failed to read data");
if (!discReader->readEncrypted(data.data(), 0, WiiUManufactorDiscId::LENGTH)) {
DEBUG_FUNCTION_LINE("Failed to read data");
return {};
}
if (((uint32_t *) data)[0] != MAGIC) {
OSFatal("MAGIC FAIL");
}
majorVersion = data[5];
minorVersion = data[6];
footprint = std::string((char *) &data[32]);
free(data);
return std::unique_ptr<WiiUManufactorDiscId>(new WiiUManufactorDiscId(data));
}
WiiUManufactorDiscId::WiiUManufactorDiscId(const std::array<uint8_t, WiiUManufactorDiscId::LENGTH> &pData) : data(pData) {
this->data = pData;
}

View File

@ -16,15 +16,20 @@
****************************************************************************/
#pragma once
#include <memory>
#include <cstdint>
#include <WUD/DiscReader.h>
#include <optional>
class WiiUManufactorDiscID {
class WiiUManufactorDiscId {
public:
WiiUManufactorDiscID(DiscReader *reader, uint32_t offset);
static std::optional<std::unique_ptr<WiiUManufactorDiscId>> make_unique(const std::shared_ptr<DiscReader> &discReader);
static constexpr uint32_t LENGTH = 65536;
std::array<uint8_t, WiiUManufactorDiscId::LENGTH> data;
static uint32_t LENGTH;
private:
uint8_t data[65536]{};
explicit WiiUManufactorDiscId(const std::array<uint8_t, WiiUManufactorDiscId::LENGTH> &pData);
};

View File

@ -1,33 +1,49 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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 "FSTUtils.h"
#include "logger.h"
#include <filesystem>
NodeEntry *FSTUtils::getFSTEntryByFullPath(DirectoryEntry *root, std::string &givenFullPath) {
std::optional<std::shared_ptr<NodeEntry>> FSTUtils::getFSTEntryByFullPath(const std::shared_ptr<DirectoryEntry> &root, std::string &givenFullPath) {
std::string fullPath = givenFullPath;
if (strncmp(fullPath.c_str(), "/", 1) != 0) {
fullPath = "/" + fullPath;
}
DirectoryEntry *pathOpt = root;
auto pathOpt = std::optional(root);
std::filesystem::path asPath = fullPath;
std::string dirPath = asPath.parent_path().string();
if (dirPath != "/") {
pathOpt = getFileEntryDir(root, dirPath);
}
if (pathOpt == nullptr) {
return nullptr;
if (!pathOpt.has_value()) {
return {};
}
for (auto &child: pathOpt->getChildren()) {
for (auto &child: pathOpt.value()->getChildren()) {
if (child->getFullPath() == fullPath) {
return child;
}
}
return nullptr;
return {};
}
DirectoryEntry *FSTUtils::getFileEntryDir(DirectoryEntry *curEntry, std::string &string) {
std::optional<std::shared_ptr<DirectoryEntry>> FSTUtils::getFileEntryDir(const std::shared_ptr<DirectoryEntry> &curEntry, std::string &string) {
// We add the "/" at the end so we don't get false results when using the "startWith" function.
if (!string.ends_with("/")) {
string += "/";
@ -44,18 +60,14 @@ DirectoryEntry *FSTUtils::getFileEntryDir(DirectoryEntry *curEntry, std::string
return getFileEntryDir(curChild, string);
}
}
return nullptr;
return {};
}
SectionEntry *FSTUtils::getSectionEntryForIndex(FST *pFst, uint16_t index) {
if (pFst == nullptr || pFst->sectionEntries == nullptr) {
return nullptr;
}
std::optional<std::shared_ptr<SectionEntry>> FSTUtils::getSectionEntryForIndex(const std::shared_ptr<FST> &pFst, uint16_t index) {
for (const auto &entry: pFst->sectionEntries->getSections()) {
if (entry->sectionNumber == index) {
return entry;
}
}
return nullptr;
return {};
}

View File

@ -1,3 +1,19 @@
/****************************************************************************
* Copyright (C) 2016-2021 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <string>
@ -7,10 +23,10 @@
class FSTUtils {
public:
static NodeEntry *getFSTEntryByFullPath(DirectoryEntry *root, std::string &givenFullPath);
static std::optional<std::shared_ptr<NodeEntry>> getFSTEntryByFullPath(const std::shared_ptr<DirectoryEntry> &root, std::string &givenFullPath);
static DirectoryEntry *getFileEntryDir(DirectoryEntry *curEntry, std::string &string);
static std::optional<std::shared_ptr<DirectoryEntry>> getFileEntryDir(const std::shared_ptr<DirectoryEntry> &curEntry, std::string &string);
static SectionEntry *getSectionEntryForIndex(FST *pFst, uint16_t index);
static std::optional<std::shared_ptr<SectionEntry>> getSectionEntryForIndex(const std::shared_ptr<FST> &pFst, uint16_t index);
};

View File

@ -21,8 +21,8 @@
class AddressInBlocks {
public:
explicit AddressInBlocks(const BlockSize &blockSize, uint32_t pValue) : blockSize(blockSize) {
value = pValue;
explicit AddressInBlocks(const BlockSize &pBlockSize, uint32_t pValue) : blockSize(pBlockSize), value(pValue) {
}
AddressInBlocks() = default;