From 48a2981a93b643e0f7fcc371c7523379790fee2e Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Sun, 24 Nov 2019 13:47:48 -1000 Subject: [PATCH] Shared NFS data class not necessary --- include/nod/Util.hpp | 11 +- lib/DiscIONFS.cpp | 255 +++++++++++++++++++++---------------------- lib/DiscWii.cpp | 6 +- lib/nod.cpp | 10 +- 4 files changed, 139 insertions(+), 143 deletions(-) diff --git a/include/nod/Util.hpp b/include/nod/Util.hpp index 82e2df5..8a09093 100644 --- a/include/nod/Util.hpp +++ b/include/nod/Util.hpp @@ -54,14 +54,21 @@ namespace nod { /* define our own min/max to avoid MSVC BS */ template -inline T min(T a, T b) { +constexpr T min(T a, T b) { return a < b ? a : b; } template -inline T max(T a, T b) { +constexpr T max(T a, T b) { return a > b ? a : b; } +/* template-based div for flexible typing and avoiding a library call */ +template +constexpr auto div(T a, T b) { + struct DivTp { T quot, rem; }; + return DivTp{a / b, a % b}; +} + /* Log Module */ extern logvisor::Module LogModule; diff --git a/lib/DiscIONFS.cpp b/lib/DiscIONFS.cpp index 1c28499..7598bca 100644 --- a/lib/DiscIONFS.cpp +++ b/lib/DiscIONFS.cpp @@ -5,8 +5,6 @@ #include -#include - namespace nod { /* @@ -16,137 +14,132 @@ namespace nod { */ class DiscIONFS : public IDiscIO { - struct DiscIONFSShared { - std::vector> files; + std::vector> files; - struct NFSHead { - uint32_t magic; // EGGS - uint32_t version; - uint32_t unknown[2]; // Signature, UUID? - uint32_t lbaRangeCount; - struct { - uint32_t startBlock; - uint32_t numBlocks; - } lbaRanges[61]; - uint32_t endMagic; // SGGE - } nfsHead; + struct NFSHead { + uint32_t magic; // EGGS + uint32_t version; + uint32_t unknown[2]; // Signature, UUID? + uint32_t lbaRangeCount; + struct { + uint32_t startBlock; + uint32_t numBlocks; + } lbaRanges[61]; + uint32_t endMagic; // SGGE + } nfsHead; - uint8_t key[16]; + uint8_t key[16]; - uint32_t calculateNumFiles() const { - uint32_t totalBlockCount = 0; - for (uint32_t i = 0; i < nfsHead.lbaRangeCount; ++i) - totalBlockCount += nfsHead.lbaRanges[i].numBlocks; - return (uint64_t(totalBlockCount) * uint64_t(0x8000) + - (uint64_t(0x200) + uint64_t(0xF9FFFFF))) / uint64_t(0xFA00000); - } + uint32_t calculateNumFiles() const { + uint32_t totalBlockCount = 0; + for (uint32_t i = 0; i < nfsHead.lbaRangeCount; ++i) + totalBlockCount += nfsHead.lbaRanges[i].numBlocks; + return (uint64_t(totalBlockCount) * uint64_t(0x8000) + + (uint64_t(0x200) + uint64_t(0xF9FFFFF))) / uint64_t(0xFA00000); + } - struct FBO { - uint32_t file, block, lblock, offset; - }; - - FBO logicalToFBO(uint64_t offset) const { - auto blockAndRemBytes = std::lldiv(offset, 0x8000); /* 32768 bytes per block */ - uint32_t block = UINT32_MAX; - for (uint32_t i = 0, physicalBlock = 0; i < nfsHead.lbaRangeCount; ++i) { - const auto& range = nfsHead.lbaRanges[i]; - if (blockAndRemBytes.quot >= range.startBlock && blockAndRemBytes.quot - range.startBlock < range.numBlocks) { - block = physicalBlock + (blockAndRemBytes.quot - range.startBlock); - break; - } - physicalBlock += range.numBlocks; - } - /* This offset has no physical mapping, read zeroes */ - if (block == UINT32_MAX) - return {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX}; - auto fileAndRemBlocks = std::lldiv(block, 8000); /* 8000 blocks per file */ - return {uint32_t(fileAndRemBlocks.quot), uint32_t(fileAndRemBlocks.rem), - uint32_t(blockAndRemBytes.quot), uint32_t(blockAndRemBytes.rem)}; - } - - DiscIONFSShared(SystemStringView fpin, bool& err) { - /* Validate file path format */ - using SignedSize = std::make_signed::type; - const auto dotPos = SignedSize(fpin.rfind('.')); - const auto slashPos = SignedSize(fpin.find_last_of("/\\")); - if (fpin.size() <= 4 || dotPos == -1 || dotPos <= slashPos || - fpin.compare(slashPos + 1, 4, "hif_") || - fpin.compare(dotPos, fpin.size() - dotPos, ".nfs")) { - LogModule.report(logvisor::Error, - fmt("'{}' must begin with 'hif_' and end with '.nfs' to be accepted as an NFS image"), fpin); - err = true; - return; - } - - /* Load key file */ - const SystemString dir(fpin.begin(), fpin.begin() + slashPos + 1); - auto keyFile = NewFileIO(dir + "../code/htk.bin")->beginReadStream(); - if (!keyFile) - keyFile = NewFileIO(dir + "htk.bin")->beginReadStream(); - if (!keyFile) { - LogModule.report(logvisor::Error, fmt("Unable to open '{}../code/htk.bin' or '{}htk.bin'"), dir, dir); - err = true; - return; - } - if (keyFile->read(key, 16) != 16) { - LogModule.report(logvisor::Error, fmt("Unable to read from '{}../code/htk.bin' or '{}htk.bin'"), dir, dir); - err = true; - return; - } - - /* Load header from first file */ - const SystemString firstPath = fmt::format(fmt("{}hif_{:06}.nfs"), dir, 0); - files.push_back(NewFileIO(firstPath)); - auto rs = files.back()->beginReadStream(); - if (!rs) { - LogModule.report(logvisor::Error, fmt("'{}' does not exist"), firstPath); - err = true; - return; - } - if (rs->read(&nfsHead, 0x200) != 0x200) { - LogModule.report(logvisor::Error, fmt("Unable to read header from '{}'"), firstPath); - err = true; - return; - } - if (std::memcmp(&nfsHead.magic, "EGGS", 4)) { - LogModule.report(logvisor::Error, fmt("Invalid magic in '{}'"), firstPath); - err = true; - return; - } - nfsHead.lbaRangeCount = SBig(nfsHead.lbaRangeCount); - for (uint32_t i = 0; i < nfsHead.lbaRangeCount; ++i) { - auto& range = nfsHead.lbaRanges[i]; - range.startBlock = SBig(range.startBlock); - range.numBlocks = SBig(range.numBlocks); - } - - /* Ensure remaining files exist */ - const uint32_t numFiles = calculateNumFiles(); - files.reserve(numFiles); - for (uint32_t i = 1; i < numFiles; ++i) { - SystemString path = fmt::format(fmt("{}hif_{:06}.nfs"), dir, i); - files.push_back(NewFileIO(path)); - if (!files.back()->exists()) { - LogModule.report(logvisor::Error, fmt("'{}' does not exist"), path); - err = true; - return; - } - } - } + struct FBO { + uint32_t file, block, lblock, offset; }; - std::shared_ptr m_shared; + + FBO logicalToFBO(uint64_t offset) const { + auto blockAndRemBytes = nod::div(offset, uint64_t(0x8000)); /* 32768 bytes per block */ + uint32_t block = UINT32_MAX; + for (uint32_t i = 0, physicalBlock = 0; i < nfsHead.lbaRangeCount; ++i) { + const auto& range = nfsHead.lbaRanges[i]; + if (blockAndRemBytes.quot >= range.startBlock && blockAndRemBytes.quot - range.startBlock < range.numBlocks) { + block = physicalBlock + (blockAndRemBytes.quot - range.startBlock); + break; + } + physicalBlock += range.numBlocks; + } + /* This offset has no physical mapping, read zeroes */ + if (block == UINT32_MAX) + return {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX}; + auto fileAndRemBlocks = nod::div(block, uint32_t(8000)); /* 8000 blocks per file */ + return {uint32_t(fileAndRemBlocks.quot), uint32_t(fileAndRemBlocks.rem), + uint32_t(blockAndRemBytes.quot), uint32_t(blockAndRemBytes.rem)}; + } public: - DiscIONFS(SystemStringView fpin, bool& err) : m_shared(std::make_shared(fpin, err)) {} + DiscIONFS(SystemStringView fpin, bool& err) { + /* Validate file path format */ + using SignedSize = std::make_signed::type; + const auto dotPos = SignedSize(fpin.rfind('.')); + const auto slashPos = SignedSize(fpin.find_last_of("/\\")); + if (fpin.size() <= 4 || dotPos == -1 || dotPos <= slashPos || + fpin.compare(slashPos + 1, 4, "hif_") || + fpin.compare(dotPos, fpin.size() - dotPos, ".nfs")) { + LogModule.report(logvisor::Error, + fmt("'{}' must begin with 'hif_' and end with '.nfs' to be accepted as an NFS image"), fpin); + err = true; + return; + } + + /* Load key file */ + const SystemString dir(fpin.begin(), fpin.begin() + slashPos + 1); + auto keyFile = NewFileIO(dir + "../code/htk.bin")->beginReadStream(); + if (!keyFile) + keyFile = NewFileIO(dir + "htk.bin")->beginReadStream(); + if (!keyFile) { + LogModule.report(logvisor::Error, fmt("Unable to open '{}../code/htk.bin' or '{}htk.bin'"), dir, dir); + err = true; + return; + } + if (keyFile->read(key, 16) != 16) { + LogModule.report(logvisor::Error, fmt("Unable to read from '{}../code/htk.bin' or '{}htk.bin'"), dir, dir); + err = true; + return; + } + + /* Load header from first file */ + const SystemString firstPath = fmt::format(fmt("{}hif_{:06}.nfs"), dir, 0); + files.push_back(NewFileIO(firstPath)); + auto rs = files.back()->beginReadStream(); + if (!rs) { + LogModule.report(logvisor::Error, fmt("'{}' does not exist"), firstPath); + err = true; + return; + } + if (rs->read(&nfsHead, 0x200) != 0x200) { + LogModule.report(logvisor::Error, fmt("Unable to read header from '{}'"), firstPath); + err = true; + return; + } + if (std::memcmp(&nfsHead.magic, "EGGS", 4)) { + LogModule.report(logvisor::Error, fmt("Invalid magic in '{}'"), firstPath); + err = true; + return; + } + nfsHead.lbaRangeCount = SBig(nfsHead.lbaRangeCount); + for (uint32_t i = 0; i < nfsHead.lbaRangeCount; ++i) { + auto& range = nfsHead.lbaRanges[i]; + range.startBlock = SBig(range.startBlock); + range.numBlocks = SBig(range.numBlocks); + } + + /* Ensure remaining files exist */ + const uint32_t numFiles = calculateNumFiles(); + files.reserve(numFiles); + for (uint32_t i = 1; i < numFiles; ++i) { + SystemString path = fmt::format(fmt("{}hif_{:06}.nfs"), dir, i); + files.push_back(NewFileIO(path)); + if (!files.back()->exists()) { + LogModule.report(logvisor::Error, fmt("'{}' does not exist"), path); + err = true; + return; + } + } + } class ReadStream : public IReadStream { friend class DiscIONFS; - std::shared_ptr m_shared; + const DiscIONFS& m_parent; std::unique_ptr m_rs; std::unique_ptr m_aes; /* Physical address - all UINT32_MAX indicates logical zero block */ - DiscIONFSShared::FBO m_physAddr; + DiscIONFS::FBO m_physAddr; /* Logical address */ uint64_t m_offset; @@ -156,24 +149,24 @@ public: uint32_t m_curFile = UINT32_MAX; uint32_t m_curBlock = UINT32_MAX; - ReadStream(std::shared_ptr shared, uint64_t offset, bool& err) - : m_shared(std::move(shared)), m_aes(NewAES()), + ReadStream(const DiscIONFS& parent, uint64_t offset, bool& err) + : m_parent(parent), m_aes(NewAES()), m_physAddr({UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX}), m_offset(offset) { - m_aes->setKey(m_shared->key); - setNewLogicalAddr(offset); + m_aes->setKey(m_parent.key); + setLogicalAddr(offset); } uint8_t m_encBuf[0x8000] = {}; uint8_t m_decBuf[0x8000] = {}; void setCurFile(uint32_t curFile) { - if (curFile >= m_shared->files.size()) { + if (curFile >= m_parent.files.size()) { LogModule.report(logvisor::Error, fmt("Out of bounds NFS file access")); return; } m_curFile = curFile; m_curBlock = UINT32_MAX; - m_rs = m_shared->files[m_curFile]->beginReadStream(); + m_rs = m_parent.files[m_curFile]->beginReadStream(); } void setCurBlock(uint32_t curBlock) { @@ -181,7 +174,7 @@ public: m_rs->seek(m_curBlock * 0x8000 + 0x200); } - void setNewPhysicalAddr(DiscIONFSShared::FBO physAddr) { + void setPhysicalAddr(DiscIONFS::FBO physAddr) { /* If we're just changing the offset, nothing else needs to be done */ if (m_physAddr.file == physAddr.file && m_physAddr.block == physAddr.block) { m_physAddr.offset = physAddr.offset; @@ -217,9 +210,7 @@ public: m_aes->decrypt((const uint8_t*)ivBuf, m_encBuf, m_decBuf, 0x8000); } - void setNewLogicalAddr(uint64_t addr) { - setNewPhysicalAddr(m_shared->logicalToFBO(m_offset)); - } + void setLogicalAddr(uint64_t addr) { setPhysicalAddr(m_parent.logicalToFBO(m_offset)); } public: uint64_t read(void* buf, uint64_t length) override { @@ -237,7 +228,7 @@ public: dst += readSize; rem -= readSize; m_offset += readSize; - setNewLogicalAddr(m_offset); + setLogicalAddr(m_offset); } return dst - (uint8_t*)buf; @@ -250,13 +241,13 @@ public: m_offset += offset; else return; - setNewLogicalAddr(m_offset); + setLogicalAddr(m_offset); } }; std::unique_ptr beginReadStream(uint64_t offset) const override { bool err = false; - auto ret = std::unique_ptr(new ReadStream(m_shared, offset, err)); + auto ret = std::unique_ptr(new ReadStream(*this, offset, err)); if (err) return {}; diff --git a/lib/DiscWii.cpp b/lib/DiscWii.cpp index 1347990..cea4361 100644 --- a/lib/DiscWii.cpp +++ b/lib/DiscWii.cpp @@ -373,7 +373,7 @@ public: } uint64_t position() const override { return m_offset; } uint64_t read(void* buf, uint64_t length) override { - auto blockAndRemOff = std::lldiv(m_offset, 0x7c00); + auto blockAndRemOff = nod::div(m_offset, uint64_t(0x7c00)); uint64_t rem = length; uint8_t* dst = (uint8_t*)buf; @@ -1239,7 +1239,7 @@ std::optional DiscBuilderWii::CalculateTotalSizeRequired(SystemStringV std::optional sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeBuild(dirIn, PartitionKind::Data, true); if (!sz) return sz; - auto szDiv = std::lldiv(*sz, 0x1F0000); + auto szDiv = nod::div(*sz, uint64_t(0x1F0000)); if (szDiv.rem) ++szDiv.quot; sz = szDiv.quot * 0x200000; @@ -1346,7 +1346,7 @@ std::optional DiscMergerWii::CalculateTotalSizeRequired(DiscWii& sourc std::optional sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeMerge(sourceDisc.getDataPartition(), dirIn); if (!sz) return std::nullopt; - auto szDiv = std::lldiv(*sz, 0x1F0000); + auto szDiv = nod::div(*sz, uint64_t(0x1F0000)); if (szDiv.rem) ++szDiv.quot; sz = szDiv.quot * 0x200000; diff --git a/lib/nod.cpp b/lib/nod.cpp index d679fab..a0c8640 100644 --- a/lib/nod.cpp +++ b/lib/nod.cpp @@ -68,16 +68,14 @@ std::unique_ptr OpenDiscFromImage(SystemStringView path, bool& isWii) std::unique_ptr ret; if (isWii) { ret = std::make_unique(std::move(discIO), err); - if (err) { - return nullptr; - } + if (err) + return {}; return ret; } ret = std::make_unique(std::move(discIO), err); - if (err) { - return nullptr; - } + if (err) + return {}; return ret; }