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

View File

@ -16,45 +16,45 @@
****************************************************************************/ ****************************************************************************/
#include "DefaultNUSDataProcessor.h" #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) { if ((pContent->type & 0x0002) == 0x0002) {
DEBUG_FUNCTION_LINE("Hashed content not supported yet"); DEBUG_FUNCTION_LINE("Hashed content not supported yet");
return false; return false;
} }
auto contentSize = ROUNDUP(pContent->encryptedFileSize, 16);
out_data.resize(contentSize);
*length = ROUNDUP(pContent->encryptedFileSize, 16); auto *inData = (uint8_t *) malloc(contentSize);
*data = (uint8_t *) malloc(*length); if (inData == nullptr) {
if (*data == nullptr) { DEBUG_FUNCTION_LINE("Failed to alloc");
return false; return false;
} }
auto *inData = (uint8_t *) malloc(*length); if (!dataProvider->readRawContent(pContent, inData, 0, contentSize)) {
DEBUG_FUNCTION_LINE("Failed tor read content");
if (!dataProvider->readRawContent(pContent, inData, 0, *length)) {
free(*data);
free(inData); free(inData);
return false; return false;
} }
uint8_t IV[16]; std::array<uint8_t, 16> IV{};
memset(IV, 0, 16); memset(IV.data(), 0, 16);
uint16_t content_index = pContent->index; 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); free(inData);
return true; return true;
} }
NUSDataProvider *DefaultNUSDataProcessor::getDataProvider() { std::shared_ptr<NUSDataProvider> DefaultNUSDataProcessor::getDataProvider() {
return dataProvider; return dataProvider;
} }
DefaultNUSDataProcessor::DefaultNUSDataProcessor(NUSDataProvider *pDataProvider, NUSDecryption *pNUSDecryption) { DefaultNUSDataProcessor::DefaultNUSDataProcessor(
dataProvider = pDataProvider; std::shared_ptr<NUSDataProvider> pDataProvider,
nusDecryption = pNUSDecryption; 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 { class DefaultNUSDataProcessor : public NUSDataProcessor {
public: public:
DefaultNUSDataProcessor(NUSDataProvider *pDataProvider, NUSDecryption *pNUSDecryption); DefaultNUSDataProcessor(std::shared_ptr<NUSDataProvider> pDataProvider, std::shared_ptr<NUSDecryption> pNUSDecryption);
~DefaultNUSDataProcessor() override = default; ~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: private:
NUSDataProvider *dataProvider; std::shared_ptr<NUSDataProvider> dataProvider;
NUSDecryption *nusDecryption; std::shared_ptr<NUSDecryption> nusDecryption;
}; };

View File

@ -24,6 +24,7 @@
DiscReaderDiscDrive::DiscReaderDiscDrive() : DiscReader() { DiscReaderDiscDrive::DiscReaderDiscDrive() : DiscReader() {
DEBUG_FUNCTION_LINE();
auto *sector_buf = (uint8_t *) malloc(READ_SECTOR_SIZE); auto *sector_buf = (uint8_t *) malloc(READ_SECTOR_SIZE);
if (sector_buf == nullptr) { if (sector_buf == nullptr) {
return; return;
@ -75,6 +76,7 @@ bool DiscReaderDiscDrive::IsReady() {
} }
DiscReaderDiscDrive::~DiscReaderDiscDrive() { DiscReaderDiscDrive::~DiscReaderDiscDrive() {
DEBUG_FUNCTION_LINE();
if (device_handle != -1) { if (device_handle != -1) {
IOSUHAX_FSA_RawOpen(gFSAfd, "/dev/odd01", &device_handle); 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; 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; ~DiscReaderDiscDrive() override;
static std::optional<DiscReaderDiscDrive *> Create();
bool readEncryptedSector(uint8_t *buffer, uint32_t block_cnt, uint64_t offset_in_sector) const override; bool readEncryptedSector(uint8_t *buffer, uint32_t block_cnt, uint64_t offset_in_sector) const override;
bool IsReady() override; bool IsReady() override;

View File

@ -10,7 +10,7 @@ protected:
public: public:
virtual ~NUSDataProcessor() = default; 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: public:
virtual ~NUSDataProvider() = default; 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" #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; gamePartition = pGamePartition;
discReader = pDiscReader; discReader = pDiscReader;
} }
NUSDataProviderWUD::~NUSDataProviderWUD() { 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) { if (buffer == nullptr) {
DEBUG_FUNCTION_LINE();
return false; 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); return discReader->readEncrypted(buffer, offsetInWUD, size);
} }
bool NUSDataProviderWUD::getContentH3Hash(Content *content, uint8_t **data, uint32_t *size) { bool NUSDataProviderWUD::getContentH3Hash(const std::shared_ptr<Content> &content, std::vector<uint8_t> &out_data) {
if (content == nullptr || data == nullptr || size == nullptr) {
DEBUG_FUNCTION_LINE();
return false;
}
auto cur = gamePartition->getVolumes().begin()->second->h3HashArrayList[content->index]; auto cur = gamePartition->getVolumes().begin()->second->h3HashArrayList[content->index];
if (cur == nullptr || cur->size == 0) { if (cur == nullptr || cur->size == 0) {
DEBUG_FUNCTION_LINE(); DEBUG_FUNCTION_LINE();
return false; return false;
} }
*data = (uint8_t *) malloc(cur->size); out_data.resize(cur->size);
*size = cur->size; memcpy(out_data.data(), cur->data, cur->size);
memcpy(*data, cur->data, *size);
return true; return true;
} }
void NUSDataProviderWUD::setFST(FST *pFST) { void NUSDataProviderWUD::setFST(const std::shared_ptr<FST> &pFST) {
// We need to set the correct blocksizes // We need to set the correct blocksizes
auto blockSize = gamePartition->getVolumes().begin()->second->blockSize; auto blockSize = gamePartition->getVolumes().begin()->second->blockSize;
for (const auto &e: pFST->sectionEntries->getSections()) { for (const auto &e: pFST->sectionEntries->getSections()) {
@ -60,55 +59,30 @@ void NUSDataProviderWUD::setFST(FST *pFST) {
fst = pFST; fst = pFST;
} }
bool NUSDataProviderWUD::getRawCert(uint8_t **data, uint32_t *size) { bool NUSDataProviderWUD::getRawCert(std::vector<uint8_t> &out_data) {
if (data == nullptr || size == nullptr) { out_data = gamePartition->rawCert;
return false;
}
*data = (uint8_t *) malloc(gamePartition->certLen);
if (*data == nullptr) {
return false;
}
*size = gamePartition->certLen;
memcpy(*data, gamePartition->rawCert, gamePartition->certLen);
return true; return true;
} }
bool NUSDataProviderWUD::getRawTicket(uint8_t **data, uint32_t *size) { bool NUSDataProviderWUD::getRawTicket(std::vector<uint8_t> &out_data) {
if (data == nullptr || size == nullptr) { out_data = gamePartition->rawTicket;
return false;
}
*data = (uint8_t *) malloc(gamePartition->tikLen);
if (*data == nullptr) {
return false;
}
*size = gamePartition->tikLen;
memcpy(*data, gamePartition->rawTicket, gamePartition->tikLen);
return true; return true;
} }
bool NUSDataProviderWUD::getRawTMD(uint8_t **data, uint32_t *size) { bool NUSDataProviderWUD::getRawTMD(std::vector<uint8_t> &out_data) {
if (data == nullptr || size == nullptr) { out_data = gamePartition->rawTMD;
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);
return true; 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; 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(); return gamePartition->getSectionOffsetOnDefaultPartition() + vh->FSTAddress.getAddressInBytes();
} }
auto *info = FSTUtils::getSectionEntryForIndex(fst, content->index); auto info = FSTUtils::getSectionEntryForIndex(fst, content->index);
if (info == nullptr) { if (!info.has_value()) {
OSFatal("Failed to get section for Content"); 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 { class NUSDataProviderWUD : public NUSDataProvider {
public: public:
NUSDataProviderWUD(WiiUGMPartition *pGamePartition, DiscReader *pDiscReader); NUSDataProviderWUD(const std::shared_ptr<WiiUGMPartition> &pPartition, const std::shared_ptr<DiscReader> &pDrive);
~NUSDataProviderWUD() override; ~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{}; std::shared_ptr<FST> fst;
WiiUGMPartition *gamePartition; std::shared_ptr<WiiUGMPartition> gamePartition;
DiscReader *discReader; std::shared_ptr<DiscReader> discReader;
private: 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" #include "NUSDecryption.h"
void NUSDecryption::decryptData(uint8_t *IV, uint8_t *inData, uint8_t *outData, uint32_t size) const { #include <utility>
aes_set_key(ticket->ticketKeyDec); #include <utils/logger.h>
aes_decrypt(IV, inData, outData, size);
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) { NUSDecryption::NUSDecryption(std::shared_ptr<Ticket> pTicket) : ticket(std::move(pTicket)) {
ticket = pTicket; DEBUG_FUNCTION_LINE();
} }

View File

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

View File

@ -31,18 +31,26 @@ class NUSTitle {
public: public:
~NUSTitle(); ~NUSTitle();
NUSDataProcessor *dataProcessor; std::shared_ptr<NUSDataProcessor> dataProcessor;
TitleMetaData *tmd; std::shared_ptr<TitleMetaData> tmd;
Ticket *ticket; std::shared_ptr<Ticket> ticket;
FST *fst; std::shared_ptr<FST> fst;
NUSDecryption *decryption; std::shared_ptr<NUSDecryption> decryption;
NUSDataProvider *dataProvider; 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: 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/ ****************************************************************************/
#include "Ticket.h" #include "Ticket.h"
#include <algorithm>
#include <utils/logger.h>
Ticket::Ticket(uint8_t *data, uint8_t *commonKey) { Ticket::Ticket(const std::array<uint8_t, 16> &pEncryptedKey, const std::array<uint8_t, 16> &pDecryptedKey) :
uint8_t *tikKeyEnc = data + 0x1BF; ticketKeyEnc(pEncryptedKey),
uint8_t *title_id = data + 0x1DC; ticketKeyDec(pDecryptedKey) {
uint8_t IV[0x10]; DEBUG_FUNCTION_LINE();
int k; }
for (k = 0; k < 8; k++) {
IV[k] = title_id[k]; std::optional<std::shared_ptr<Ticket>> Ticket::make_shared(const std::vector<uint8_t> &data, std::optional<const std::array<uint8_t, 16>> commonKey) {
IV[k + 8] = 0x00; if (data.size() <= 0x1DC + 0x10) {
DEBUG_FUNCTION_LINE("Not enough data to parse a ticket");
return {};
} }
aes_set_key(commonKey); std::array<uint8_t, 16> title_id{};
aes_decrypt(IV, tikKeyEnc, ticketKeyDec, 16); std::array<uint8_t, 16> decryptedKey{};
memcpy(ticketKeyEnc, tikKeyEnc, 16); 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 <cstdint>
#include <utils/rijndael.h> #include <utils/rijndael.h>
#include <cstring> #include <cstring>
#include <optional>
#include <memory>
#include <vector>
class Ticket { class Ticket {
public: 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]{}; static std::optional<std::shared_ptr<Ticket>> make_shared(const std::vector<uint8_t> &data, std::optional<const std::array<uint8_t, 16>> commonKey);
uint8_t ticketKeyDec[16]{};
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; 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; 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; 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; curOffset += WiiUPartitions::LENGTH;
if (curOffset - offset != 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; WiiUContentsInformation::WiiUContentsInformation(std::unique_ptr<WiiUDiscContentsHeader> pDiscContentHeader,
delete discContentHeader; std::unique_ptr<WiiUPartitions> pPartitions) :
} discContentHeader(std::move(pDiscContentHeader)),
partitions(std::move(pPartitions)) {
};

View File

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

View File

@ -16,29 +16,43 @@
****************************************************************************/ ****************************************************************************/
#include <utils/blocksize/DiscBlockSize.h> #include <utils/blocksize/DiscBlockSize.h>
#include <coreinit/debug.h> #include <coreinit/debug.h>
#include <cstdlib>
#include "WiiUDiscContentsHeader.h" #include "WiiUDiscContentsHeader.h"
uint32_t WiiUDiscContentsHeader::LENGTH = 2048; std::optional<std::unique_ptr<WiiUDiscContentsHeader>> WiiUDiscContentsHeader::make_unique(const std::shared_ptr<DiscReader> &discReader, uint32_t offset) {
uint32_t WiiUDiscContentsHeader::MAGIC = 0xCCA6E67B;
WiiUDiscContentsHeader::WiiUDiscContentsHeader(DiscReader *reader, uint32_t offset) {
auto *buffer = (uint8_t *) malloc(LENGTH); auto *buffer = (uint8_t *) malloc(LENGTH);
if (!reader->hasDiscKey) { if (!buffer) {
if (!reader->readEncrypted(buffer, offset, LENGTH)) { DEBUG_FUNCTION_LINE("Failed to alloc buffer");
OSFatal("WiiUDiscContentsHeader: Failed to read encrypted"); return {};
}
if (!discReader->hasDiscKey) {
if (!discReader->readEncrypted(buffer, offset, LENGTH)) {
DEBUG_FUNCTION_LINE("Failed to read data");
return {};
} }
} else { } else {
if (!reader->readDecrypted(buffer, offset, 0, LENGTH, reader->discKey, nullptr, true)) { if (!discReader->readDecrypted(buffer, offset, 0, LENGTH, discReader->discKey, nullptr, true)) {
OSFatal("WiiUDiscContentsHeader: Failed to read decrypted"); DEBUG_FUNCTION_LINE("Failed to read data");
return {};
} }
} }
if (((uint32_t *) buffer)[0] != MAGIC) { if (((uint32_t *) buffer)[0] != MAGIC) {
OSFatal("WiiUDiscContentsHeader MAGIC mismatch."); DEBUG_FUNCTION_LINE("MAGIC mismatch");
return {};
} }
blockSize = DiscBlockSize(((uint32_t *) buffer)[1]); auto blockSize = DiscBlockSize(((uint32_t *) buffer)[1]);
memcpy(tocHash, &buffer[8], 20); std::array<uint8_t, 20> tocHash{};
numberOfPartition = ((uint32_t *) buffer)[7]; memcpy(tocHash.data(), &buffer[8], 20);
auto numberOfPartition = ((uint32_t *) buffer)[7];
free(buffer); 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 #pragma once
#include <algorithm>
#include <memory>
#include <WUD/DiscReader.h> #include <WUD/DiscReader.h>
#include <utils/blocksize/DiscBlockSize.h> #include <utils/blocksize/DiscBlockSize.h>
#include <optional>
class WiiUDiscContentsHeader { class WiiUDiscContentsHeader {
public: public:
WiiUDiscContentsHeader(DiscReader *reader, uint32_t offset);
~WiiUDiscContentsHeader() = default;
DiscBlockSize blockSize{}; DiscBlockSize blockSize{};
uint8_t tocHash[20]{};
uint32_t numberOfPartition; 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" #include "WiiUDataPartition.h"
WiiUDataPartition::~WiiUDataPartition() { #include <utility>
delete basePartition;
delete fst; 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 &{ std::string WiiUDataPartition::getVolumeId() const &{
return basePartition->getVolumeId(); return basePartition->getVolumeId();
} }
std::map<AddressInDiscBlocks, VolumeHeader *> WiiUDataPartition::getVolumes() const &{ std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> WiiUDataPartition::getVolumes() const &{
return basePartition->getVolumes(); return basePartition->getVolumes();
} }

View File

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

View File

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

View File

@ -16,32 +16,31 @@
****************************************************************************/ ****************************************************************************/
#pragma once #pragma once
#include <memory>
#include <cstdint> #include <cstdint>
#include <cstdlib> #include <cstdlib>
#include "WiiUPartition.h" #include "WiiUPartition.h"
class WiiUGMPartition : public WiiUPartition { class WiiUGMPartition : public WiiUPartition {
public: public:
WiiUGMPartition(WiiUPartition *partition, uint8_t *pRawTIK, uint32_t pTikLen, uint8_t *pRawTMD, uint32_t pTMDLen, uint8_t *pRawCert, uint32_t pCertLen); WiiUGMPartition(std::shared_ptr<WiiUPartition> partition,
std::vector<uint8_t> pRawTicket,
~WiiUGMPartition() override; std::vector<uint8_t> pRawTMD,
std::vector<uint8_t> pRawCert);
[[nodiscard]] std::string getVolumeId() const & 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]] uint16_t getFileSystemDescriptor() const override;
[[nodiscard]] uint64_t getSectionOffsetOnDefaultPartition() override; [[nodiscard]] uint64_t getSectionOffsetOnDefaultPartition() override;
uint8_t *rawTicket; std::vector<uint8_t> rawTicket;
uint8_t *rawTMD; std::vector<uint8_t> rawTMD;
uint8_t *rawCert; std::vector<uint8_t> rawCert;
uint32_t tikLen;
uint32_t TMDLen;
uint32_t certLen;
private: 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 * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/ ****************************************************************************/
#include <memory>
#include <coreinit/debug.h> #include <coreinit/debug.h>
#include "WiiUPartition.h" #include "WiiUPartition.h"
uint32_t WiiUPartition::LENGTH = 128; uint64_t WiiUPartition::getSectionOffsetOnDefaultPartition() {
if (volumes.size() != 1) {
WiiUPartition::WiiUPartition() = default; OSFatal("We have more or less than 1 volume header.");
WiiUPartition::~WiiUPartition() {
for (auto const&[key, val]: volumes) {
delete val;
} }
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); auto buffer = (uint8_t *) malloc(LENGTH);
if (buffer == nullptr) { if (buffer == nullptr) {
OSFatal("WiiUPartition: alloc buffer failed"); return {};
} }
if (!reader->hasDiscKey) { if (!discReader->hasDiscKey) {
if (!reader->readEncrypted(buffer, offset, LENGTH)) { if (!discReader->readEncrypted(buffer, offset, LENGTH)) {
OSFatal("WiiUPartition: Failed to read encrypted"); return {};
} }
} else { } else {
auto bufferBigger = (uint8_t *) malloc(LENGTH + 0x10); auto bufferBigger = (uint8_t *) malloc(LENGTH + 0x10);
if (bufferBigger == nullptr) { if (bufferBigger == nullptr) {
OSFatal("WiiUPartition: alloc bufferBigger failed"); return {};
} }
if (!reader->readDecrypted(bufferBigger, offset - 0x10, 0, LENGTH + 0x10, reader->discKey, nullptr, true)) { if (!discReader->readDecrypted(bufferBigger, offset - 0x10, 0, LENGTH + 0x10, discReader->discKey, nullptr, true)) {
OSFatal("WiiUPartition: Failed to read encrypted"); return {};
} }
memcpy(buffer, bufferBigger + 0x10, LENGTH); memcpy(buffer, bufferBigger + 0x10, LENGTH);
@ -54,26 +51,46 @@ WiiUPartition::WiiUPartition(DiscReader *reader, uint32_t offset, const DiscBloc
char name[32]; char name[32];
memset(name, 0, sizeof(name)); memset(name, 0, sizeof(name));
memcpy(name, buffer, 31); memcpy(name, buffer, 31);
volumeId = name; auto volumeId = name;
uint8_t num = buffer[31]; uint8_t num = buffer[31];
std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> volumes;
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
auto address = *((uint32_t *) &buffer[32 + (i * 4)]); auto address = *((uint32_t *) &buffer[32 + (i * 4)]);
AddressInDiscBlocks discLbaAddress = AddressInDiscBlocks(blockSize, address); AddressInDiscBlocks discLbaAddress = AddressInDiscBlocks(blockSize, address);
auto vh = new VolumeHeader(reader, discLbaAddress.getAddressInBytes()); auto vh = VolumeHeader::make_shared(discReader, discLbaAddress.getAddressInBytes());
volumes[discLbaAddress] = vh; 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); free(buffer);
return std::unique_ptr<WiiUPartition>(new WiiUPartition(
volumeId,
volumes,
fileSystemDescriptor));
} }
uint64_t WiiUPartition::getSectionOffsetOnDefaultPartition() { std::string WiiUPartition::getVolumeId() const &{
if (volumes.size() != 1) { return volumeId;
OSFatal("We have more or less than 1 volume header.");
}
return volumes.begin()->first.getAddressInBytes();
} }
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 #pragma once
#include <map> #include <map>
#include <utility>
#include <utils/blocksize/DiscBlockSize.h> #include <utils/blocksize/DiscBlockSize.h>
#include <utils/blocksize/AddressInDiscBlocks.h> #include <utils/blocksize/AddressInDiscBlocks.h>
#include "volumes/VolumeHeader.h" #include "volumes/VolumeHeader.h"
@ -24,29 +25,29 @@
class WiiUPartition { class WiiUPartition {
public: 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 uint64_t getSectionOffsetOnDefaultPartition();
virtual ~WiiUPartition(); [[nodiscard]] virtual std::string getVolumeId() const &;
[[nodiscard]] virtual std::string getVolumeId() const &{ [[nodiscard]] virtual std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> getVolumes() const &;
return volumeId;
}
[[nodiscard]] virtual std::map<AddressInDiscBlocks, VolumeHeader *> getVolumes() const &{ [[nodiscard]] virtual uint16_t getFileSystemDescriptor() const;
return volumes;
}
[[nodiscard]] virtual uint16_t getFileSystemDescriptor() const { static std::optional<std::shared_ptr<WiiUPartition>> make_shared(const std::shared_ptr<DiscReader> &discReader, uint32_t offset, const DiscBlockSize &blockSize);
return fileSystemDescriptor;
} protected:
WiiUPartition() = default;
private: 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::string volumeId;
std::map<AddressInDiscBlocks, VolumeHeader *> volumes; std::map<AddressInDiscBlocks, std::shared_ptr<VolumeHeader>> volumes;
uint16_t fileSystemDescriptor{}; uint16_t fileSystemDescriptor{};
static uint32_t LENGTH;
}; };

View File

@ -16,94 +16,140 @@
****************************************************************************/ ****************************************************************************/
#include <utils/FSTUtils.h> #include <utils/FSTUtils.h>
#include <coreinit/debug.h> #include <coreinit/debug.h>
#include <utility>
#include "WiiUPartitions.h" #include "WiiUPartitions.h"
#include "WiiUGMPartition.h" #include "WiiUGMPartition.h"
#include "WiiUDataPartition.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) { auto asFileEntry = std::dynamic_pointer_cast<FileEntry>(entryOpt.value());
std::vector<WiiUPartition *> tmp; 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); tmp.reserve(numberOfPartitions);
for (uint32_t i = 0; i < numberOfPartitions; i++) { 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) { for (auto &partition: tmp) {
if (partition->getVolumeId().starts_with("SI")) { if (partition->getVolumeId().starts_with("SI")) {
SIPartition = partition; SIPartition = partition;
break;
} }
} }
if (SIPartition != nullptr) { if (SIPartition.has_value()) {
for (auto const&[key, val]: SIPartition->getVolumes()) { for (auto const&[key, val]: SIPartition.value()->getVolumes()) {
auto volumeAddress = key; auto volumeAddress = key;
auto volumeAddressInBytes = volumeAddress.getAddressInBytes(); auto volumeAddressInBytes = volumeAddress.getAddressInBytes();
auto volumeHeader = val; auto volumeHeader = val;
auto fst = (uint8_t *) malloc(volumeHeader->FSTSize); std::vector<uint8_t> fstData;
if (fst == nullptr) { fstData.resize(volumeHeader->FSTSize);
OSFatal("WiiUPartitions: Failed to alloc FST buffer");
}
if (!reader->hasDiscKey) { if (!discReader->hasDiscKey) {
if (!reader->readEncrypted(fst, volumeAddressInBytes + volumeHeader->FSTAddress.getAddressInBytes(), if (!discReader->readEncrypted(fstData.data(), volumeAddressInBytes + volumeHeader->FSTAddress.getAddressInBytes(),
volumeHeader->FSTSize)) { volumeHeader->FSTSize)) {
OSFatal("WiiUPartitions: Failed to read encrypted"); DEBUG_FUNCTION_LINE("Failed to read FST");
return {};
} }
} else { } else {
if (!reader->readDecrypted(fst, volumeAddressInBytes + volumeHeader->FSTAddress.getAddressInBytes(), 0, volumeHeader->FSTSize, if (!discReader->readDecrypted(fstData.data(), volumeAddressInBytes + volumeHeader->FSTAddress.getAddressInBytes(), 0, volumeHeader->FSTSize,
reader->discKey, nullptr, true)) { discReader->discKey, nullptr, true)) {
OSFatal("WiiUPartitions: Failed to read decrypted"); DEBUG_FUNCTION_LINE("Failed to read FST");
return {};
} }
} }
FST *siFST = new FST(fst, volumeHeader->FSTSize, 0, volumeHeader->blockSize); auto siFST = FST::make_shared(fstData, 0, volumeHeader->blockSize);
free(fst); if (!siFST.has_value()) {
DEBUG_FUNCTION_LINE("Failed to parse FST");
return {};
}
for (auto &child: siFST->getRootEntry()->getDirChildren()) { for (auto &child: siFST.value()->getRootEntry()->getDirChildren()) {
uint8_t *tikRaw = nullptr; std::vector<uint8_t> bufferTicket;
uint32_t tikRawLen = 0;
std::string tikFilePath = std::string(child->getFullPath() + '/' + WUD_TICKET_FILENAME); std::string tikFilePath = std::string(child->getFullPath() + '/' + WUD_TICKET_FILENAME);
if (!getFSTEntryAsByte(&tikRaw, &tikRawLen, tikFilePath, siFST, volumeAddress, reader)) { if (!getFSTEntryAsByte(tikFilePath, siFST.value(), volumeAddress, discReader, bufferTicket)) {
OSFatal("tikRaw"); DEBUG_FUNCTION_LINE("Failted to read FSTEntry");
return {};
} }
uint8_t *tmdRaw = nullptr; std::vector<uint8_t> bufferTMD;
uint32_t tmdRawLen = 0;
std::string tmdFilePath = std::string(child->getFullPath() + '/' + WUD_TMD_FILENAME); std::string tmdFilePath = std::string(child->getFullPath() + '/' + WUD_TMD_FILENAME);
if (!getFSTEntryAsByte(&tmdRaw, &tmdRawLen, tmdFilePath, siFST, volumeAddress, reader)) { if (!getFSTEntryAsByte(tmdFilePath, siFST.value(), volumeAddress, discReader, bufferTMD)) {
OSFatal("tmdRaw"); DEBUG_FUNCTION_LINE("Failted to read FSTEntry");
return {};
} }
uint8_t *certRaw = nullptr; std::vector<uint8_t> bufferCert;
uint32_t certRawLen = 0;
std::string certFilePath = std::string(child->getFullPath() + '/' + WUD_CERT_FILENAME); std::string certFilePath = std::string(child->getFullPath() + '/' + WUD_CERT_FILENAME);
if (!getFSTEntryAsByte(&certRaw, &certRawLen, certFilePath, siFST, volumeAddress, reader)) { if (!getFSTEntryAsByte(certFilePath, siFST.value(), volumeAddress, discReader, bufferCert)) {
OSFatal("certRaw"); DEBUG_FUNCTION_LINE("Failted to read FSTEntry");
return {};
} }
char partitionNameRaw[0x12]; char partitionNameRaw[0x12];
memset(partitionNameRaw, 0, 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; std::string partitionName = std::string("GM") + partitionNameRaw;
WiiUPartition *curPartition = nullptr; std::optional<std::shared_ptr<WiiUPartition>> curPartition;
for (auto &partition: tmp) { for (auto &partition: tmp) {
if (partition->getVolumeId().starts_with(partitionName)) { if (partition->getVolumeId().starts_with(partitionName)) {
curPartition = partition; curPartition = partition;
break;
} }
} }
if (curPartition == nullptr) { if (!curPartition.has_value()) {
OSFatal("Failed to get partition"); 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); 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 volumeAddress = partition->getVolumes().begin()->first;
auto vh = partition->getVolumes().begin()->second; auto vh = partition->getVolumes().begin()->second;
auto *rawFST = (uint8_t *) malloc(vh->FSTSize);
if (rawFST == nullptr) { std::vector<uint8_t> fstData;
OSFatal("Failed to alloc rawFST"); fstData.resize(vh->FSTSize);
}
if (!reader->hasDiscKey) { if (!discReader->hasDiscKey) {
if (!reader->readEncrypted(rawFST, volumeAddress.getAddressInBytes() + vh->FSTAddress.getAddressInBytes(), vh->FSTSize)) { if (!discReader->readEncrypted(fstData.data(), volumeAddress.getAddressInBytes() + vh->FSTAddress.getAddressInBytes(), vh->FSTSize)) {
OSFatal("WiiUPartition: Failed to read encrypted"); OSFatal("WiiUPartition: Failed to read encrypted");
} }
} else { } else {
if (!reader->readDecrypted(rawFST, volumeAddress.getAddressInBytes() + vh->FSTAddress.getAddressInBytes(), 0, vh->FSTSize, if (!discReader->readDecrypted(fstData.data(), volumeAddress.getAddressInBytes() + vh->FSTAddress.getAddressInBytes(), 0, vh->FSTSize,
reader->discKey, nullptr, true)) { discReader->discKey, nullptr, true)) {
OSFatal("WiiUPartition: Failed to read encrypted"); OSFatal("WiiUPartition: Failed to read encrypted");
} }
} }
FST *fst = new FST(rawFST, vh->FSTSize, 0, vh->blockSize); auto fstOpt = FST::make_shared(fstData, 0, vh->blockSize);
free(rawFST); if (!fstOpt.has_value()) {
partitions.push_back(new WiiUDataPartition(partition, fst)); 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() { WiiUPartitions::WiiUPartitions(std::vector<std::shared_ptr<WiiUPartition>> pPartitions) : partitions(std::move(pPartitions)) {
for (auto &partition: partitions) { DEBUG_FUNCTION_LINE();
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);
} }

View File

@ -16,6 +16,7 @@
****************************************************************************/ ****************************************************************************/
#pragma once #pragma once
#include <memory>
#include <cstdint> #include <cstdint>
#include <utils/blocksize/DiscBlockSize.h> #include <utils/blocksize/DiscBlockSize.h>
#include <utils/blocksize/AddressInDiscBlocks.h> #include <utils/blocksize/AddressInDiscBlocks.h>
@ -30,13 +31,21 @@
class WiiUPartitions { class WiiUPartitions {
public: 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(); static std::optional<std::unique_ptr<WiiUPartitions>> make_unique(
const std::shared_ptr<DiscReader> &discReader,
std::vector<WiiUPartition *> partitions; uint32_t offset,
static uint32_t LENGTH; uint32_t numberOfPartitions,
const DiscBlockSize &blockSize);
private:
explicit WiiUPartitions(std::vector<std::shared_ptr<WiiUPartition>> pPartitions);
}; };

View File

@ -34,4 +34,4 @@ H3HashArray::~H3HashArray() {
if (data) { if (data) {
free(data); free(data);
} }
} }

View File

@ -15,58 +15,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/ ****************************************************************************/
#include <memory>
#include "VolumeHeader.h" #include "VolumeHeader.h"
#include <utils/utils.h>
#include <coreinit/debug.h> #include <coreinit/debug.h>
#include <utils/logger.h>
uint32_t VolumeHeader::MAGIC = 0xCC93A4F5; uint32_t VolumeHeader::MAGIC = 0xCC93A4F5;
VolumeHeader::VolumeHeader(DiscReader *reader, uint64_t offset) { std::vector<std::shared_ptr<H3HashArray>> VolumeHeader::getH3HashArray(uint8_t *h3Data, uint32_t pNumberOfH3HashArray, uint32_t pH3HashArrayListSize) {
auto buffer = (uint8_t *) malloc(64); std::vector<std::shared_ptr<H3HashArray>> arrayList;
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;
if (pNumberOfH3HashArray == 0) { if (pNumberOfH3HashArray == 0) {
return arrayList; return arrayList;
} }
@ -80,15 +37,93 @@ std::vector<H3HashArray *> VolumeHeader::getH3HashArray(uint8_t *h3Data, uint32_
curEnd = offsetPtr[1]; 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; return arrayList;
} }
VolumeHeader::~VolumeHeader() { std::optional<std::shared_ptr<VolumeHeader>> VolumeHeader::make_shared(const std::shared_ptr<DiscReader> &discReader, uint64_t offset) {
for (auto &h3: h3HashArrayList) { auto buffer = (uint8_t *) malloc(64);
delete h3; 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 #pragma once
#include <utility>
#include <vector> #include <vector>
#include <cstdint> #include <cstdint>
#include <WUD/DiscReader.h> #include <WUD/DiscReader.h>
#include <utils/blocksize/VolumeBlockSize.h> #include <utils/blocksize/VolumeBlockSize.h>
#include <utils/blocksize/AddressInVolumeBlocks.h> #include <utils/blocksize/AddressInVolumeBlocks.h>
#include <utils/blocksize/SizeInVolumeBlocks.h> #include <utils/blocksize/SizeInVolumeBlocks.h>
#include <optional>
#include <utils/utils.h>
#include "H3HashArray.h" #include "H3HashArray.h"
class VolumeHeader { class VolumeHeader {
public: public:
static std::vector<H3HashArray *> getH3HashArray(uint8_t *h3Data, uint32_t numberOfH3HashArray, uint32_t h3HashArrayListSize); static std::vector<std::shared_ptr<H3HashArray>> getH3HashArray(uint8_t *h3Data, uint32_t numberOfH3HashArray, uint32_t h3HashArrayListSize);
VolumeHeader(DiscReader *reader, uint64_t offset);
~VolumeHeader();
static uint32_t MAGIC; static uint32_t MAGIC;
VolumeBlockSize blockSize; VolumeBlockSize blockSize;
@ -43,8 +42,26 @@ public:
uint8_t majorVersion; uint8_t majorVersion;
uint8_t minorVersion; uint8_t minorVersion;
uint8_t expiringMajorVersion; uint8_t expiringMajorVersion;
std::vector<H3HashArray *> h3HashArrayList; std::vector<std::shared_ptr<H3HashArray>> h3HashArrayList;
uint32_t h3HashArrayListSize; uint32_t h3HashArrayListSize;
uint32_t numberOfH3HashArray; uint32_t numberOfH3HashArray;
static std::optional<std::shared_ptr<VolumeHeader>> make_shared(const std::shared_ptr<DiscReader> &discReader, uint64_t offset);
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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/ ****************************************************************************/
#include "FST.h" #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; uint32_t curOffset = offset;
header = new FSTHeader(data + curOffset); if (curOffset + FSTHeader::LENGTH > data.size()) {
curOffset += header->LENGTH; DEBUG_FUNCTION_LINE("Not enough data to parse the FSTHeader");
return {};
}
sectionEntries = new SectionEntries(data + curOffset, header->numberOfSections, blockSize); std::array<uint8_t, FSTHeader::LENGTH> fstData{};
curOffset += sectionEntries->getSizeInBytes(); 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); 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() { FST::FST(std::unique_ptr<FSTHeader> pHeader,
delete nodeEntries; std::shared_ptr<SectionEntries> pSectionEntries,
delete stringTable; std::shared_ptr<StringTable> pStringTable,
delete sectionEntries; std::unique_ptr<NodeEntries> pNodeEntries) :
delete header; 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 #pragma once
#include <optional>
#include <memory>
#include <cstdint> #include <cstdint>
#include <utility>
#include <WUD/entities/FST/header/FSTHeader.h> #include <WUD/entities/FST/header/FSTHeader.h>
#include <WUD/entities/FST/sectionentry/SectionEntries.h> #include <WUD/entities/FST/sectionentry/SectionEntries.h>
#include <WUD/entities/FST/stringtable/StringTable.h> #include <WUD/entities/FST/stringtable/StringTable.h>
@ -24,16 +27,20 @@
#include <WUD/entities/FST/nodeentry/RootEntry.h> #include <WUD/entities/FST/nodeentry/RootEntry.h>
class FST { class FST {
public: 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; std::shared_ptr<SectionEntries> sectionEntries;
SectionEntries *sectionEntries; private:
StringTable *stringTable; FST(std::unique_ptr<FSTHeader> pHeader,
NodeEntries *nodeEntries; 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/ ****************************************************************************/
#include <utils/blocksize/SectionBlockSize.h> #include <utils/blocksize/SectionBlockSize.h>
#include <coreinit/debug.h> #include <utils/logger.h>
#include "FSTHeader.h" #include "FSTHeader.h"
FSTHeader::FSTHeader(uint8_t *data) { std::optional<std::unique_ptr<FSTHeader>> FSTHeader::make_unique(const std::array<uint8_t, FSTHeader::LENGTH> &data) {
auto *dataAsUint = (uint32_t *) data; auto *dataAsUint = (uint32_t *) data.data();
if ((dataAsUint[0] & 0xFFFFFF00) != 0x46535400) { if ((dataAsUint[0] & 0xFFFFFF00) != 0x46535400) {
OSFatal("FST Header magic was wrong"); DEBUG_FUNCTION_LINE("FST Header magic was wrong");
return {};
} }
FSTVersion = data[3]; auto FSTVersion = data[3];
blockSize = SectionBlockSize(dataAsUint[1]); auto blockSize = SectionBlockSize(dataAsUint[1]);
numberOfSections = dataAsUint[2]; auto numberOfSections = dataAsUint[2];
hashDisabled = data[12]; 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 #pragma once
#include <optional>
#include <memory>
#include <cstdint> #include <cstdint>
#include <utils/blocksize/SectionBlockSize.h> #include <utils/blocksize/SectionBlockSize.h>
class FSTHeader { class FSTHeader {
public: 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; uint8_t FSTVersion;
SectionBlockSize blockSize; SectionBlockSize blockSize;
uint8_t hashDisabled;
uint32_t numberOfSections; 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 <coreinit/debug.h>
#include "DirectoryEntry.h" #include "DirectoryEntry.h"
DirectoryEntry *DirectoryEntry::parseData(const uint8_t *data, NodeEntryParam param, SectionEntries *sectionEntries, StringTable *stringTable) { std::optional<std::shared_ptr<DirectoryEntry>>
auto *directoryEntry = new DirectoryEntry(); DirectoryEntry::parseData(const std::array<uint8_t, NodeEntry::LENGTH> &data, const NodeEntryParam &param, const std::shared_ptr<SectionEntries> &sectionEntries,
directoryEntry->entryNumber = param.entryNumber; const std::shared_ptr<StringTable> &stringTable) {
directoryEntry->parent = param.parent; auto parentEntryNumber = ((uint32_t *) &data[4])[0];
directoryEntry->entryType = param.type; auto lastEntryNumber = ((uint32_t *) &data[8])[0];
directoryEntry->nameString = stringTable->getStringEntry(param.uint24); auto stringNameOpt = stringTable->getStringEntry(param.uint24);
if (directoryEntry->nameString == nullptr) { if (!stringNameOpt.has_value()) {
OSFatal("Failed to find string for offset"); DEBUG_FUNCTION_LINE("Failed to get string name");
return {};
} }
directoryEntry->parentEntryNumber = ((uint32_t *) &data[4])[0]; auto sectionEntryOpt = sectionEntries->getSection(param.sectionNumber);
directoryEntry->lastEntryNumber = ((uint32_t *) &data[8])[0]; if (!sectionEntryOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to get section entry");
directoryEntry->permission = param.permission; return {};
if (param.sectionNumber > sectionEntries->size()) {
OSFatal("section number does not match");
} }
directoryEntry->sectionEntry = sectionEntries->getSection(param.sectionNumber);
return directoryEntry;
return std::unique_ptr<DirectoryEntry>(new DirectoryEntry(param, stringNameOpt.value(), sectionEntryOpt.value(), parentEntryNumber, lastEntryNumber));
} }
DirectoryEntry::~DirectoryEntry() { std::vector<std::shared_ptr<DirectoryEntry>> DirectoryEntry::getDirChildren() const {
for (auto &child: children) { std::vector<std::shared_ptr<DirectoryEntry>> res;
delete child;
}
}
std::vector<DirectoryEntry *> DirectoryEntry::getDirChildren() const {
std::vector<DirectoryEntry *> res;
for (auto &cur: children) { for (auto &cur: children) {
if (cur->isDirectory()) { if (cur->isDirectory()) {
res.push_back(dynamic_cast<DirectoryEntry *>(cur)); res.push_back(std::dynamic_pointer_cast<DirectoryEntry>(cur));
} }
} }
return res; return res;
} }
std::vector<FileEntry *> DirectoryEntry::getFileChildren() const { std::vector<std::shared_ptr<FileEntry>> DirectoryEntry::getFileChildren() const {
std::vector<FileEntry *> res; std::vector<std::shared_ptr<FileEntry>> res;
for (auto &cur: children) { for (auto &cur: children) {
if (cur->isFile()) { if (cur->isFile()) {
res.push_back(dynamic_cast<FileEntry *>(cur)); res.push_back(std::dynamic_pointer_cast<FileEntry>(cur));
} }
} }
return res; return res;
} }
std::vector<NodeEntry *> DirectoryEntry::getChildren() const { std::vector<std::shared_ptr<NodeEntry>> DirectoryEntry::getChildren() const {
return children; 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); 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" #include "FileEntry.h"
class DirectoryEntry : public NodeEntry { class DirectoryEntry : public NodeEntry {
public: public:
~DirectoryEntry() override; static std::optional<std::shared_ptr<DirectoryEntry>>
parseData(const std::array<uint8_t, NodeEntry::LENGTH> &data,
static DirectoryEntry *parseData(const uint8_t *data, NodeEntryParam param, SectionEntries *sectionEntries, StringTable *stringTable); const NodeEntryParam &param,
const std::shared_ptr<SectionEntries> &sectionEntries,
const std::shared_ptr<StringTable> &stringTable);
uint32_t parentEntryNumber{}; uint32_t parentEntryNumber{};
uint32_t lastEntryNumber{}; 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; 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> #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 stringNameOpt = stringTable->getStringEntry(param.uint24);
auto *entry = new FileEntry(SectionAddress(blockSize, ((uint32_t *) &data[4])[0])); if (!stringNameOpt.has_value()) {
DEBUG_FUNCTION_LINE("Failed to get string name");
entry->entryNumber = param.entryNumber; return {};
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");
} }
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; return std::shared_ptr<FileEntry>(new FileEntry(param, stringNameOpt.value(), sectionEntryOpt.value(), size, offset));
entry->sectionEntry = sectionEntries->getSection(param.sectionNumber);
return entry;
} }
SectionEntry *FileEntry::getSectionEntry() { std::shared_ptr<SectionEntry> FileEntry::getSectionEntry() {
return sectionEntry; return sectionEntry;
} }
@ -54,3 +56,19 @@ uint64_t FileEntry::getOffset() const {
uint32_t FileEntry::getSize() const { uint32_t FileEntry::getSize() const {
return size; 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 { class FileEntry : public NodeEntry {
public: 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; ~FileEntry() override = default;
SectionEntry *getSectionEntry(); std::shared_ptr<SectionEntry> getSectionEntry();
[[nodiscard]] uint64_t getOffset() const; [[nodiscard]] uint64_t getOffset() const;
[[nodiscard]] uint32_t getSize() const; [[nodiscard]] uint32_t getSize() const;
private: private:
FileEntry(const NodeEntryParam &param,
const std::shared_ptr<StringEntry> &pStringEntry,
const std::shared_ptr<SectionEntry> &pSectionEntry,
uint32_t pSize,
SectionAddress offset);
SectionAddress address; SectionAddress address;
uint32_t size{}; uint32_t size{};
}; };

View File

@ -17,25 +17,30 @@
#include <coreinit/debug.h> #include <coreinit/debug.h>
#include "NodeEntries.h" #include "NodeEntries.h"
NodeEntries::NodeEntries(RootEntry *pEntry) { std::optional<std::shared_ptr<NodeEntry>> NodeEntries::DeserializeImpl(const std::vector<uint8_t> &pData,
rootEntry = pEntry; uint32_t pOffset,
} const std::optional<std::shared_ptr<DirectoryEntry>> &pParent,
uint32_t pEntryNumber,
NodeEntries::~NodeEntries() { const std::shared_ptr<SectionEntries> &pSectionEntries,
delete rootEntry; const std::shared_ptr<StringTable> &pStringTable,
} const SectionBlockSize &pBlockSize) {
auto nodeEntry = NodeEntry::AutoDeserialize(pData, pOffset, pParent, pEntryNumber, pSectionEntries, pStringTable, pBlockSize);
NodeEntry *NodeEntries::DeserializeImpl(uint8_t *data, uint32_t offset, DirectoryEntry *parent, uint32_t entryNumber, SectionEntries *sectionEntries, StringTable *stringTable, if (!nodeEntry.has_value()) {
const SectionBlockSize &blockSize) { DEBUG_FUNCTION_LINE("Failed to AutoDeserialize NodeEntry");
NodeEntry *nodeEntry = NodeEntry::AutoDeserialize(data, offset, parent, entryNumber, sectionEntries, stringTable, blockSize); return {};
auto asDirEntry = dynamic_cast<DirectoryEntry *>(nodeEntry); }
auto asDirEntry = std::dynamic_pointer_cast<DirectoryEntry>(nodeEntry.value());
if (asDirEntry != nullptr) { if (asDirEntry != nullptr) {
uint32_t curEntryNumber = asDirEntry->entryNumber + 1; uint32_t curEntryNumber = asDirEntry->entryNumber + 1;
while (curEntryNumber < asDirEntry->lastEntryNumber) { while (curEntryNumber < asDirEntry->lastEntryNumber) {
NodeEntry *entry = NodeEntries::DeserializeImpl(data, offset + (curEntryNumber - asDirEntry->entryNumber) * NodeEntry::LENGTH, auto entry = NodeEntries::DeserializeImpl(pData, pOffset + (curEntryNumber - asDirEntry->entryNumber) * NodeEntry::LENGTH,
asDirEntry, curEntryNumber, sectionEntries, stringTable, blockSize); asDirEntry, curEntryNumber, pSectionEntries, pStringTable, pBlockSize);
asDirEntry->addChild(entry); if (!entry.has_value()) {
auto *childAsDir = dynamic_cast<DirectoryEntry *>(entry); 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) { if (childAsDir != nullptr) {
curEntryNumber = childAsDir->lastEntryNumber; curEntryNumber = childAsDir->lastEntryNumber;
} else { } else {
@ -46,12 +51,26 @@ NodeEntry *NodeEntries::DeserializeImpl(uint8_t *data, uint32_t offset, Director
return nodeEntry; return nodeEntry;
} }
NodeEntries *NodeEntries::parseData(unsigned char *data, uint32_t offset, SectionEntries *sectionEntries, StringTable *stringTable, const SectionBlockSize &blockSize) { std::optional<std::unique_ptr<NodeEntries>>
NodeEntry *rootEntry = NodeEntries::DeserializeImpl(data, offset, (DirectoryEntry *) nullptr, 0, sectionEntries, stringTable, blockSize); NodeEntries::make_unique(const std::vector<uint8_t> &data, uint32_t offset, const std::shared_ptr<SectionEntries> &pSectionEntries, const std::shared_ptr<StringTable> &pStringTable,
auto rootEntryCasted = dynamic_cast<RootEntry *>(rootEntry); const SectionBlockSize &blockSize) {
if (rootEntryCasted != nullptr) { auto rootEntry = NodeEntries::DeserializeImpl(data, offset, std::nullopt, 0, pSectionEntries, pStringTable, blockSize);
return new NodeEntries(rootEntryCasted); if (!rootEntry.has_value()) {
DEBUG_FUNCTION_LINE("DeserializeImpl for root entry has failed");
return {};
} }
OSFatal("Failed to parse Root"); auto rootEntryCasted = std::dynamic_pointer_cast<RootEntry>(rootEntry.value());
return nullptr; 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 <WUD/entities/FST/stringtable/StringTable.h>
#include <utils/blocksize/SectionBlockSize.h> #include <utils/blocksize/SectionBlockSize.h>
#include <WUD/entities/FST/sectionentry/SectionEntries.h> #include <WUD/entities/FST/sectionentry/SectionEntries.h>
#include <utility>
#include "DirectoryEntry.h" #include "DirectoryEntry.h"
#include "RootEntry.h" #include "RootEntry.h"
#include "NodeEntry.h" #include "NodeEntry.h"
@ -27,14 +29,32 @@
class NodeEntries { class NodeEntries {
public: public:
explicit NodeEntries(RootEntry *pEntry);
~NodeEntries(); virtual ~NodeEntries() {
DEBUG_FUNCTION_LINE("Bye");
}
static NodeEntry * static std::optional<std::shared_ptr<NodeEntry>>
DeserializeImpl(unsigned char *data, uint32_t offset, DirectoryEntry *parent, uint32_t entryNumber, SectionEntries *sectionEntries, StringTable *stringTable, const SectionBlockSize &blockSize); 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 <utils/blocksize/SectionBlockSize.h>
#include <WUD/entities/FST/stringtable/StringTable.h> #include <WUD/entities/FST/stringtable/StringTable.h>
#include <WUD/entities/FST/sectionentry/SectionEntries.h> #include <WUD/entities/FST/sectionentry/SectionEntries.h>
#include <coreinit/debug.h>
#include <algorithm>
#include <utility>
#include "NodeEntry.h" #include "NodeEntry.h"
#include "DirectoryEntry.h" #include "DirectoryEntry.h"
#include "RootEntry.h" #include "RootEntry.h"
uint32_t NodeEntry::LENGTH = 16; std::optional<std::shared_ptr<NodeEntry>>
NodeEntry::AutoDeserialize(const std::vector<uint8_t> &data,
NodeEntry *NodeEntry::AutoDeserialize(uint8_t *data, uint32_t offset, DirectoryEntry *pParent, uint32_t eEntryNumber, SectionEntries *sectionEntries, uint32_t offset,
StringTable *stringTable, const SectionBlockSize &blockSize) { const std::optional<std::shared_ptr<DirectoryEntry>> &pParent,
uint8_t *curEntryData = &data[offset]; 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{}; NodeEntryParam param{};
param.permission = ((uint16_t *) &curEntryData[12])[0]; 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.entryNumber = eEntryNumber;
param.parent = pParent; param.parent = pParent;
param.type = curEntryData[0]; 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 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) { } 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) { } 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"); DEBUG_FUNCTION_LINE("FST Unknown Node Type");
return nullptr; return {};
} }
std::string NodeEntry::getName() const &{ std::string NodeEntry::getName() {
if (nameString != nullptr) { auto res = nameString->toString();
return nameString->toString(); if (res.has_value()) {
return res.value();
} }
return "ERROR"; return "[ERROR]";
} }
std::string NodeEntry::getFullPathInternal() const &{ std::string NodeEntry::getFullPathInternal() {
if (parent != nullptr) { if (parent.has_value()) {
return parent->getFullPathInternal().append("/").append(getName()); return parent.value()->getFullPathInternal().append("/").append(getName());
} }
return getName(); return getName();
} }
std::string NodeEntry::getFullPath() const &{ std::string NodeEntry::getFullPath() {
return getFullPathInternal(); return getFullPathInternal();
} }
std::string NodeEntry::getPath() const &{ std::string NodeEntry::getPath() {
if (parent != nullptr) { if (parent.has_value()) {
return parent->getFullPath().append("/"); return parent.value()->getFullPath().append("/");
} }
return "/"; return "/";
} }
@ -80,4 +117,23 @@ bool NodeEntry::isDirectory() const {
bool NodeEntry::isFile() const { bool NodeEntry::isFile() const {
return (entryType & ENTRY_TYPE_File) == ENTRY_TYPE_File; 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: public:
uint16_t permission{}; uint16_t permission{};
StringEntry *nameString{}; std::shared_ptr<StringEntry> nameString;
SectionEntry *sectionEntry{}; std::shared_ptr<SectionEntry> sectionEntry;
DirectoryEntry *parent{}; std::optional<std::shared_ptr<DirectoryEntry>> parent;
uint8_t entryType{}; uint8_t entryType{};
uint32_t entryNumber{}; uint32_t entryNumber{};
static NodeEntry *AutoDeserialize(uint8_t *data, uint32_t offset, DirectoryEntry *pParent, uint32_t eEntryNumber, SectionEntries *sectionEntries, static std::optional<std::shared_ptr<NodeEntry>>
StringTable *stringTable, const SectionBlockSize &blockSize); 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 ~NodeEntry() = default;
virtual void printPathRecursive() { virtual void printPathRecursive();
DEBUG_FUNCTION_LINE("%s", getFullPath().c_str());
}
[[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 isDirectory() const;
[[nodiscard]] bool isFile() const; [[nodiscard]] bool isFile() const;
static uint32_t LENGTH; static constexpr uint32_t LENGTH = 16;
private:
[[nodiscard]] std::string getFullPathInternal() const &; [[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: public:
uint16_t sectionNumber; uint16_t sectionNumber;
uint32_t entryNumber; uint32_t entryNumber;
DirectoryEntry *parent; std::optional<std::shared_ptr<DirectoryEntry>> parent;
uint16_t permission; uint16_t permission;
uint8_t type; uint8_t type;
uint32_t uint24; uint32_t uint24;

View File

@ -17,29 +17,28 @@
#include <coreinit/debug.h> #include <coreinit/debug.h>
#include "RootEntry.h" #include "RootEntry.h"
RootEntry::RootEntry(DirectoryEntry *input) { RootEntry::RootEntry(const std::shared_ptr<DirectoryEntry> &input) : DirectoryEntry(input) {
if ((input->entryType & ENTRY_TYPE_Directory) != ENTRY_TYPE_Directory || input->entryNumber != 0) {
OSFatal("Input is no root entry."); }
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()));
} }
DEBUG_FUNCTION_LINE("Failed to parse dir");
entryNumber = input->entryNumber; return {};
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));
} }

View File

@ -24,13 +24,17 @@
class RootEntry : public DirectoryEntry { class RootEntry : public DirectoryEntry {
explicit RootEntry(DirectoryEntry *input);
public: public:
~RootEntry() override = default; ~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" #include "SectionEntries.h"
SectionEntries::SectionEntries(uint8_t *data, uint32_t numberOfSections, const VolumeBlockSize &pBlockSize) { std::optional<std::shared_ptr<SectionEntry>> SectionEntries::getSection(uint16_t sectionNumber) const {
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 {
for (auto const &e: list) { for (auto const &e: list) {
if (e->sectionNumber == sectionNumber) { if (e->sectionNumber == sectionNumber) {
return e; return e;
} }
} }
return nullptr; return {};
} }
uint32_t SectionEntries::getSizeInBytes() const { uint32_t SectionEntries::getSizeInBytes() const {
return list.size() * 32; return list.size() * SectionEntry::LENGTH;
} }
uint32_t SectionEntries::size() const { uint32_t SectionEntries::size() const {
return list.size(); 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 #pragma once
#include <optional>
#include <memory>
#include <cstdint> #include <cstdint>
#include <utility>
#include <vector> #include <vector>
#include <utils/blocksize/VolumeBlockSize.h> #include <utils/blocksize/VolumeBlockSize.h>
#include <utils/logger.h>
#include "SectionEntry.h" #include "SectionEntry.h"
class SectionEntries { class SectionEntries {
public: public:
SectionEntries(uint8_t *data, uint32_t numberOfSections, const VolumeBlockSize &pBlockSize);
[[nodiscard]] uint32_t getSizeInBytes() const; [[nodiscard]] uint32_t getSizeInBytes() const;
[[nodiscard]] uint32_t size() 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 &{ [[nodiscard]] std::vector<std::shared_ptr<SectionEntry>> getSections() const &;
return list;
} static std::optional<std::shared_ptr<SectionEntries>> make_shared(const std::vector<uint8_t> &data, uint32_t numberOfSections, const VolumeBlockSize &pBlockSize);
private: 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" #include "SectionEntry.h"
SectionEntry::SectionEntry(uint8_t *data, uint32_t pSectionNumber, const VolumeBlockSize &pBlockSize) { SectionEntry::SectionEntry(const std::array<uint8_t, SectionEntry::LENGTH> &data, uint32_t pSectionNumber, const VolumeBlockSize &pBlockSize) {
auto *dataAsUint = (uint32_t *) data; auto *dataAsUint = (uint32_t *) data.data();
address = AddressInVolumeBlocks(pBlockSize, dataAsUint[0]); address = AddressInVolumeBlocks(pBlockSize, dataAsUint[0]);
size = SizeInVolumeBlocks(pBlockSize, dataAsUint[1]); size = SizeInVolumeBlocks(pBlockSize, dataAsUint[1]);

View File

@ -18,12 +18,15 @@
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include <array>
#include <utils/blocksize/AddressInVolumeBlocks.h> #include <utils/blocksize/AddressInVolumeBlocks.h>
#include <utils/blocksize/SizeInVolumeBlocks.h> #include <utils/blocksize/SizeInVolumeBlocks.h>
class SectionEntry { class SectionEntry {
public: 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; ~SectionEntry() = default;

View File

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

View File

@ -18,16 +18,18 @@
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include <memory>
#include <optional>
class StringTable; class StringTable;
class StringEntry { class StringEntry {
public: 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; uint32_t offset;
}; };

View File

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

View File

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

View File

@ -17,12 +17,21 @@
#include <cstring> #include <cstring>
#include "Content.h" #include "Content.h"
uint32_t Content::LENGTH = 0x30; Content::Content(uint32_t pId, uint16_t pIndex, uint16_t pType, uint64_t pEncryptedFileSize, const std::array<uint8_t, 0x14> &pHash) :
ID(pId),
Content::Content(uint8_t *data) { index(pIndex),
ID = ((uint32_t *) &data[0x00])[0]; type(pType),
index = ((uint16_t *) &data[0x04])[0]; encryptedFileSize(pEncryptedFileSize),
type = ((uint16_t *) &data[0x06])[0]; hash(pHash) {
encryptedFileSize = ((uint64_t *) &data[0x08])[0]; }
memcpy(hash, &data[0x10], 0x14);
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 #pragma once
#include <cstdint> #include <cstdint>
#include <optional>
#include <memory>
class Content { class Content {
public: public:
static uint32_t LENGTH; static constexpr uint32_t LENGTH = 0x30;
explicit Content(uint8_t *data);
uint16_t index;
uint32_t ID; uint32_t ID;
uint16_t index;
uint16_t type; uint16_t type;
uint64_t encryptedFileSize; 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" #include "TitleMetaData.h"
TitleMetaData::TitleMetaData(uint8_t *data) { #include <utility>
contentCount = ((uint16_t *) &data[0x1DE])[0]; #include <utils/logger.h>
TitleMetaData::TitleMetaData(std::vector<std::shared_ptr<Content>> pContentList) : contentList(std::move(pContentList)) {
// Get Contents // 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() { std::optional<std::shared_ptr<Content>> TitleMetaData::getContentByIndex(uint16_t i) {
for (auto &content: contentList) {
delete content;
}
}
Content *TitleMetaData::getContentByIndex(uint16_t i) {
for (auto &content: contentList) { for (auto &content: contentList) {
if (content->index == i) { if (content->index == i) {
return content; 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 #pragma once
#include <optional>
#include <memory>
#include <cstdint> #include <cstdint>
#include <vector> #include <vector>
#include "Content.h" #include "Content.h"
class TitleMetaData { class TitleMetaData {
public: 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; static std::optional<std::shared_ptr<TitleMetaData>> make_shared(const std::vector<uint8_t> &data);
Content *getContentByIndex(uint16_t index);
private: private:
uint16_t contentCount; explicit TitleMetaData(std::vector<std::shared_ptr<Content>> pContentList);
}; };

View File

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

View File

@ -20,21 +20,25 @@
#include <WUD/DiscReader.h> #include <WUD/DiscReader.h>
#include <WUD/content/WiiUContentsInformation.h> #include <WUD/content/WiiUContentsInformation.h>
#include <WUD/DiscReaderDiscDrive.h> #include <WUD/DiscReaderDiscDrive.h>
#include "WiiUManufactorDiscID.h" #include <memory>
#include "WiiUDiscID.h" #include "WiiUManufactorDiscId.h"
#include "WiiUDiscId.h"
class WiiUDiscHeader { class WiiUDiscHeader {
public: 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(); std::unique_ptr<WiiUManufactorDiscId> manufactorDiscId;
std::unique_ptr<WiiUDiscId> discId;
WiiUManufactorDiscID *manufactorDiscID = nullptr; std::unique_ptr<WiiUContentsInformation> wiiUContentsInformation;
WiiUDiscID *discId = nullptr;
WiiUContentsInformation *wiiUContentsInformation = nullptr;
static uint32_t LENGTH; 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 #pragma once
#include <memory>
#include <string> #include <string>
#include <WUD/DiscReader.h> #include <WUD/DiscReader.h>
#include <optional>
#include <utility>
class WiiUDiscID { class WiiUDiscId {
public: public:
WiiUDiscID(DiscReader *reader, uint32_t offset); static constexpr uint32_t LENGTH = 32768;
static constexpr uint32_t MAGIC = 0xCC549EB9;
static uint32_t LENGTH;
static uint32_t MAGIC;
uint8_t majorVersion;
uint8_t minorVersion; uint8_t minorVersion;
uint8_t majorVersion;
std::string footprint; std::string footprint;
static std::optional<std::unique_ptr<WiiUDiscId>> make_unique(const std::shared_ptr<DiscReader> &discReader, uint32_t offset);
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 * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/ ****************************************************************************/
#include "WiiUDiscID.h" #include "WiiUManufactorDiscId.h"
#include <coreinit/debug.h> #include <coreinit/debug.h>
#include <utils/logger.h>
uint32_t WiiUDiscID::LENGTH = 32768; std::optional<std::unique_ptr<WiiUManufactorDiscId>> WiiUManufactorDiscId::make_unique(const std::shared_ptr<DiscReader> &discReader) {
uint32_t WiiUDiscID::MAGIC = 0xCC549EB9; if (!discReader->IsReady()) {
DEBUG_FUNCTION_LINE("DiscReader is not ready");
WiiUDiscID::WiiUDiscID(DiscReader *reader, uint32_t offset) { return {};
auto data = (uint8_t *) malloc(LENGTH);
if (data == nullptr) {
OSFatal("Failed to alloc for WiiUDiscID");
} }
std::array<uint8_t, WiiUManufactorDiscId::LENGTH> data{};
if (!reader->readEncrypted(data, offset, LENGTH)) { if (!discReader->readEncrypted(data.data(), 0, WiiUManufactorDiscId::LENGTH)) {
OSFatal("Failed to read data"); DEBUG_FUNCTION_LINE("Failed to read data");
return {};
} }
return std::unique_ptr<WiiUManufactorDiscId>(new WiiUManufactorDiscId(data));
if (((uint32_t *) data)[0] != MAGIC) {
OSFatal("MAGIC FAIL");
}
majorVersion = data[5];
minorVersion = data[6];
footprint = std::string((char *) &data[32]);
free(data);
} }
WiiUManufactorDiscId::WiiUManufactorDiscId(const std::array<uint8_t, WiiUManufactorDiscId::LENGTH> &pData) : data(pData) {
this->data = pData;
}

View File

@ -16,15 +16,20 @@
****************************************************************************/ ****************************************************************************/
#pragma once #pragma once
#include <memory>
#include <cstdint> #include <cstdint>
#include <WUD/DiscReader.h> #include <WUD/DiscReader.h>
#include <optional>
class WiiUManufactorDiscID { class WiiUManufactorDiscId {
public: 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: 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 "FSTUtils.h"
#include "logger.h" #include "logger.h"
#include <filesystem> #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; std::string fullPath = givenFullPath;
if (strncmp(fullPath.c_str(), "/", 1) != 0) { if (strncmp(fullPath.c_str(), "/", 1) != 0) {
fullPath = "/" + fullPath; fullPath = "/" + fullPath;
} }
DirectoryEntry *pathOpt = root; auto pathOpt = std::optional(root);
std::filesystem::path asPath = fullPath; std::filesystem::path asPath = fullPath;
std::string dirPath = asPath.parent_path().string(); std::string dirPath = asPath.parent_path().string();
if (dirPath != "/") { if (dirPath != "/") {
pathOpt = getFileEntryDir(root, dirPath); pathOpt = getFileEntryDir(root, dirPath);
} }
if (pathOpt == nullptr) { if (!pathOpt.has_value()) {
return nullptr; return {};
} }
for (auto &child: pathOpt->getChildren()) { for (auto &child: pathOpt.value()->getChildren()) {
if (child->getFullPath() == fullPath) { if (child->getFullPath() == fullPath) {
return child; 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. // We add the "/" at the end so we don't get false results when using the "startWith" function.
if (!string.ends_with("/")) { if (!string.ends_with("/")) {
string += "/"; string += "/";
@ -44,18 +60,14 @@ DirectoryEntry *FSTUtils::getFileEntryDir(DirectoryEntry *curEntry, std::string
return getFileEntryDir(curChild, string); return getFileEntryDir(curChild, string);
} }
} }
return nullptr; return {};
} }
SectionEntry *FSTUtils::getSectionEntryForIndex(FST *pFst, uint16_t index) { std::optional<std::shared_ptr<SectionEntry>> FSTUtils::getSectionEntryForIndex(const std::shared_ptr<FST> &pFst, uint16_t index) {
if (pFst == nullptr || pFst->sectionEntries == nullptr) {
return nullptr;
}
for (const auto &entry: pFst->sectionEntries->getSections()) { for (const auto &entry: pFst->sectionEntries->getSections()) {
if (entry->sectionNumber == index) { if (entry->sectionNumber == index) {
return entry; 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 #pragma once
#include <string> #include <string>
@ -7,10 +23,10 @@
class FSTUtils { class FSTUtils {
public: 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 { class AddressInBlocks {
public: public:
explicit AddressInBlocks(const BlockSize &blockSize, uint32_t pValue) : blockSize(blockSize) { explicit AddressInBlocks(const BlockSize &pBlockSize, uint32_t pValue) : blockSize(pBlockSize), value(pValue) {
value = pValue;
} }
AddressInBlocks() = default; AddressInBlocks() = default;