mirror of
https://github.com/wiiu-env/wudd.git
synced 2024-11-26 03:34:18 +01:00
Use shared_ptr/unique_ptr in combination with std::optional instead of raw pointers
This commit is contained in:
parent
6919bdb44f
commit
fc2e994b72
@ -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;
|
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
};
|
};
|
@ -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) {
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
@ -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();
|
||||||
}
|
}
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
};
|
};
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
};
|
};
|
@ -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)) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -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;
|
|
||||||
};
|
};
|
@ -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 {};
|
||||||
}
|
}
|
||||||
WiiUPartition *SIPartition = nullptr;
|
tmp.push_back(partitionOpt.value());
|
||||||
|
}
|
||||||
|
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
};
|
};
|
@ -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) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
};
|
};
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
};
|
};
|
@ -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) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -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 ¶m, const std::shared_ptr<SectionEntries> §ionEntries,
|
||||||
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 ¶m,
|
||||||
|
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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -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 ¶m,
|
||||||
|
const std::shared_ptr<SectionEntries> §ionEntries,
|
||||||
|
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 ¶m,
|
||||||
|
const std::shared_ptr<StringEntry> &stringEntry,
|
||||||
|
const std::shared_ptr<SectionEntry> §ionEntry,
|
||||||
|
uint32_t parentEntryNumber,
|
||||||
|
uint32_t lastEntryNumber);
|
||||||
};
|
};
|
@ -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 ¶m,
|
||||||
|
const std::shared_ptr<SectionEntries> §ionEntries,
|
||||||
|
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 ¶m,
|
||||||
|
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) {
|
||||||
|
|
||||||
|
}
|
@ -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 ¶m,
|
||||||
|
const std::shared_ptr<SectionEntries> §ionEntries,
|
||||||
|
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 ¶m,
|
||||||
|
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{};
|
||||||
};
|
};
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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> §ionEntries,
|
||||||
|
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> §ionEntries,
|
||||||
|
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;
|
||||||
};
|
};
|
||||||
|
@ -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> §ionEntries,
|
||||||
|
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 "/";
|
||||||
}
|
}
|
||||||
@ -81,3 +118,22 @@ 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -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> §ionEntries,
|
||||||
|
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);
|
||||||
};
|
};
|
@ -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;
|
||||||
|
@ -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 ¶m,
|
||||||
|
const std::shared_ptr<SectionEntries> §ionEntries,
|
||||||
|
const std::shared_ptr<StringTable> &stringTable) {
|
||||||
|
auto dir = DirectoryEntry::parseData(data, param, sectionEntries, stringTable);
|
||||||
|
if (dir.has_value()) {
|
||||||
|
if ((dir.value()->entryType & ENTRY_TYPE_Directory) != ENTRY_TYPE_Directory || dir.value()->entryNumber != 0) {
|
||||||
|
DEBUG_FUNCTION_LINE("Input is no root entry.");
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
return std::shared_ptr<NodeEntry>(new RootEntry(dir.value()));
|
||||||
entryNumber = input->entryNumber;
|
|
||||||
parent = input->parent;
|
|
||||||
nameString = input->nameString;
|
|
||||||
if (nameString == nullptr) {
|
|
||||||
OSFatal("nameString was null");
|
|
||||||
}
|
}
|
||||||
entryType = input->entryType;
|
DEBUG_FUNCTION_LINE("Failed to parse dir");
|
||||||
|
return {};
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
@ -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 ¶m,
|
||||||
|
const std::shared_ptr<SectionEntries> §ionEntries,
|
||||||
|
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);
|
||||||
};
|
};
|
@ -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)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
@ -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]);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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) {
|
||||||
|
if (strings.count(address) > 0) {
|
||||||
return strings[address];
|
return strings[address];
|
||||||
|
}
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
StringEntry *StringTable::getStringEntry(uint32_t address) {
|
std::optional<std::shared_ptr<StringEntry>> StringTable::getStringEntry(uint32_t address) {
|
||||||
|
if (stringMap.count(address) > 0) {
|
||||||
return stringMap[address];
|
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 {};
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
@ -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) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
);
|
||||||
};
|
};
|
54
source/WUD/header/WiiUDiscId.cpp
Normal file
54
source/WUD/header/WiiUDiscId.cpp
Normal 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) {
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
};
|
};
|
@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
@ -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");
|
|
||||||
}
|
WiiUManufactorDiscId::WiiUManufactorDiscId(const std::array<uint8_t, WiiUManufactorDiscId::LENGTH> &pData) : data(pData) {
|
||||||
|
this->data = pData;
|
||||||
majorVersion = data[5];
|
|
||||||
minorVersion = data[6];
|
|
||||||
|
|
||||||
footprint = std::string((char *) &data[32]);
|
|
||||||
|
|
||||||
free(data);
|
|
||||||
}
|
}
|
@ -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);
|
||||||
};
|
};
|
@ -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 {};
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user