diff --git a/driver/main.cpp b/driver/main.cpp index a916854..76a4c93 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -40,7 +40,7 @@ int main(int argc, char* argv[]) logvisor::RegisterConsoleLogger(); nod::ExtractionContext ctx = { true, true, [&](const std::string& str, float c){ - fprintf(stderr, "Current node: %s, Extraction %g%% Complete\n", str.c_str(), c); + fprintf(stderr, "Current node: %s, Extraction %g%% Complete\n", str.c_str(), c * 100.f); }}; const nod::SystemChar* inDir = nullptr; const nod::SystemChar* outDir = _S("."); @@ -58,18 +58,13 @@ int main(int argc, char* argv[]) outDir = argv[a]; } - size_t lastIdx = -1; - auto progFunc = [&](size_t idx, const nod::SystemString& name, size_t bytes) + auto progFunc = [&](float prog, const nod::SystemString& name, size_t bytes) { - if (idx != lastIdx) - { - lastIdx = idx; - printf("\n"); - } + nod::Printf(_S("\r ")); if (bytes != -1) - nod::Printf(_S("\r%s %" PRISize " B"), name.c_str(), bytes); + nod::Printf(_S("\r%g%% %s %" PRISize " B"), prog * 100.f, name.c_str(), bytes); else - nod::Printf(_S("\r%s"), name.c_str()); + nod::Printf(_S("\r%g%% %s"), prog * 100.f, name.c_str()); fflush(stdout); }; @@ -135,7 +130,7 @@ int main(int argc, char* argv[]) if (nod::DiscBuilderGCN::CalculateTotalSizeRequired(argv[4], argv[5]) == -1) return 1; - bool ret; + nod::EBuildResult ret; if (argc < 8) { @@ -151,7 +146,7 @@ int main(int argc, char* argv[]) } printf("\n"); - if (!ret) + if (ret != nod::EBuildResult::Success) return 1; } else if (!strcasecmp(argv[1], _S("makewii"))) @@ -202,7 +197,7 @@ int main(int argc, char* argv[]) if (nod::DiscBuilderWii::CalculateTotalSizeRequired(argv[4], argv[5], dual) == -1) return 1; - bool ret; + nod::EBuildResult ret; if (argc < 9) { @@ -218,7 +213,7 @@ int main(int argc, char* argv[]) } printf("\n"); - if (!ret) + if (ret != nod::EBuildResult::Success) return 1; } else if (!strcasecmp(argv[1], _S("mergegcn"))) @@ -252,7 +247,7 @@ int main(int argc, char* argv[]) if (nod::DiscMergerGCN::CalculateTotalSizeRequired(static_cast(*disc), argv[2]) == -1) return 1; - bool ret; + nod::EBuildResult ret; if (argc < 5) { @@ -268,7 +263,7 @@ int main(int argc, char* argv[]) } printf("\n"); - if (!ret) + if (ret != nod::EBuildResult::Success) return 1; } else if (!strcasecmp(argv[1], _S("mergewii"))) @@ -303,7 +298,7 @@ int main(int argc, char* argv[]) if (nod::DiscMergerWii::CalculateTotalSizeRequired(static_cast(*disc), argv[2], dual) == -1) return 1; - bool ret; + nod::EBuildResult ret; if (argc < 5) { @@ -319,7 +314,7 @@ int main(int argc, char* argv[]) } printf("\n"); - if (!ret) + if (ret != nod::EBuildResult::Success) return 1; } else diff --git a/include/nod/DiscBase.hpp b/include/nod/DiscBase.hpp index 2bc7780..256c95b 100644 --- a/include/nod/DiscBase.hpp +++ b/include/nod/DiscBase.hpp @@ -15,7 +15,14 @@ namespace nod { -using FProgress = std::function; +using FProgress = std::function; + +enum class EBuildResult +{ + Success, + Failed, + DiskFull +}; class FSTNode { @@ -237,6 +244,18 @@ public: uint64_t m_offset; public: mutable size_t m_curNodeIdx = 0; + float getProgressFactor() const { return getNodeCount() ? m_curNodeIdx / float(getNodeCount()) : 0.f; } + float getProgressFactorMidFile(size_t curByte, size_t totalBytes) const + { + if (!getNodeCount()) + return 0.f; + + if (totalBytes) + return (m_curNodeIdx + (curByte / float(totalBytes))) / float(getNodeCount()); + else + return m_curNodeIdx / float(getNodeCount()); + } + IPartition(const DiscBase& parent, Kind kind, uint64_t offset) : m_parent(parent), m_kind(kind), m_offset(offset) {} virtual uint64_t normalizeOffset(uint64_t anOffset) const {return anOffset;} @@ -342,18 +361,25 @@ public: size_t m_buildNameOff = 0; virtual uint64_t userAllocate(uint64_t reqSz, IPartWriteStream& ws)=0; virtual uint32_t packOffset(uint64_t offset) const=0; + + void recursiveBuildNodesPre(const SystemChar* dirIn, uint64_t dolInode); bool recursiveBuildNodes(IPartWriteStream& ws, bool system, const SystemChar* dirIn, uint64_t dolInode); + bool recursiveBuildFST(const SystemChar* dirIn, uint64_t dolInode, std::function incParents); + + void recursiveMergeNodesPre(const DiscBase::IPartition::Node* nodeIn, const SystemChar* dirIn); bool recursiveMergeNodes(IPartWriteStream& ws, bool system, const DiscBase::IPartition::Node* nodeIn, const SystemChar* dirIn, const SystemString& keyPath); bool recursiveMergeFST(const DiscBase::IPartition::Node* nodeIn, const SystemChar* dirIn, std::function incParents, const SystemString& keyPath); + static bool RecursiveCalculateTotalSize(uint64_t& totalSz, const DiscBase::IPartition::Node* nodeIn, const SystemChar* dirIn); + void addBuildName(const SystemString& str) { SystemUTF8View utf8View(str); @@ -396,11 +422,26 @@ protected: std::vector> m_partitions; int64_t m_discCapacity; public: - std::function m_progressCB; + FProgress m_progressCB; size_t m_progressIdx = 0; + size_t m_progressTotal = 0; + float getProgressFactor() const + { + return m_progressTotal ? std::min(1.f, m_progressIdx / float(m_progressTotal)) : 0.f; + } + float getProgressFactorMidFile(size_t curByte, size_t totalBytes) const + { + if (!m_progressTotal) + return 0.f; + + if (totalBytes) + return (m_progressIdx + (curByte / float(totalBytes))) / float(m_progressTotal); + else + return m_progressIdx / float(m_progressTotal); + } + virtual ~DiscBuilderBase() = default; - DiscBuilderBase(const SystemChar* outPath, int64_t discCapacity, - std::function progressCB) + DiscBuilderBase(const SystemChar* outPath, int64_t discCapacity, FProgress progressCB) : m_outPath(outPath), m_fileIO(NewFileIO(outPath, discCapacity)), m_discCapacity(discCapacity), m_progressCB(progressCB) {} DiscBuilderBase(DiscBuilderBase&&) = default; diff --git a/include/nod/DiscGCN.hpp b/include/nod/DiscGCN.hpp index 5390a3e..6582437 100644 --- a/include/nod/DiscGCN.hpp +++ b/include/nod/DiscGCN.hpp @@ -21,8 +21,8 @@ class DiscBuilderGCN : public DiscBuilderBase public: DiscBuilderGCN(const SystemChar* outPath, const char gameID[6], const char* gameTitle, uint32_t fstMemoryAddr, FProgress progressCB); - bool buildFromDirectory(const SystemChar* dirIn, const SystemChar* dolIn, - const SystemChar* apploaderIn); + EBuildResult buildFromDirectory(const SystemChar* dirIn, const SystemChar* dolIn, + const SystemChar* apploaderIn); static uint64_t CalculateTotalSizeRequired(const SystemChar* dirIn, const SystemChar* dolIn); }; @@ -32,7 +32,7 @@ class DiscMergerGCN DiscBuilderGCN m_builder; public: DiscMergerGCN(const SystemChar* outPath, DiscGCN& sourceDisc, FProgress progressCB); - bool mergeFromDirectory(const SystemChar* dirIn); + EBuildResult mergeFromDirectory(const SystemChar* dirIn); static uint64_t CalculateTotalSizeRequired(DiscGCN& sourceDisc, const SystemChar* dirIn); }; diff --git a/include/nod/DiscWii.hpp b/include/nod/DiscWii.hpp index 5cbcc2e..a6a0547 100644 --- a/include/nod/DiscWii.hpp +++ b/include/nod/DiscWii.hpp @@ -21,10 +21,10 @@ class DiscBuilderWii : public DiscBuilderBase public: DiscBuilderWii(const SystemChar* outPath, const char gameID[6], const char* gameTitle, bool dualLayer, FProgress progressCB); - bool buildFromDirectory(const SystemChar* dirIn, - const SystemChar* dolIn, - const SystemChar* apploaderIn, - const SystemChar* partHeadIn); + EBuildResult buildFromDirectory(const SystemChar* dirIn, + const SystemChar* dolIn, + const SystemChar* apploaderIn, + const SystemChar* partHeadIn); static uint64_t CalculateTotalSizeRequired(const SystemChar* dirIn, const SystemChar* dolIn, bool& dualLayer); }; @@ -36,7 +36,7 @@ class DiscMergerWii public: DiscMergerWii(const SystemChar* outPath, DiscWii& sourceDisc, bool dualLayer, FProgress progressCB); - bool mergeFromDirectory(const SystemChar* dirIn); + EBuildResult mergeFromDirectory(const SystemChar* dirIn); static uint64_t CalculateTotalSizeRequired(DiscWii& sourceDisc, const SystemChar* dirIn, bool& dualLayer); }; diff --git a/include/nod/IFileIO.hpp b/include/nod/IFileIO.hpp index 009c1c9..31f89fb 100644 --- a/include/nod/IFileIO.hpp +++ b/include/nod/IFileIO.hpp @@ -20,7 +20,55 @@ public: { virtual ~IWriteStream() {} virtual uint64_t write(const void* buf, uint64_t length)=0; - virtual uint64_t copyFromDisc(struct IPartReadStream& discio, uint64_t length)=0; + + uint64_t copyFromDisc(IPartReadStream& discio, uint64_t length) + { + uint64_t read = 0; + uint8_t buf[0x7c00]; + while (length) + { + uint64_t thisSz = nod::min(uint64_t(0x7c00), length); + uint64_t readSz = discio.read(buf, thisSz); + if (thisSz != readSz) + { + LogModule.report(logvisor::Error, "unable to read enough from disc"); + return read; + } + if (write(buf, readSz) != readSz) + { + LogModule.report(logvisor::Error, "unable to write in file"); + return read; + } + length -= thisSz; + read += thisSz; + } + return read; + } + uint64_t copyFromDisc(IPartReadStream& discio, uint64_t length, const std::function& prog) + { + uint64_t read = 0; + uint8_t buf[0x7c00]; + uint64_t total = length; + while (length) + { + uint64_t thisSz = nod::min(uint64_t(0x7c00), length); + uint64_t readSz = discio.read(buf, thisSz); + if (thisSz != readSz) + { + LogModule.report(logvisor::Error, "unable to read enough from disc"); + return read; + } + if (write(buf, readSz) != readSz) + { + LogModule.report(logvisor::Error, "unable to write in file"); + return read; + } + length -= thisSz; + read += thisSz; + prog(read / float(total)); + } + return read; + } }; virtual std::unique_ptr beginWriteStream() const=0; virtual std::unique_ptr beginWriteStream(uint64_t offset) const=0; diff --git a/lib/DiscBase.cpp b/lib/DiscBase.cpp index be79386..ceb4ca0 100644 --- a/lib/DiscBase.cpp +++ b/lib/DiscBase.cpp @@ -99,7 +99,7 @@ bool DiscBase::IPartition::Node::extractToDirectory(const SystemString& basePath { ++m_parent.m_curNodeIdx; if (ctx.verbose && ctx.progressCB && !getName().empty()) - ctx.progressCB(getName(), float(m_parent.m_curNodeIdx * 100.f) / m_parent.getNodeCount()); + ctx.progressCB(getName(), m_parent.m_curNodeIdx / float(m_parent.getNodeCount())); if (Mkdir(path.c_str(), 0755) && errno != EEXIST) { LogModule.report(logvisor::Error, _S("unable to mkdir '%s'"), path.c_str()); @@ -112,9 +112,8 @@ bool DiscBase::IPartition::Node::extractToDirectory(const SystemString& basePath else if (m_kind == Kind::File) { Sstat theStat; - ++m_parent.m_curNodeIdx; if (ctx.verbose && ctx.progressCB) - ctx.progressCB(getName(), float(m_parent.m_curNodeIdx * 100.f) / m_parent.getNodeCount()); + ctx.progressCB(getName(), m_parent.m_curNodeIdx / float(m_parent.getNodeCount())); if (ctx.force || Stat(path.c_str(), &theStat)) { @@ -122,8 +121,14 @@ bool DiscBase::IPartition::Node::extractToDirectory(const SystemString& basePath std::unique_ptr ws = NewFileIO(path)->beginWriteStream(); if (!rs || !ws) return false; - ws->copyFromDisc(*rs, m_discLength); + ws->copyFromDisc(*rs, m_discLength, + [&](float prog) + { + if (ctx.verbose && ctx.progressCB) + ctx.progressCB(getName(), (m_parent.m_curNodeIdx + prog) / float(m_parent.getNodeCount())); + }); } + ++m_parent.m_curNodeIdx; } return true; } @@ -263,6 +268,26 @@ static size_t PatchDOL(IFileIO::IReadStream& in, IPartWriteStream& out, size_t s return out.write(buf.get(), sz); } +void DiscBuilderBase::PartitionBuilderBase::recursiveBuildNodesPre(const SystemChar* dirIn, + uint64_t dolInode) +{ + DirectoryEnumerator dEnum(dirIn, DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true); + for (const DirectoryEnumerator::Entry& e : dEnum) + { + if (e.m_isDir) + { + recursiveBuildNodesPre(e.m_path.c_str(), dolInode); + } + else + { + if (dolInode == GetInode(e.m_path.c_str())) + continue; + + ++m_parent.m_progressTotal; + } + } +} + bool DiscBuilderBase::PartitionBuilderBase::recursiveBuildNodes(IPartWriteStream& ws, bool system, const SystemChar* dirIn, @@ -299,12 +324,12 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveBuildNodes(IPartWriteStream { bool patched; xferSz = PatchDOL(*rs, ws, e.m_fileSz, patched); - m_parent.m_progressCB(++m_parent.m_progressIdx, e.m_name + (patched ? _S(" [PATCHED]") : _S("")), xferSz); + m_parent.m_progressCB(m_parent.getProgressFactor(), e.m_name + (patched ? _S(" [PATCHED]") : _S("")), xferSz); + ++m_parent.m_progressIdx; } else { char buf[0x8000]; - ++m_parent.m_progressIdx; while (xferSz < e.m_fileSz) { size_t rdSz = rs->read(buf, nod::min(size_t(0x8000ul), e.m_fileSz - xferSz)); @@ -312,8 +337,9 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveBuildNodes(IPartWriteStream break; ws.write(buf, rdSz); xferSz += rdSz; - m_parent.m_progressCB(m_parent.m_progressIdx, e.m_name, xferSz); + m_parent.m_progressCB(m_parent.getProgressFactorMidFile(xferSz, e.m_fileSz), e.m_name, xferSz); } + ++m_parent.m_progressIdx; } for (size_t i=0 ; i fileNodes; + std::unordered_map dirNodes; + if (nodeIn) + { + fileNodes.reserve(nodeIn->size()); + dirNodes.reserve(nodeIn->size()); + for (const Partition::Node& ch : *nodeIn) + { + if (ch.getKind() == Partition::Node::Kind::File) + fileNodes.insert(std::make_pair(ch.getName(), &ch)); + else if (ch.getKind() == Partition::Node::Kind::Directory) + dirNodes.insert(std::make_pair(ch.getName(), &ch)); + } + } + + /* Merge this directory's files */ + if (dirIn) + { + DirectoryEnumerator dEnum(dirIn, DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true); + for (const DirectoryEnumerator::Entry& e : dEnum) + { + SystemUTF8View nameView(e.m_name); + + if (e.m_isDir) + { + auto search = dirNodes.find(nameView.utf8_str()); + if (search != dirNodes.cend()) + { + recursiveMergeNodesPre(search->second, e.m_path.c_str()); + dirNodes.erase(search); + } + else + { + recursiveMergeNodesPre(nullptr, e.m_path.c_str()); + } + } + else + { + fileNodes.erase(nameView.utf8_str()); + ++m_parent.m_progressTotal; + } + } + } + + /* Write-through remaining dir nodes */ + for (const auto& p : dirNodes) + { + recursiveMergeNodesPre(p.second, nullptr); + } + + /* Write-through remaining file nodes */ + m_parent.m_progressTotal += fileNodes.size(); +} + bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeNodes(IPartWriteStream& ws, bool system, const DiscBase::IPartition::Node* nodeIn, @@ -426,13 +510,13 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeNodes(IPartWriteStream { bool patched; xferSz = PatchDOL(*rs, ws, e.m_fileSz, patched); - m_parent.m_progressCB(++m_parent.m_progressIdx, e.m_name + + m_parent.m_progressCB(m_parent.getProgressFactor(), e.m_name + (patched ? _S(" [PATCHED]") : _S("")), xferSz); + ++m_parent.m_progressIdx; } else { char buf[0x8000]; - ++m_parent.m_progressIdx; while (xferSz < e.m_fileSz) { size_t rdSz = rs->read(buf, nod::min(size_t(0x8000ul), e.m_fileSz - xferSz)); @@ -440,8 +524,9 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeNodes(IPartWriteStream break; ws.write(buf, rdSz); xferSz += rdSz; - m_parent.m_progressCB(m_parent.m_progressIdx, e.m_name, xferSz); + m_parent.m_progressCB(m_parent.getProgressFactorMidFile(xferSz, e.m_fileSz), e.m_name, xferSz); } + ++m_parent.m_progressIdx; } for (size_t i=0 ; iread(buf, nod::min(size_t(0x8000), size_t(ch.size() - xferSz))); @@ -500,8 +585,9 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeNodes(IPartWriteStream break; ws.write(buf, rdSz); xferSz += rdSz; - m_parent.m_progressCB(m_parent.m_progressIdx, sysName.sys_str(), xferSz); + m_parent.m_progressCB(m_parent.getProgressFactorMidFile(xferSz, ch.size()), sysName.sys_str(), xferSz); } + ++m_parent.m_progressIdx; } for (size_t i=0 ; igetFSTRoot(), dirIn); + /* Clear file */ + m_parent.m_progressCB(m_parent.getProgressFactor(), _S("Preparing output image"), -1); ++m_parent.m_progressIdx; - m_parent.m_progressCB(m_parent.m_progressIdx, _S("Preparing output image"), -1); /* Add root node */ m_buildNodes.emplace_back(true, m_buildNameOff, 0, 1); @@ -780,8 +875,9 @@ bool DiscBuilderBase::PartitionBuilderBase::mergeFromDirectory(IPartWriteStream& bool patched; PatchDOL(dolBuf, xferSz, patched); ws.write(dolBuf.get(), xferSz); - m_parent.m_progressCB(++m_parent.m_progressIdx, SystemString(_S("")) + + m_parent.m_progressCB(m_parent.getProgressFactor(), SystemString(_S("")) + (patched ? _S(" [PATCHED]") : _S("")), xferSz); + ++m_parent.m_progressIdx; for (size_t i=0 ; iread(buf, 8192); @@ -278,8 +277,9 @@ public: "apploader flows into user area (one or the other is too big)"); return false; } - m_parent.m_progressCB(m_parent.m_progressIdx, apploaderName, xferSz); + m_parent.m_progressCB(m_parent.getProgressFactor(), apploaderName, xferSz); } + ++m_parent.m_progressIdx; return true; }); } @@ -298,7 +298,6 @@ public: std::unique_ptr apploaderBuf = partIn->getApploaderBuf(); size_t apploaderSz = partIn->getApploaderSize(); SystemString apploaderName(_S("")); - ++m_parent.m_progressIdx; ws.write(apploaderBuf.get(), apploaderSz); xferSz += apploaderSz; if (0x2440 + xferSz >= m_curUser) @@ -307,31 +306,32 @@ public: "apploader flows into user area (one or the other is too big)"); return false; } - m_parent.m_progressCB(m_parent.m_progressIdx, apploaderName, xferSz); + m_parent.m_progressCB(m_parent.getProgressFactor(), apploaderName, xferSz); + ++m_parent.m_progressIdx; return true; }); } }; -bool DiscBuilderGCN::buildFromDirectory(const SystemChar* dirIn, const SystemChar* dolIn, - const SystemChar* apploaderIn) +EBuildResult DiscBuilderGCN::buildFromDirectory(const SystemChar* dirIn, const SystemChar* dolIn, + const SystemChar* apploaderIn) { if (!m_fileIO->beginWriteStream()) - return false; + return EBuildResult::Failed; if (!CheckFreeSpace(m_outPath.c_str(), 0x57058000)) { LogModule.report(logvisor::Error, _S("not enough free disk space for %s"), m_outPath.c_str()); - return false; + return EBuildResult::DiskFull; } + m_progressCB(getProgressFactor(), _S("Preallocating image"), -1); ++m_progressIdx; - m_progressCB(m_progressIdx, _S("Preallocating image"), -1); auto ws = m_fileIO->beginWriteStream(0x57058000 - 1); if (!ws) - return false; + return EBuildResult::Failed; ws->write("", 1); PartitionBuilderGCN& pb = static_cast(*m_partitions[0]); - return pb.buildFromDirectory(dirIn, dolIn, apploaderIn); + return pb.buildFromDirectory(dirIn, dolIn, apploaderIn) ? EBuildResult::Success : EBuildResult::Failed; } uint64_t DiscBuilderGCN::CalculateTotalSizeRequired(const SystemChar* dirIn, const SystemChar* dolIn) @@ -361,24 +361,25 @@ DiscMergerGCN::DiscMergerGCN(const SystemChar* outPath, DiscGCN& sourceDisc, FPr : m_sourceDisc(sourceDisc), m_builder(sourceDisc.makeMergeBuilder(outPath, progressCB)) {} -bool DiscMergerGCN::mergeFromDirectory(const SystemChar* dirIn) +EBuildResult DiscMergerGCN::mergeFromDirectory(const SystemChar* dirIn) { if (!m_builder.getFileIO().beginWriteStream()) - return false; + return EBuildResult::Failed; if (!CheckFreeSpace(m_builder.m_outPath.c_str(), 0x57058000)) { LogModule.report(logvisor::Error, _S("not enough free disk space for %s"), m_builder.m_outPath.c_str()); - return false; + return EBuildResult::DiskFull; } + m_builder.m_progressCB(m_builder.getProgressFactor(), _S("Preallocating image"), -1); ++m_builder.m_progressIdx; - m_builder.m_progressCB(m_builder.m_progressIdx, _S("Preallocating image"), -1); auto ws = m_builder.m_fileIO->beginWriteStream(0x57058000 - 1); if (!ws) - return false; + return EBuildResult::Failed; ws->write("", 1); PartitionBuilderGCN& pb = static_cast(*m_builder.m_partitions[0]); - return pb.mergeFromDirectory(static_cast(m_sourceDisc.getDataPartition()), dirIn); + return pb.mergeFromDirectory(static_cast(m_sourceDisc.getDataPartition()), dirIn) ? + EBuildResult::Success : EBuildResult::Failed; } uint64_t DiscMergerGCN::CalculateTotalSizeRequired(DiscGCN& sourceDisc, const SystemChar* dirIn) diff --git a/lib/DiscWii.cpp b/lib/DiscWii.cpp index 8a4b522..990e549 100644 --- a/lib/DiscWii.cpp +++ b/lib/DiscWii.cpp @@ -928,7 +928,6 @@ public: bool good = false; uint64_t attempts = 0; SystemString bfName(_S("Brute force attempts")); - ++m_parent.m_progressIdx; for (int w=0 ; w<7 ; ++w) { for (uint64_t i=0 ; iread(buf, 8192); @@ -1008,8 +1007,9 @@ public: "apploader flows into user area (one or the other is too big)"); return false; } - m_parent.m_progressCB(m_parent.m_progressIdx, apploaderName, xferSz); + m_parent.m_progressCB(m_parent.getProgressFactor(), apploaderName, xferSz); } + ++m_parent.m_progressIdx; return true; }, phBuf.get(), phSz, theStat.st_size); } @@ -1030,7 +1030,6 @@ public: std::unique_ptr apploaderBuf = partIn->getApploaderBuf(); size_t apploaderSz = partIn->getApploaderSize(); SystemString apploaderName(_S("")); - ++m_parent.m_progressIdx; cws.write(apploaderBuf.get(), apploaderSz); xferSz += apploaderSz; if (0x2440 + xferSz >= 0x1F0000) @@ -1039,69 +1038,70 @@ public: "apploader flows into user area (one or the other is too big)"); return false; } - m_parent.m_progressCB(m_parent.m_progressIdx, apploaderName, xferSz); + m_parent.m_progressCB(m_parent.getProgressFactor(), apploaderName, xferSz); + ++m_parent.m_progressIdx; return true; }, phBuf.get(), phSz, partIn->getApploaderSize()); } }; -bool DiscBuilderWii::buildFromDirectory(const SystemChar* dirIn, const SystemChar* dolIn, - const SystemChar* apploaderIn, const SystemChar* partHeadIn) +EBuildResult DiscBuilderWii::buildFromDirectory(const SystemChar* dirIn, const SystemChar* dolIn, + const SystemChar* apploaderIn, const SystemChar* partHeadIn) { PartitionBuilderWii& pb = static_cast(*m_partitions[0]); uint64_t filledSz = pb.m_baseOffset; if (!m_fileIO->beginWriteStream()) - return false; + return EBuildResult::Failed; if (!CheckFreeSpace(m_outPath.c_str(), m_discCapacity)) { LogModule.report(logvisor::Error, _S("not enough free disk space for %s"), m_outPath.c_str()); - return false; + return EBuildResult::DiskFull; } + m_progressCB(getProgressFactor(), _S("Preallocating image"), -1); ++m_progressIdx; - m_progressCB(m_progressIdx, _S("Preallocating image"), -1); std::unique_ptr ws = m_fileIO->beginWriteStream(m_discCapacity - 1); if (!ws) - return false; + return EBuildResult::Failed; ws->write("", 1); /* Assemble image */ filledSz = pb.buildFromDirectory(dirIn, dolIn, apploaderIn, partHeadIn); if (filledSz == -1) - return false; + return EBuildResult::Failed; else if (filledSz >= uint64_t(m_discCapacity)) { LogModule.report(logvisor::Error, "data partition exceeds disc capacity"); - return false; + return EBuildResult::Failed; } + m_progressCB(getProgressFactor(), _S("Finishing Disc"), -1); ++m_progressIdx; - m_progressCB(m_progressIdx, _S("Finishing Disc"), -1); /* Populate disc header */ ws = m_fileIO->beginWriteStream(0); if (!ws) - return false; + return EBuildResult::Failed; Header header(pb.getGameID(), pb.getGameTitle().c_str(), true, 0, 0, 0); header.write(*ws); /* Populate partition info */ ws = m_fileIO->beginWriteStream(0x40000); if (!ws) - return false; + return EBuildResult::Failed; uint32_t vals[2] = {SBig(uint32_t(1)), SBig(uint32_t(0x40020 >> uint64_t(2)))}; ws->write(vals, 8); ws = m_fileIO->beginWriteStream(0x40020); if (!ws) - return false; + return EBuildResult::Failed; vals[0] = SBig(uint32_t(pb.m_baseOffset >> uint64_t(2))); ws->write(vals, 4); /* Populate region info */ ws = m_fileIO->beginWriteStream(0x4E000); if (!ws) - return false; + return EBuildResult::Failed; const char* gameID = pb.getGameID(); if (gameID[3] == 'P') vals[0] = SBig(uint32_t(2)); @@ -1114,14 +1114,14 @@ bool DiscBuilderWii::buildFromDirectory(const SystemChar* dirIn, const SystemCha /* Make disc unrated */ ws = m_fileIO->beginWriteStream(0x4E010); if (!ws) - return false; + return EBuildResult::Failed; for (int i=0 ; i<16 ; ++i) ws->write("\x80", 1); /* Fill image to end */ ws = m_fileIO->beginWriteStream(filledSz); if (!ws) - return false; + return EBuildResult::Failed; uint8_t fillBuf[512]; memset(fillBuf, 0xff, 512); for (size_t i=m_discCapacity-filledSz ; i>0 ;) @@ -1136,7 +1136,7 @@ bool DiscBuilderWii::buildFromDirectory(const SystemChar* dirIn, const SystemCha break; } - return true; + return EBuildResult::Success; } uint64_t DiscBuilderWii::CalculateTotalSizeRequired(const SystemChar* dirIn, const SystemChar* dolIn, @@ -1172,61 +1172,61 @@ DiscMergerWii::DiscMergerWii(const SystemChar* outPath, DiscWii& sourceDisc, : m_sourceDisc(sourceDisc), m_builder(sourceDisc.makeMergeBuilder(outPath, dualLayer, progressCB)) {} -bool DiscMergerWii::mergeFromDirectory(const SystemChar* dirIn) +EBuildResult DiscMergerWii::mergeFromDirectory(const SystemChar* dirIn) { PartitionBuilderWii& pb = static_cast(*m_builder.m_partitions[0]); uint64_t filledSz = pb.m_baseOffset; if (!m_builder.m_fileIO->beginWriteStream()) - return false; + return EBuildResult::Failed; if (!CheckFreeSpace(m_builder.m_outPath.c_str(), m_builder.m_discCapacity)) { LogModule.report(logvisor::Error, _S("not enough free disk space for %s"), m_builder.m_outPath.c_str()); - return false; + return EBuildResult::DiskFull; } + m_builder.m_progressCB(m_builder.getProgressFactor(), _S("Preallocating image"), -1); ++m_builder.m_progressIdx; - m_builder.m_progressCB(m_builder.m_progressIdx, _S("Preallocating image"), -1); std::unique_ptr ws = m_builder.m_fileIO->beginWriteStream(m_builder.m_discCapacity - 1); if (!ws) - return false; + return EBuildResult::Failed; ws->write("", 1); /* Assemble image */ filledSz = pb.mergeFromDirectory(static_cast(m_sourceDisc.getDataPartition()), dirIn); if (filledSz == -1) - return false; + return EBuildResult::Failed; else if (filledSz >= uint64_t(m_builder.m_discCapacity)) { LogModule.report(logvisor::Error, "data partition exceeds disc capacity"); - return false; + return EBuildResult::Failed; } + m_builder.m_progressCB(m_builder.getProgressFactor(), _S("Finishing Disc"), -1); ++m_builder.m_progressIdx; - m_builder.m_progressCB(m_builder.m_progressIdx, _S("Finishing Disc"), -1); /* Populate disc header */ ws = m_builder.m_fileIO->beginWriteStream(0); if (!ws) - return false; + return EBuildResult::Failed; m_sourceDisc.getHeader().write(*ws); /* Populate partition info */ ws = m_builder.m_fileIO->beginWriteStream(0x40000); if (!ws) - return false; + return EBuildResult::Failed; uint32_t vals[2] = {SBig(uint32_t(1)), SBig(uint32_t(0x40020 >> uint64_t(2)))}; ws->write(vals, 8); ws = m_builder.m_fileIO->beginWriteStream(0x40020); if (!ws) - return false; + return EBuildResult::Failed; vals[0] = SBig(uint32_t(pb.m_baseOffset >> uint64_t(2))); ws->write(vals, 4); /* Populate region info */ ws = m_builder.m_fileIO->beginWriteStream(0x4E000); if (!ws) - return false; + return EBuildResult::Failed; const char* gameID = pb.getGameID(); if (gameID[3] == 'P') vals[0] = SBig(uint32_t(2)); @@ -1239,14 +1239,14 @@ bool DiscMergerWii::mergeFromDirectory(const SystemChar* dirIn) /* Make disc unrated */ ws = m_builder.m_fileIO->beginWriteStream(0x4E010); if (!ws) - return false; + return EBuildResult::Failed; for (int i=0 ; i<16 ; ++i) ws->write("\x80", 1); /* Fill image to end */ ws = m_builder.m_fileIO->beginWriteStream(filledSz); if (!ws) - return false; + return EBuildResult::Failed; uint8_t fillBuf[512]; memset(fillBuf, 0xff, 512); for (size_t i=m_builder.m_discCapacity-filledSz ; i>0 ;) @@ -1261,7 +1261,7 @@ bool DiscMergerWii::mergeFromDirectory(const SystemChar* dirIn) break; } - return true; + return EBuildResult::Success; } uint64_t DiscMergerWii::CalculateTotalSizeRequired(DiscWii& sourceDisc, diff --git a/lib/FileIOFILE.cpp b/lib/FileIOFILE.cpp index 7e7813b..56b3f14 100644 --- a/lib/FileIOFILE.cpp +++ b/lib/FileIOFILE.cpp @@ -83,29 +83,6 @@ public: } return fwrite(buf, 1, length, fp); } - uint64_t copyFromDisc(IPartReadStream& discio, uint64_t length) - { - uint64_t read = 0; - uint8_t buf[0x7c00]; - while (length) - { - uint64_t thisSz = nod::min(uint64_t(0x7c00), length); - uint64_t readSz = discio.read(buf, thisSz); - if (thisSz != readSz) - { - LogModule.report(logvisor::Error, "unable to read enough from disc"); - return read; - } - if (write(buf, readSz) != readSz) - { - LogModule.report(logvisor::Error, "unable to write in file"); - return read; - } - length -= thisSz; - read += thisSz; - } - return read; - } }; std::unique_ptr beginWriteStream() const { diff --git a/lib/FileIOWin32.cpp b/lib/FileIOWin32.cpp index 57e182d..776af56 100644 --- a/lib/FileIOWin32.cpp +++ b/lib/FileIOWin32.cpp @@ -95,29 +95,6 @@ public: WriteFile(fp, buf, length, &ret, nullptr); return ret; } - uint64_t copyFromDisc(IPartReadStream& discio, uint64_t length) - { - uint64_t read = 0; - uint8_t buf[0x7c00]; - while (length) - { - uint64_t thisSz = nod::min(uint64_t(0x7c00), length); - uint64_t readSz = discio.read(buf, thisSz); - if (thisSz != readSz) - { - LogModule.report(logvisor::Error, "unable to read enough from disc"); - return read; - } - if (write(buf, readSz) != readSz) - { - LogModule.report(logvisor::Error, "unable to write in file"); - return read; - } - length -= thisSz; - read += thisSz; - } - return read; - } }; std::unique_ptr beginWriteStream() const {