mirror of https://github.com/AxioDL/nod.git
New code style refactor
This commit is contained in:
parent
3d380fdc3b
commit
be8409681f
438
driver/main.cpp
438
driver/main.cpp
|
@ -3,14 +3,14 @@
|
|||
#include "logvisor/logvisor.hpp"
|
||||
#include "nod/nod.hpp"
|
||||
|
||||
static void printHelp()
|
||||
{
|
||||
fprintf(stderr, "Usage:\n"
|
||||
" nodtool extract [-f] <image-in> [<dir-out>]\n"
|
||||
" nodtool makegcn <fsroot-in> [<image-out>]\n"
|
||||
" nodtool makewii <fsroot-in> [<image-out>]\n"
|
||||
" nodtool mergegcn <fsroot-in> <image-in> [<image-out>]\n"
|
||||
" nodtool mergewii <fsroot-in> <image-in> [<image-out>]\n");
|
||||
static void printHelp() {
|
||||
fprintf(stderr,
|
||||
"Usage:\n"
|
||||
" nodtool extract [-f] <image-in> [<dir-out>]\n"
|
||||
" nodtool makegcn <fsroot-in> [<image-out>]\n"
|
||||
" nodtool makewii <fsroot-in> [<image-out>]\n"
|
||||
" nodtool mergegcn <fsroot-in> <image-in> [<image-out>]\n"
|
||||
" nodtool mergewii <fsroot-in> <image-in> [<image-out>]\n");
|
||||
}
|
||||
|
||||
#if NOD_UCS2
|
||||
|
@ -25,241 +25,203 @@ int wmain(int argc, wchar_t* argv[])
|
|||
int main(int argc, char* argv[])
|
||||
#endif
|
||||
{
|
||||
if (argc < 3 ||
|
||||
(!strcasecmp(argv[1], _SYS_STR("makegcn")) && argc < 3) ||
|
||||
(!strcasecmp(argv[1], _SYS_STR("makewii")) && argc < 3) ||
|
||||
(!strcasecmp(argv[1], _SYS_STR("mergegcn")) && argc < 4) ||
|
||||
(!strcasecmp(argv[1], _SYS_STR("mergewii")) && argc < 4))
|
||||
{
|
||||
printHelp();
|
||||
return 1;
|
||||
}
|
||||
if (argc < 3 || (!strcasecmp(argv[1], _SYS_STR("makegcn")) && argc < 3) ||
|
||||
(!strcasecmp(argv[1], _SYS_STR("makewii")) && argc < 3) ||
|
||||
(!strcasecmp(argv[1], _SYS_STR("mergegcn")) && argc < 4) ||
|
||||
(!strcasecmp(argv[1], _SYS_STR("mergewii")) && argc < 4)) {
|
||||
printHelp();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Enable logging to console */
|
||||
logvisor::RegisterStandardExceptions();
|
||||
logvisor::RegisterConsoleLogger();
|
||||
/* Enable logging to console */
|
||||
logvisor::RegisterStandardExceptions();
|
||||
logvisor::RegisterConsoleLogger();
|
||||
|
||||
bool verbose = false;
|
||||
nod::ExtractionContext ctx = {true,
|
||||
[&](std::string_view str, float c) {
|
||||
if (verbose)
|
||||
fprintf(stderr, "Current node: %s, Extraction %g%% Complete\n", str.data(), c * 100.f);
|
||||
}};
|
||||
const nod::SystemChar* inDir = nullptr;
|
||||
const nod::SystemChar* outDir = _SYS_STR(".");
|
||||
bool verbose = false;
|
||||
nod::ExtractionContext ctx = {true, [&](std::string_view str, float c) {
|
||||
if (verbose)
|
||||
fprintf(stderr, "Current node: %s, Extraction %g%% Complete\n", str.data(),
|
||||
c * 100.f);
|
||||
}};
|
||||
const nod::SystemChar* inDir = nullptr;
|
||||
const nod::SystemChar* outDir = _SYS_STR(".");
|
||||
|
||||
for (int a=2 ; a<argc ; ++a)
|
||||
{
|
||||
if (argv[a][0] == '-' && argv[a][1] == 'f')
|
||||
ctx.force = true;
|
||||
else if (argv[a][0] == '-' && argv[a][1] == 'v')
|
||||
verbose = true;
|
||||
for (int a = 2; a < argc; ++a) {
|
||||
if (argv[a][0] == '-' && argv[a][1] == 'f')
|
||||
ctx.force = true;
|
||||
else if (argv[a][0] == '-' && argv[a][1] == 'v')
|
||||
verbose = true;
|
||||
|
||||
else if (!inDir)
|
||||
inDir = argv[a];
|
||||
else
|
||||
outDir = argv[a];
|
||||
}
|
||||
|
||||
auto progFunc = [&](float prog, nod::SystemStringView name, size_t bytes)
|
||||
{
|
||||
nod::Printf(_SYS_STR("\r "));
|
||||
if (bytes != -1)
|
||||
nod::Printf(_SYS_STR("\r%g%% %s %" PRISize " B"), prog * 100.f, name.data(), bytes);
|
||||
else
|
||||
nod::Printf(_SYS_STR("\r%g%% %s"), prog * 100.f, name.data());
|
||||
fflush(stdout);
|
||||
};
|
||||
|
||||
if (!strcasecmp(argv[1], _SYS_STR("extract")))
|
||||
{
|
||||
bool isWii;
|
||||
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(inDir, isWii);
|
||||
if (!disc)
|
||||
return 1;
|
||||
|
||||
nod::Mkdir(outDir, 0755);
|
||||
|
||||
nod::IPartition* dataPart = disc->getDataPartition();
|
||||
if (!dataPart)
|
||||
return 1;
|
||||
|
||||
if (!dataPart->extractToDirectory(outDir, ctx))
|
||||
return 1;
|
||||
}
|
||||
else if (!strcasecmp(argv[1], _SYS_STR("makegcn")))
|
||||
{
|
||||
/* Pre-validate path */
|
||||
nod::Sstat theStat;
|
||||
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode))
|
||||
{
|
||||
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as directory"), argv[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (nod::DiscBuilderGCN::CalculateTotalSizeRequired(argv[2]) == -1)
|
||||
return 1;
|
||||
|
||||
nod::EBuildResult ret;
|
||||
|
||||
if (argc < 4)
|
||||
{
|
||||
nod::SystemString outPath(argv[2]);
|
||||
outPath.append(_SYS_STR(".iso"));
|
||||
nod::DiscBuilderGCN b(outPath, progFunc);
|
||||
ret = b.buildFromDirectory(argv[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
nod::DiscBuilderGCN b(argv[3], progFunc);
|
||||
ret = b.buildFromDirectory(argv[2]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
if (ret != nod::EBuildResult::Success)
|
||||
return 1;
|
||||
}
|
||||
else if (!strcasecmp(argv[1], _SYS_STR("makewii")))
|
||||
{
|
||||
/* Pre-validate path */
|
||||
nod::Sstat theStat;
|
||||
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode))
|
||||
{
|
||||
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as directory"), argv[4]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool dual = false;
|
||||
if (nod::DiscBuilderWii::CalculateTotalSizeRequired(argv[2], dual) == -1)
|
||||
return 1;
|
||||
|
||||
nod::EBuildResult ret;
|
||||
|
||||
if (argc < 4)
|
||||
{
|
||||
nod::SystemString outPath(argv[2]);
|
||||
outPath.append(_SYS_STR(".iso"));
|
||||
nod::DiscBuilderWii b(outPath.c_str(), dual, progFunc);
|
||||
ret = b.buildFromDirectory(argv[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
nod::DiscBuilderWii b(argv[3], dual, progFunc);
|
||||
ret = b.buildFromDirectory(argv[2]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
if (ret != nod::EBuildResult::Success)
|
||||
return 1;
|
||||
}
|
||||
else if (!strcasecmp(argv[1], _SYS_STR("mergegcn")))
|
||||
{
|
||||
/* Pre-validate paths */
|
||||
nod::Sstat theStat;
|
||||
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode))
|
||||
{
|
||||
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as directory"), argv[2]);
|
||||
return 1;
|
||||
}
|
||||
if (nod::Stat(argv[3], &theStat) || !S_ISREG(theStat.st_mode))
|
||||
{
|
||||
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as file"), argv[3]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool isWii;
|
||||
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(argv[3], isWii);
|
||||
if (!disc)
|
||||
{
|
||||
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to open image %s"), argv[3]);
|
||||
return 1;
|
||||
}
|
||||
if (isWii)
|
||||
{
|
||||
nod::LogModule.report(logvisor::Error, _SYS_STR("Wii images should be merged with 'mergewii'"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (nod::DiscMergerGCN::CalculateTotalSizeRequired(static_cast<nod::DiscGCN&>(*disc), argv[2]) == -1)
|
||||
return 1;
|
||||
|
||||
nod::EBuildResult ret;
|
||||
|
||||
if (argc < 5)
|
||||
{
|
||||
nod::SystemString outPath(argv[2]);
|
||||
outPath.append(_SYS_STR(".iso"));
|
||||
nod::DiscMergerGCN b(outPath.c_str(), static_cast<nod::DiscGCN&>(*disc), progFunc);
|
||||
ret = b.mergeFromDirectory(argv[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
nod::DiscMergerGCN b(argv[4], static_cast<nod::DiscGCN&>(*disc), progFunc);
|
||||
ret = b.mergeFromDirectory(argv[2]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
if (ret != nod::EBuildResult::Success)
|
||||
return 1;
|
||||
}
|
||||
else if (!strcasecmp(argv[1], _SYS_STR("mergewii")))
|
||||
{
|
||||
/* Pre-validate paths */
|
||||
nod::Sstat theStat;
|
||||
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode))
|
||||
{
|
||||
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as directory"), argv[2]);
|
||||
return 1;
|
||||
}
|
||||
if (nod::Stat(argv[3], &theStat) || !S_ISREG(theStat.st_mode))
|
||||
{
|
||||
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as file"), argv[3]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool isWii;
|
||||
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(argv[3], isWii);
|
||||
if (!disc)
|
||||
{
|
||||
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to open image %s"), argv[3]);
|
||||
return 1;
|
||||
}
|
||||
if (!isWii)
|
||||
{
|
||||
nod::LogModule.report(logvisor::Error, _SYS_STR("GameCube images should be merged with 'mergegcn'"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool dual = false;
|
||||
if (nod::DiscMergerWii::CalculateTotalSizeRequired(static_cast<nod::DiscWii&>(*disc), argv[2], dual) == -1)
|
||||
return 1;
|
||||
|
||||
nod::EBuildResult ret;
|
||||
|
||||
if (argc < 5)
|
||||
{
|
||||
nod::SystemString outPath(argv[2]);
|
||||
outPath.append(_SYS_STR(".iso"));
|
||||
nod::DiscMergerWii b(outPath.c_str(), static_cast<nod::DiscWii&>(*disc), dual, progFunc);
|
||||
ret = b.mergeFromDirectory(argv[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
nod::DiscMergerWii b(argv[4], static_cast<nod::DiscWii&>(*disc), dual, progFunc);
|
||||
ret = b.mergeFromDirectory(argv[2]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
if (ret != nod::EBuildResult::Success)
|
||||
return 1;
|
||||
}
|
||||
else if (!inDir)
|
||||
inDir = argv[a];
|
||||
else
|
||||
{
|
||||
printHelp();
|
||||
return 1;
|
||||
outDir = argv[a];
|
||||
}
|
||||
|
||||
auto progFunc = [&](float prog, nod::SystemStringView name, size_t bytes) {
|
||||
nod::Printf(_SYS_STR("\r "));
|
||||
if (bytes != -1)
|
||||
nod::Printf(_SYS_STR("\r%g%% %s %" PRISize " B"), prog * 100.f, name.data(), bytes);
|
||||
else
|
||||
nod::Printf(_SYS_STR("\r%g%% %s"), prog * 100.f, name.data());
|
||||
fflush(stdout);
|
||||
};
|
||||
|
||||
if (!strcasecmp(argv[1], _SYS_STR("extract"))) {
|
||||
bool isWii;
|
||||
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(inDir, isWii);
|
||||
if (!disc)
|
||||
return 1;
|
||||
|
||||
nod::Mkdir(outDir, 0755);
|
||||
|
||||
nod::IPartition* dataPart = disc->getDataPartition();
|
||||
if (!dataPart)
|
||||
return 1;
|
||||
|
||||
if (!dataPart->extractToDirectory(outDir, ctx))
|
||||
return 1;
|
||||
} else if (!strcasecmp(argv[1], _SYS_STR("makegcn"))) {
|
||||
/* Pre-validate path */
|
||||
nod::Sstat theStat;
|
||||
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode)) {
|
||||
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as directory"), argv[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
nod::LogModule.report(logvisor::Info, _SYS_STR("Success!"));
|
||||
return 0;
|
||||
}
|
||||
if (nod::DiscBuilderGCN::CalculateTotalSizeRequired(argv[2]) == -1)
|
||||
return 1;
|
||||
|
||||
nod::EBuildResult ret;
|
||||
|
||||
if (argc < 4) {
|
||||
nod::SystemString outPath(argv[2]);
|
||||
outPath.append(_SYS_STR(".iso"));
|
||||
nod::DiscBuilderGCN b(outPath, progFunc);
|
||||
ret = b.buildFromDirectory(argv[2]);
|
||||
} else {
|
||||
nod::DiscBuilderGCN b(argv[3], progFunc);
|
||||
ret = b.buildFromDirectory(argv[2]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
if (ret != nod::EBuildResult::Success)
|
||||
return 1;
|
||||
} else if (!strcasecmp(argv[1], _SYS_STR("makewii"))) {
|
||||
/* Pre-validate path */
|
||||
nod::Sstat theStat;
|
||||
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode)) {
|
||||
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as directory"), argv[4]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool dual = false;
|
||||
if (nod::DiscBuilderWii::CalculateTotalSizeRequired(argv[2], dual) == -1)
|
||||
return 1;
|
||||
|
||||
nod::EBuildResult ret;
|
||||
|
||||
if (argc < 4) {
|
||||
nod::SystemString outPath(argv[2]);
|
||||
outPath.append(_SYS_STR(".iso"));
|
||||
nod::DiscBuilderWii b(outPath.c_str(), dual, progFunc);
|
||||
ret = b.buildFromDirectory(argv[2]);
|
||||
} else {
|
||||
nod::DiscBuilderWii b(argv[3], dual, progFunc);
|
||||
ret = b.buildFromDirectory(argv[2]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
if (ret != nod::EBuildResult::Success)
|
||||
return 1;
|
||||
} else if (!strcasecmp(argv[1], _SYS_STR("mergegcn"))) {
|
||||
/* Pre-validate paths */
|
||||
nod::Sstat theStat;
|
||||
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode)) {
|
||||
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as directory"), argv[2]);
|
||||
return 1;
|
||||
}
|
||||
if (nod::Stat(argv[3], &theStat) || !S_ISREG(theStat.st_mode)) {
|
||||
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as file"), argv[3]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool isWii;
|
||||
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(argv[3], isWii);
|
||||
if (!disc) {
|
||||
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to open image %s"), argv[3]);
|
||||
return 1;
|
||||
}
|
||||
if (isWii) {
|
||||
nod::LogModule.report(logvisor::Error, _SYS_STR("Wii images should be merged with 'mergewii'"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (nod::DiscMergerGCN::CalculateTotalSizeRequired(static_cast<nod::DiscGCN&>(*disc), argv[2]) == -1)
|
||||
return 1;
|
||||
|
||||
nod::EBuildResult ret;
|
||||
|
||||
if (argc < 5) {
|
||||
nod::SystemString outPath(argv[2]);
|
||||
outPath.append(_SYS_STR(".iso"));
|
||||
nod::DiscMergerGCN b(outPath.c_str(), static_cast<nod::DiscGCN&>(*disc), progFunc);
|
||||
ret = b.mergeFromDirectory(argv[2]);
|
||||
} else {
|
||||
nod::DiscMergerGCN b(argv[4], static_cast<nod::DiscGCN&>(*disc), progFunc);
|
||||
ret = b.mergeFromDirectory(argv[2]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
if (ret != nod::EBuildResult::Success)
|
||||
return 1;
|
||||
} else if (!strcasecmp(argv[1], _SYS_STR("mergewii"))) {
|
||||
/* Pre-validate paths */
|
||||
nod::Sstat theStat;
|
||||
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode)) {
|
||||
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as directory"), argv[2]);
|
||||
return 1;
|
||||
}
|
||||
if (nod::Stat(argv[3], &theStat) || !S_ISREG(theStat.st_mode)) {
|
||||
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as file"), argv[3]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool isWii;
|
||||
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(argv[3], isWii);
|
||||
if (!disc) {
|
||||
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to open image %s"), argv[3]);
|
||||
return 1;
|
||||
}
|
||||
if (!isWii) {
|
||||
nod::LogModule.report(logvisor::Error, _SYS_STR("GameCube images should be merged with 'mergegcn'"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool dual = false;
|
||||
if (nod::DiscMergerWii::CalculateTotalSizeRequired(static_cast<nod::DiscWii&>(*disc), argv[2], dual) == -1)
|
||||
return 1;
|
||||
|
||||
nod::EBuildResult ret;
|
||||
|
||||
if (argc < 5) {
|
||||
nod::SystemString outPath(argv[2]);
|
||||
outPath.append(_SYS_STR(".iso"));
|
||||
nod::DiscMergerWii b(outPath.c_str(), static_cast<nod::DiscWii&>(*disc), dual, progFunc);
|
||||
ret = b.mergeFromDirectory(argv[2]);
|
||||
} else {
|
||||
nod::DiscMergerWii b(argv[4], static_cast<nod::DiscWii&>(*disc), dual, progFunc);
|
||||
ret = b.mergeFromDirectory(argv[2]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
if (ret != nod::EBuildResult::Success)
|
||||
return 1;
|
||||
} else {
|
||||
printHelp();
|
||||
return 1;
|
||||
}
|
||||
|
||||
nod::LogModule.report(logvisor::Info, _SYS_STR("Success!"));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -2,65 +2,52 @@
|
|||
|
||||
#include "Util.hpp"
|
||||
|
||||
namespace nod
|
||||
{
|
||||
namespace nod {
|
||||
|
||||
struct CaseInsensitiveCompare
|
||||
{
|
||||
bool operator()(std::string_view lhs, std::string_view rhs) const
|
||||
{
|
||||
struct CaseInsensitiveCompare {
|
||||
bool operator()(std::string_view lhs, std::string_view rhs) const {
|
||||
#if _WIN32
|
||||
if (_stricmp(lhs.data(), rhs.data()) < 0)
|
||||
if (_stricmp(lhs.data(), rhs.data()) < 0)
|
||||
#else
|
||||
if (strcasecmp(lhs.data(), rhs.data()) < 0)
|
||||
if (strcasecmp(lhs.data(), rhs.data()) < 0)
|
||||
#endif
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
bool operator()(std::wstring_view lhs, std::wstring_view rhs) const
|
||||
{
|
||||
if (_wcsicmp(lhs.data(), rhs.data()) < 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool operator()(std::wstring_view lhs, std::wstring_view rhs) const {
|
||||
if (_wcsicmp(lhs.data(), rhs.data()) < 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
class DirectoryEnumerator
|
||||
{
|
||||
class DirectoryEnumerator {
|
||||
public:
|
||||
enum class Mode
|
||||
{
|
||||
Native,
|
||||
DirsSorted,
|
||||
FilesSorted,
|
||||
DirsThenFilesSorted
|
||||
};
|
||||
struct Entry
|
||||
{
|
||||
SystemString m_path;
|
||||
SystemString m_name;
|
||||
size_t m_fileSz;
|
||||
bool m_isDir;
|
||||
enum class Mode { Native, DirsSorted, FilesSorted, DirsThenFilesSorted };
|
||||
struct Entry {
|
||||
SystemString m_path;
|
||||
SystemString m_name;
|
||||
size_t m_fileSz;
|
||||
bool m_isDir;
|
||||
|
||||
Entry(const SystemString& path, const SystemChar* name, size_t sz, bool isDir)
|
||||
: m_path(path), m_name(name), m_fileSz(sz), m_isDir(isDir) {}
|
||||
};
|
||||
Entry(const SystemString& path, const SystemChar* name, size_t sz, bool isDir)
|
||||
: m_path(path), m_name(name), m_fileSz(sz), m_isDir(isDir) {}
|
||||
};
|
||||
|
||||
private:
|
||||
std::vector<Entry> m_entries;
|
||||
std::vector<Entry> m_entries;
|
||||
|
||||
public:
|
||||
DirectoryEnumerator(SystemStringView path, Mode mode=Mode::DirsThenFilesSorted,
|
||||
bool sizeSort=false, bool reverse=false, bool noHidden=false);
|
||||
DirectoryEnumerator(SystemStringView path, Mode mode = Mode::DirsThenFilesSorted, bool sizeSort = false,
|
||||
bool reverse = false, bool noHidden = false);
|
||||
|
||||
operator bool() const {return m_entries.size() != 0;}
|
||||
size_t size() const {return m_entries.size();}
|
||||
std::vector<Entry>::const_iterator begin() const {return m_entries.cbegin();}
|
||||
std::vector<Entry>::const_iterator end() const {return m_entries.cend();}
|
||||
operator bool() const { return m_entries.size() != 0; }
|
||||
size_t size() const { return m_entries.size(); }
|
||||
std::vector<Entry>::const_iterator begin() const { return m_entries.cbegin(); }
|
||||
std::vector<Entry>::const_iterator end() const { return m_entries.cend(); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
} // namespace nod
|
||||
|
|
|
@ -11,495 +11,453 @@
|
|||
#include "IDiscIO.hpp"
|
||||
#include "IFileIO.hpp"
|
||||
|
||||
namespace nod
|
||||
{
|
||||
namespace nod {
|
||||
|
||||
using FProgress = std::function<void(float totalProg, SystemStringView fileName, size_t fileBytesXfered)>;
|
||||
|
||||
enum class EBuildResult
|
||||
{
|
||||
Success,
|
||||
Failed,
|
||||
DiskFull
|
||||
};
|
||||
enum class EBuildResult { Success, Failed, DiskFull };
|
||||
|
||||
enum class PartitionKind : uint32_t
|
||||
{
|
||||
Data,
|
||||
Update,
|
||||
Channel
|
||||
};
|
||||
enum class PartitionKind : uint32_t { Data, Update, Channel };
|
||||
const SystemChar* getKindString(PartitionKind kind);
|
||||
|
||||
class FSTNode
|
||||
{
|
||||
uint32_t typeAndNameOffset;
|
||||
uint32_t offset;
|
||||
uint32_t length;
|
||||
class FSTNode {
|
||||
uint32_t typeAndNameOffset;
|
||||
uint32_t offset;
|
||||
uint32_t length;
|
||||
|
||||
public:
|
||||
FSTNode(bool isDir, uint32_t nameOff, uint32_t off, uint32_t len)
|
||||
{
|
||||
typeAndNameOffset = nameOff & 0xffffff;
|
||||
typeAndNameOffset |= isDir << 24;
|
||||
typeAndNameOffset = SBig(typeAndNameOffset);
|
||||
offset = SBig(off);
|
||||
length = SBig(len);
|
||||
}
|
||||
inline bool isDir() const {return ((SBig(typeAndNameOffset) >> 24) != 0);}
|
||||
inline uint32_t getNameOffset() const {return SBig(typeAndNameOffset) & 0xffffff;}
|
||||
inline uint32_t getOffset() const {return SBig(offset);}
|
||||
inline uint32_t getLength() const {return SBig(length);}
|
||||
void incrementLength()
|
||||
{
|
||||
uint32_t orig = SBig(length);
|
||||
++orig;
|
||||
length = SBig(orig);
|
||||
}
|
||||
FSTNode(bool isDir, uint32_t nameOff, uint32_t off, uint32_t len) {
|
||||
typeAndNameOffset = nameOff & 0xffffff;
|
||||
typeAndNameOffset |= isDir << 24;
|
||||
typeAndNameOffset = SBig(typeAndNameOffset);
|
||||
offset = SBig(off);
|
||||
length = SBig(len);
|
||||
}
|
||||
inline bool isDir() const { return ((SBig(typeAndNameOffset) >> 24) != 0); }
|
||||
inline uint32_t getNameOffset() const { return SBig(typeAndNameOffset) & 0xffffff; }
|
||||
inline uint32_t getOffset() const { return SBig(offset); }
|
||||
inline uint32_t getLength() const { return SBig(length); }
|
||||
void incrementLength() {
|
||||
uint32_t orig = SBig(length);
|
||||
++orig;
|
||||
length = SBig(orig);
|
||||
}
|
||||
};
|
||||
|
||||
struct Header
|
||||
{
|
||||
char m_gameID[6];
|
||||
char m_discNum;
|
||||
char m_discVersion;
|
||||
char m_audioStreaming;
|
||||
char m_streamBufSz;
|
||||
char m_unk1[14];
|
||||
uint32_t m_wiiMagic;
|
||||
uint32_t m_gcnMagic;
|
||||
char m_gameTitle[64];
|
||||
char m_disableHashVerification;
|
||||
char m_disableDiscEnc;
|
||||
char m_unk2[0x39e];
|
||||
uint32_t m_debugMonOff;
|
||||
uint32_t m_debugLoadAddr;
|
||||
char m_unk3[0x18];
|
||||
uint32_t m_dolOff;
|
||||
uint32_t m_fstOff;
|
||||
uint32_t m_fstSz;
|
||||
uint32_t m_fstMaxSz;
|
||||
uint32_t m_fstMemoryAddress;
|
||||
uint32_t m_userPosition;
|
||||
uint32_t m_userSz;
|
||||
uint8_t padding1[4];
|
||||
struct Header {
|
||||
char m_gameID[6];
|
||||
char m_discNum;
|
||||
char m_discVersion;
|
||||
char m_audioStreaming;
|
||||
char m_streamBufSz;
|
||||
char m_unk1[14];
|
||||
uint32_t m_wiiMagic;
|
||||
uint32_t m_gcnMagic;
|
||||
char m_gameTitle[64];
|
||||
char m_disableHashVerification;
|
||||
char m_disableDiscEnc;
|
||||
char m_unk2[0x39e];
|
||||
uint32_t m_debugMonOff;
|
||||
uint32_t m_debugLoadAddr;
|
||||
char m_unk3[0x18];
|
||||
uint32_t m_dolOff;
|
||||
uint32_t m_fstOff;
|
||||
uint32_t m_fstSz;
|
||||
uint32_t m_fstMaxSz;
|
||||
uint32_t m_fstMemoryAddress;
|
||||
uint32_t m_userPosition;
|
||||
uint32_t m_userSz;
|
||||
uint8_t padding1[4];
|
||||
|
||||
Header() = default;
|
||||
Header(IDiscIO& dio, bool& err)
|
||||
{
|
||||
auto rs = dio.beginReadStream();
|
||||
if (!rs)
|
||||
{
|
||||
err = true;
|
||||
return;
|
||||
}
|
||||
read(*rs);
|
||||
Header() = default;
|
||||
Header(IDiscIO& dio, bool& err) {
|
||||
auto rs = dio.beginReadStream();
|
||||
if (!rs) {
|
||||
err = true;
|
||||
return;
|
||||
}
|
||||
read(*rs);
|
||||
}
|
||||
|
||||
void read(IReadStream& s)
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
s.read(this, sizeof(*this));
|
||||
m_wiiMagic = SBig(m_wiiMagic);
|
||||
m_gcnMagic = SBig(m_gcnMagic);
|
||||
m_debugMonOff = SBig(m_debugMonOff);
|
||||
m_debugLoadAddr = SBig(m_debugLoadAddr);
|
||||
m_dolOff = SBig(m_dolOff);
|
||||
m_fstOff = SBig(m_fstOff);
|
||||
m_fstSz = SBig(m_fstSz);
|
||||
m_fstMaxSz = SBig(m_fstMaxSz);
|
||||
m_fstMemoryAddress = SBig(m_fstMemoryAddress);
|
||||
m_userPosition = SBig(m_userPosition);
|
||||
m_userSz = SBig(m_userSz);
|
||||
}
|
||||
void read(IReadStream& s) {
|
||||
memset(this, 0, sizeof(*this));
|
||||
s.read(this, sizeof(*this));
|
||||
m_wiiMagic = SBig(m_wiiMagic);
|
||||
m_gcnMagic = SBig(m_gcnMagic);
|
||||
m_debugMonOff = SBig(m_debugMonOff);
|
||||
m_debugLoadAddr = SBig(m_debugLoadAddr);
|
||||
m_dolOff = SBig(m_dolOff);
|
||||
m_fstOff = SBig(m_fstOff);
|
||||
m_fstSz = SBig(m_fstSz);
|
||||
m_fstMaxSz = SBig(m_fstMaxSz);
|
||||
m_fstMemoryAddress = SBig(m_fstMemoryAddress);
|
||||
m_userPosition = SBig(m_userPosition);
|
||||
m_userSz = SBig(m_userSz);
|
||||
}
|
||||
|
||||
void write(IWriteStream& ws) const
|
||||
{
|
||||
Header hs(*this);
|
||||
hs.m_wiiMagic = SBig(hs.m_wiiMagic);
|
||||
hs.m_gcnMagic = SBig(hs.m_gcnMagic);
|
||||
hs.m_debugMonOff = SBig(hs.m_debugMonOff);
|
||||
hs.m_debugLoadAddr = SBig(hs.m_debugLoadAddr);
|
||||
hs.m_dolOff = SBig(hs.m_dolOff);
|
||||
hs.m_fstOff = SBig(hs.m_fstOff);
|
||||
hs.m_fstSz = SBig(hs.m_fstSz);
|
||||
hs.m_fstMaxSz = SBig(hs.m_fstMaxSz);
|
||||
hs.m_fstMemoryAddress = SBig(hs.m_fstMemoryAddress);
|
||||
hs.m_userPosition = SBig(hs.m_userPosition);
|
||||
hs.m_userSz = SBig(hs.m_userSz);
|
||||
ws.write(&hs, sizeof(hs));
|
||||
}
|
||||
void write(IWriteStream& ws) const {
|
||||
Header hs(*this);
|
||||
hs.m_wiiMagic = SBig(hs.m_wiiMagic);
|
||||
hs.m_gcnMagic = SBig(hs.m_gcnMagic);
|
||||
hs.m_debugMonOff = SBig(hs.m_debugMonOff);
|
||||
hs.m_debugLoadAddr = SBig(hs.m_debugLoadAddr);
|
||||
hs.m_dolOff = SBig(hs.m_dolOff);
|
||||
hs.m_fstOff = SBig(hs.m_fstOff);
|
||||
hs.m_fstSz = SBig(hs.m_fstSz);
|
||||
hs.m_fstMaxSz = SBig(hs.m_fstMaxSz);
|
||||
hs.m_fstMemoryAddress = SBig(hs.m_fstMemoryAddress);
|
||||
hs.m_userPosition = SBig(hs.m_userPosition);
|
||||
hs.m_userSz = SBig(hs.m_userSz);
|
||||
ws.write(&hs, sizeof(hs));
|
||||
}
|
||||
};
|
||||
|
||||
/* Currently only kept for dolphin compatibility */
|
||||
struct BI2Header
|
||||
{
|
||||
int32_t m_debugMonitorSize;
|
||||
int32_t m_simMemSize;
|
||||
uint32_t m_argOffset;
|
||||
uint32_t m_debugFlag;
|
||||
uint32_t m_trkAddress;
|
||||
uint32_t m_trkSz;
|
||||
uint32_t m_countryCode;
|
||||
uint32_t m_unk1;
|
||||
uint32_t m_unk2;
|
||||
uint32_t m_unk3;
|
||||
uint32_t m_dolLimit;
|
||||
uint32_t m_unk4;
|
||||
uint8_t padding2[0x1FD0];
|
||||
struct BI2Header {
|
||||
int32_t m_debugMonitorSize;
|
||||
int32_t m_simMemSize;
|
||||
uint32_t m_argOffset;
|
||||
uint32_t m_debugFlag;
|
||||
uint32_t m_trkAddress;
|
||||
uint32_t m_trkSz;
|
||||
uint32_t m_countryCode;
|
||||
uint32_t m_unk1;
|
||||
uint32_t m_unk2;
|
||||
uint32_t m_unk3;
|
||||
uint32_t m_dolLimit;
|
||||
uint32_t m_unk4;
|
||||
uint8_t padding2[0x1FD0];
|
||||
|
||||
void read(IReadStream& rs)
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
rs.read(this, sizeof(*this));
|
||||
m_debugMonitorSize = SBig(m_debugMonitorSize);
|
||||
m_simMemSize = SBig(m_simMemSize);
|
||||
m_argOffset = SBig(m_argOffset);
|
||||
m_debugFlag = SBig(m_debugFlag);
|
||||
m_trkAddress = SBig(m_trkAddress);
|
||||
m_trkSz = SBig(m_trkSz);
|
||||
m_countryCode = SBig(m_countryCode);
|
||||
m_unk1 = SBig(m_unk1);
|
||||
m_unk2 = SBig(m_unk2);
|
||||
m_unk3 = SBig(m_unk3);
|
||||
m_dolLimit = SBig(m_dolLimit);
|
||||
m_unk4 = SBig(m_unk4);
|
||||
}
|
||||
void read(IReadStream& rs) {
|
||||
memset(this, 0, sizeof(*this));
|
||||
rs.read(this, sizeof(*this));
|
||||
m_debugMonitorSize = SBig(m_debugMonitorSize);
|
||||
m_simMemSize = SBig(m_simMemSize);
|
||||
m_argOffset = SBig(m_argOffset);
|
||||
m_debugFlag = SBig(m_debugFlag);
|
||||
m_trkAddress = SBig(m_trkAddress);
|
||||
m_trkSz = SBig(m_trkSz);
|
||||
m_countryCode = SBig(m_countryCode);
|
||||
m_unk1 = SBig(m_unk1);
|
||||
m_unk2 = SBig(m_unk2);
|
||||
m_unk3 = SBig(m_unk3);
|
||||
m_dolLimit = SBig(m_dolLimit);
|
||||
m_unk4 = SBig(m_unk4);
|
||||
}
|
||||
|
||||
void write(IWriteStream& ws) const
|
||||
{
|
||||
BI2Header h = *this;
|
||||
h.m_debugMonitorSize = SBig(h.m_debugMonitorSize);
|
||||
h.m_simMemSize = SBig(h.m_simMemSize);
|
||||
h.m_argOffset = SBig(h.m_argOffset);
|
||||
h.m_debugFlag = SBig(h.m_debugFlag);
|
||||
h.m_trkAddress = SBig(h.m_trkAddress);
|
||||
h.m_trkSz = SBig(h.m_trkSz);
|
||||
h.m_countryCode = SBig(h.m_countryCode);
|
||||
h.m_unk1 = SBig(h.m_unk1);
|
||||
h.m_unk2 = SBig(h.m_unk2);
|
||||
h.m_unk3 = SBig(h.m_unk3);
|
||||
h.m_dolLimit = SBig(h.m_dolLimit);
|
||||
h.m_unk4 = SBig(h.m_unk4);
|
||||
ws.write(&h, sizeof(h));
|
||||
}
|
||||
void write(IWriteStream& ws) const {
|
||||
BI2Header h = *this;
|
||||
h.m_debugMonitorSize = SBig(h.m_debugMonitorSize);
|
||||
h.m_simMemSize = SBig(h.m_simMemSize);
|
||||
h.m_argOffset = SBig(h.m_argOffset);
|
||||
h.m_debugFlag = SBig(h.m_debugFlag);
|
||||
h.m_trkAddress = SBig(h.m_trkAddress);
|
||||
h.m_trkSz = SBig(h.m_trkSz);
|
||||
h.m_countryCode = SBig(h.m_countryCode);
|
||||
h.m_unk1 = SBig(h.m_unk1);
|
||||
h.m_unk2 = SBig(h.m_unk2);
|
||||
h.m_unk3 = SBig(h.m_unk3);
|
||||
h.m_dolLimit = SBig(h.m_dolLimit);
|
||||
h.m_unk4 = SBig(h.m_unk4);
|
||||
ws.write(&h, sizeof(h));
|
||||
}
|
||||
};
|
||||
|
||||
struct ExtractionContext;
|
||||
class IPartition;
|
||||
class DiscBase;
|
||||
|
||||
class Node
|
||||
{
|
||||
class Node {
|
||||
public:
|
||||
enum class Kind
|
||||
{
|
||||
File,
|
||||
Directory
|
||||
};
|
||||
enum class Kind { File, Directory };
|
||||
|
||||
private:
|
||||
friend class IPartition;
|
||||
const IPartition& m_parent;
|
||||
Kind m_kind;
|
||||
friend class IPartition;
|
||||
const IPartition& m_parent;
|
||||
Kind m_kind;
|
||||
|
||||
uint64_t m_discOffset;
|
||||
uint64_t m_discLength;
|
||||
std::string m_name;
|
||||
uint64_t m_discOffset;
|
||||
uint64_t m_discLength;
|
||||
std::string m_name;
|
||||
|
||||
std::vector<Node>::iterator m_childrenBegin;
|
||||
std::vector<Node>::iterator m_childrenEnd;
|
||||
std::vector<Node>::iterator m_childrenBegin;
|
||||
std::vector<Node>::iterator m_childrenEnd;
|
||||
|
||||
public:
|
||||
Node(const IPartition& parent, const FSTNode& node, std::string_view name);
|
||||
inline Kind getKind() const {return m_kind;}
|
||||
inline std::string_view getName() const {return m_name;}
|
||||
inline uint64_t size() const {return m_discLength;}
|
||||
std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset=0) const;
|
||||
std::unique_ptr<uint8_t[]> getBuf() const;
|
||||
inline std::vector<Node>::iterator rawBegin() const {return m_childrenBegin;}
|
||||
inline std::vector<Node>::iterator rawEnd() const {return m_childrenEnd;}
|
||||
Node(const IPartition& parent, const FSTNode& node, std::string_view name);
|
||||
inline Kind getKind() const { return m_kind; }
|
||||
inline std::string_view getName() const { return m_name; }
|
||||
inline uint64_t size() const { return m_discLength; }
|
||||
std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset = 0) const;
|
||||
std::unique_ptr<uint8_t[]> getBuf() const;
|
||||
inline std::vector<Node>::iterator rawBegin() const { return m_childrenBegin; }
|
||||
inline std::vector<Node>::iterator rawEnd() const { return m_childrenEnd; }
|
||||
|
||||
class DirectoryIterator
|
||||
{
|
||||
friend class Node;
|
||||
std::vector<Node>::iterator m_it;
|
||||
DirectoryIterator(const std::vector<Node>::iterator& it) : m_it(it) {}
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = Node;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = Node*;
|
||||
using reference = Node&;
|
||||
class DirectoryIterator {
|
||||
friend class Node;
|
||||
std::vector<Node>::iterator m_it;
|
||||
DirectoryIterator(const std::vector<Node>::iterator& it) : m_it(it) {}
|
||||
|
||||
inline bool operator!=(const DirectoryIterator& other) {return m_it != other.m_it;}
|
||||
inline bool operator==(const DirectoryIterator& other) {return m_it == other.m_it;}
|
||||
inline DirectoryIterator& operator++()
|
||||
{
|
||||
if (m_it->m_kind == Kind::Directory)
|
||||
m_it = m_it->rawEnd();
|
||||
else
|
||||
++m_it;
|
||||
return *this;
|
||||
}
|
||||
inline Node& operator*() {return *m_it;}
|
||||
inline Node* operator->() {return &*m_it;}
|
||||
};
|
||||
inline DirectoryIterator begin() const {return DirectoryIterator(m_childrenBegin);}
|
||||
inline DirectoryIterator end() const {return DirectoryIterator(m_childrenEnd);}
|
||||
inline DirectoryIterator find(std::string_view name) const
|
||||
{
|
||||
if (m_kind == Kind::Directory)
|
||||
{
|
||||
DirectoryIterator it=begin();
|
||||
for (; it != end() ; ++it)
|
||||
{
|
||||
if (!it->getName().compare(name))
|
||||
return it;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
return end();
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = Node;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = Node*;
|
||||
using reference = Node&;
|
||||
|
||||
inline bool operator!=(const DirectoryIterator& other) { return m_it != other.m_it; }
|
||||
inline bool operator==(const DirectoryIterator& other) { return m_it == other.m_it; }
|
||||
inline DirectoryIterator& operator++() {
|
||||
if (m_it->m_kind == Kind::Directory)
|
||||
m_it = m_it->rawEnd();
|
||||
else
|
||||
++m_it;
|
||||
return *this;
|
||||
}
|
||||
inline Node& operator*() { return *m_it; }
|
||||
inline Node* operator->() { return &*m_it; }
|
||||
};
|
||||
inline DirectoryIterator begin() const { return DirectoryIterator(m_childrenBegin); }
|
||||
inline DirectoryIterator end() const { return DirectoryIterator(m_childrenEnd); }
|
||||
inline DirectoryIterator find(std::string_view name) const {
|
||||
if (m_kind == Kind::Directory) {
|
||||
DirectoryIterator it = begin();
|
||||
for (; it != end(); ++it) {
|
||||
if (!it->getName().compare(name))
|
||||
return it;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
return end();
|
||||
}
|
||||
|
||||
bool extractToDirectory(SystemStringView basePath, const ExtractionContext& ctx) const;
|
||||
bool extractToDirectory(SystemStringView basePath, const ExtractionContext& ctx) const;
|
||||
};
|
||||
|
||||
class IPartition
|
||||
{
|
||||
class IPartition {
|
||||
public:
|
||||
virtual ~IPartition() = default;
|
||||
struct DOLHeader
|
||||
{
|
||||
uint32_t textOff[7];
|
||||
uint32_t dataOff[11];
|
||||
uint32_t textStarts[7];
|
||||
uint32_t dataStarts[11];
|
||||
uint32_t textSizes[7];
|
||||
uint32_t dataSizes[11];
|
||||
uint32_t bssStart;
|
||||
uint32_t bssSize;
|
||||
uint32_t entryPoint;
|
||||
};
|
||||
virtual ~IPartition() = default;
|
||||
struct DOLHeader {
|
||||
uint32_t textOff[7];
|
||||
uint32_t dataOff[11];
|
||||
uint32_t textStarts[7];
|
||||
uint32_t dataStarts[11];
|
||||
uint32_t textSizes[7];
|
||||
uint32_t dataSizes[11];
|
||||
uint32_t bssStart;
|
||||
uint32_t bssSize;
|
||||
uint32_t entryPoint;
|
||||
};
|
||||
|
||||
protected:
|
||||
Header m_header;
|
||||
BI2Header m_bi2Header;
|
||||
uint64_t m_dolOff;
|
||||
uint64_t m_fstOff;
|
||||
uint64_t m_fstSz;
|
||||
uint64_t m_apploaderSz;
|
||||
std::vector<Node> m_nodes;
|
||||
void parseFST(IPartReadStream& s);
|
||||
Header m_header;
|
||||
BI2Header m_bi2Header;
|
||||
uint64_t m_dolOff;
|
||||
uint64_t m_fstOff;
|
||||
uint64_t m_fstSz;
|
||||
uint64_t m_apploaderSz;
|
||||
std::vector<Node> m_nodes;
|
||||
void parseFST(IPartReadStream& s);
|
||||
|
||||
std::vector<FSTNode> m_buildNodes;
|
||||
std::vector<std::string> m_buildNames;
|
||||
size_t m_buildNameOff = 0;
|
||||
|
||||
uint64_t m_dolSz;
|
||||
void parseDOL(IPartReadStream& s);
|
||||
|
||||
const DiscBase& m_parent;
|
||||
PartitionKind m_kind;
|
||||
uint64_t m_offset;
|
||||
bool m_isWii;
|
||||
|
||||
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, PartitionKind kind, bool isWii, uint64_t offset)
|
||||
: m_parent(parent), m_kind(kind), m_offset(offset), m_isWii(isWii) {}
|
||||
virtual uint64_t normalizeOffset(uint64_t anOffset) const { return anOffset; }
|
||||
inline PartitionKind getKind() const { return m_kind; }
|
||||
inline bool isWii() const { return m_isWii; }
|
||||
inline uint64_t getDiscOffset() const { return m_offset; }
|
||||
virtual std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset = 0) const = 0;
|
||||
inline std::unique_ptr<IPartReadStream> beginDOLReadStream(uint64_t offset = 0) const {
|
||||
return beginReadStream(m_dolOff + offset);
|
||||
}
|
||||
inline std::unique_ptr<IPartReadStream> beginFSTReadStream(uint64_t offset = 0) const {
|
||||
return beginReadStream(m_fstOff + offset);
|
||||
}
|
||||
inline std::unique_ptr<IPartReadStream> beginApploaderReadStream(uint64_t offset = 0) const {
|
||||
return beginReadStream(0x2440 + offset);
|
||||
}
|
||||
inline const Node& getFSTRoot() const { return m_nodes[0]; }
|
||||
inline Node& getFSTRoot() { return m_nodes[0]; }
|
||||
bool extractToDirectory(SystemStringView path, const ExtractionContext& ctx);
|
||||
|
||||
inline uint64_t getDOLSize() const { return m_dolSz; }
|
||||
inline std::unique_ptr<uint8_t[]> getDOLBuf() const {
|
||||
std::unique_ptr<uint8_t[]> buf(new uint8_t[m_dolSz]);
|
||||
beginDOLReadStream()->read(buf.get(), m_dolSz);
|
||||
return buf;
|
||||
}
|
||||
|
||||
inline uint64_t getFSTSize() const { return m_fstSz; }
|
||||
inline std::unique_ptr<uint8_t[]> getFSTBuf() const {
|
||||
std::unique_ptr<uint8_t[]> buf(new uint8_t[m_fstSz]);
|
||||
beginFSTReadStream()->read(buf.get(), m_fstSz);
|
||||
return buf;
|
||||
}
|
||||
|
||||
inline uint64_t getApploaderSize() const { return m_apploaderSz; }
|
||||
inline std::unique_ptr<uint8_t[]> getApploaderBuf() const {
|
||||
std::unique_ptr<uint8_t[]> buf(new uint8_t[m_apploaderSz]);
|
||||
beginApploaderReadStream()->read(buf.get(), m_apploaderSz);
|
||||
return buf;
|
||||
}
|
||||
|
||||
inline size_t getNodeCount() const { return m_nodes.size(); }
|
||||
inline const Header& getHeader() const { return m_header; }
|
||||
inline const BI2Header& getBI2() const { return m_bi2Header; }
|
||||
virtual bool extractCryptoFiles(SystemStringView path, const ExtractionContext& ctx) const { return true; }
|
||||
bool extractSysFiles(SystemStringView path, const ExtractionContext& ctx) const;
|
||||
};
|
||||
|
||||
class DiscBase {
|
||||
public:
|
||||
virtual ~DiscBase() = default;
|
||||
|
||||
protected:
|
||||
std::unique_ptr<IDiscIO> m_discIO;
|
||||
Header m_header;
|
||||
std::vector<std::unique_ptr<IPartition>> m_partitions;
|
||||
|
||||
public:
|
||||
DiscBase(std::unique_ptr<IDiscIO>&& dio, bool& err) : m_discIO(std::move(dio)), m_header(*m_discIO, err) {}
|
||||
|
||||
inline const Header& getHeader() const { return m_header; }
|
||||
inline const IDiscIO& getDiscIO() const { return *m_discIO; }
|
||||
inline size_t getPartitonNodeCount(size_t partition = 0) const {
|
||||
if (partition > m_partitions.size())
|
||||
return -1;
|
||||
return m_partitions[partition]->getNodeCount();
|
||||
}
|
||||
|
||||
inline IPartition* getDataPartition() {
|
||||
for (const std::unique_ptr<IPartition>& part : m_partitions)
|
||||
if (part->getKind() == PartitionKind::Data)
|
||||
return part.get();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline IPartition* getUpdatePartition() {
|
||||
for (const std::unique_ptr<IPartition>& part : m_partitions)
|
||||
if (part->getKind() == PartitionKind::Update)
|
||||
return part.get();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline void extractToDirectory(SystemStringView path, const ExtractionContext& ctx) {
|
||||
for (std::unique_ptr<IPartition>& part : m_partitions)
|
||||
part->extractToDirectory(path, ctx);
|
||||
}
|
||||
|
||||
virtual bool extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const = 0;
|
||||
};
|
||||
|
||||
class DiscBuilderBase {
|
||||
friend class DiscMergerWii;
|
||||
|
||||
public:
|
||||
class PartitionBuilderBase {
|
||||
public:
|
||||
virtual ~PartitionBuilderBase() = default;
|
||||
|
||||
protected:
|
||||
std::unordered_map<SystemString, std::pair<uint64_t, uint64_t>> m_fileOffsetsSizes;
|
||||
std::vector<FSTNode> m_buildNodes;
|
||||
std::vector<std::string> m_buildNames;
|
||||
size_t m_buildNameOff = 0;
|
||||
virtual uint64_t userAllocate(uint64_t reqSz, IPartWriteStream& ws) = 0;
|
||||
virtual uint32_t packOffset(uint64_t offset) const = 0;
|
||||
|
||||
uint64_t m_dolSz;
|
||||
void parseDOL(IPartReadStream& s);
|
||||
void recursiveBuildNodesPre(SystemStringView dirIn);
|
||||
bool recursiveBuildNodes(IPartWriteStream& ws, bool system, SystemStringView dirIn);
|
||||
|
||||
const DiscBase& m_parent;
|
||||
bool recursiveBuildFST(SystemStringView dirIn, std::function<void(void)> incParents, size_t parentDirIdx);
|
||||
|
||||
void recursiveMergeNodesPre(const Node* nodeIn, SystemStringView dirIn);
|
||||
bool recursiveMergeNodes(IPartWriteStream& ws, bool system, const Node* nodeIn, SystemStringView dirIn,
|
||||
SystemStringView keyPath);
|
||||
bool recursiveMergeFST(const Node* nodeIn, SystemStringView dirIn, std::function<void(void)> incParents,
|
||||
SystemStringView keyPath);
|
||||
|
||||
static bool RecursiveCalculateTotalSize(uint64_t& totalSz, const Node* nodeIn, SystemStringView dirIn);
|
||||
|
||||
void addBuildName(SystemStringView str) {
|
||||
SystemUTF8Conv utf8View(str);
|
||||
m_buildNames.emplace_back(utf8View.utf8_str());
|
||||
m_buildNameOff += str.size() + 1;
|
||||
}
|
||||
|
||||
DiscBuilderBase& m_parent;
|
||||
PartitionKind m_kind;
|
||||
uint64_t m_offset;
|
||||
uint64_t m_dolOffset = 0;
|
||||
uint64_t m_dolSize = 0;
|
||||
bool m_isWii;
|
||||
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());
|
||||
}
|
||||
public:
|
||||
PartitionBuilderBase(DiscBuilderBase& parent, PartitionKind kind, bool isWii)
|
||||
: m_parent(parent), m_kind(kind), m_isWii(isWii) {}
|
||||
virtual std::unique_ptr<IPartWriteStream> beginWriteStream(uint64_t offset) = 0;
|
||||
bool buildFromDirectory(IPartWriteStream& ws, SystemStringView dirIn);
|
||||
static uint64_t CalculateTotalSizeBuild(SystemStringView dirIn, PartitionKind kind, bool isWii);
|
||||
bool mergeFromDirectory(IPartWriteStream& ws, const IPartition* partIn, SystemStringView dirIn);
|
||||
static uint64_t CalculateTotalSizeMerge(const IPartition* partIn, SystemStringView dirIn);
|
||||
};
|
||||
|
||||
IPartition(const DiscBase& parent, PartitionKind kind, bool isWii, uint64_t offset)
|
||||
: m_parent(parent), m_kind(kind), m_offset(offset), m_isWii(isWii) {}
|
||||
virtual uint64_t normalizeOffset(uint64_t anOffset) const {return anOffset;}
|
||||
inline PartitionKind getKind() const {return m_kind;}
|
||||
inline bool isWii() const {return m_isWii;}
|
||||
inline uint64_t getDiscOffset() const {return m_offset;}
|
||||
virtual std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset=0) const=0;
|
||||
inline std::unique_ptr<IPartReadStream> beginDOLReadStream(uint64_t offset=0) const
|
||||
{return beginReadStream(m_dolOff + offset);}
|
||||
inline std::unique_ptr<IPartReadStream> beginFSTReadStream(uint64_t offset=0) const
|
||||
{return beginReadStream(m_fstOff + offset);}
|
||||
inline std::unique_ptr<IPartReadStream> beginApploaderReadStream(uint64_t offset=0) const
|
||||
{return beginReadStream(0x2440 + offset);}
|
||||
inline const Node& getFSTRoot() const {return m_nodes[0];}
|
||||
inline Node& getFSTRoot() {return m_nodes[0];}
|
||||
bool extractToDirectory(SystemStringView path, const ExtractionContext& ctx);
|
||||
|
||||
inline uint64_t getDOLSize() const {return m_dolSz;}
|
||||
inline std::unique_ptr<uint8_t[]> getDOLBuf() const
|
||||
{
|
||||
std::unique_ptr<uint8_t[]> buf(new uint8_t[m_dolSz]);
|
||||
beginDOLReadStream()->read(buf.get(), m_dolSz);
|
||||
return buf;
|
||||
}
|
||||
|
||||
inline uint64_t getFSTSize() const {return m_fstSz;}
|
||||
inline std::unique_ptr<uint8_t[]> getFSTBuf() const
|
||||
{
|
||||
std::unique_ptr<uint8_t[]> buf(new uint8_t[m_fstSz]);
|
||||
beginFSTReadStream()->read(buf.get(), m_fstSz);
|
||||
return buf;
|
||||
}
|
||||
|
||||
inline uint64_t getApploaderSize() const {return m_apploaderSz;}
|
||||
inline std::unique_ptr<uint8_t[]> getApploaderBuf() const
|
||||
{
|
||||
std::unique_ptr<uint8_t[]> buf(new uint8_t[m_apploaderSz]);
|
||||
beginApploaderReadStream()->read(buf.get(), m_apploaderSz);
|
||||
return buf;
|
||||
}
|
||||
|
||||
inline size_t getNodeCount() const { return m_nodes.size(); }
|
||||
inline const Header& getHeader() const { return m_header; }
|
||||
inline const BI2Header& getBI2() const { return m_bi2Header; }
|
||||
virtual bool extractCryptoFiles(SystemStringView path, const ExtractionContext& ctx) const { return true; }
|
||||
bool extractSysFiles(SystemStringView path, const ExtractionContext& ctx) const;
|
||||
};
|
||||
|
||||
class DiscBase
|
||||
{
|
||||
public:
|
||||
virtual ~DiscBase() = default;
|
||||
protected:
|
||||
std::unique_ptr<IDiscIO> m_discIO;
|
||||
Header m_header;
|
||||
std::vector<std::unique_ptr<IPartition>> m_partitions;
|
||||
SystemString m_outPath;
|
||||
std::unique_ptr<IFileIO> m_fileIO;
|
||||
std::vector<std::unique_ptr<PartitionBuilderBase>> m_partitions;
|
||||
int64_t m_discCapacity;
|
||||
|
||||
public:
|
||||
DiscBase(std::unique_ptr<IDiscIO>&& dio, bool& err)
|
||||
: m_discIO(std::move(dio)), m_header(*m_discIO, err) {}
|
||||
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;
|
||||
|
||||
inline const Header& getHeader() const {return m_header;}
|
||||
inline const IDiscIO& getDiscIO() const {return *m_discIO;}
|
||||
inline size_t getPartitonNodeCount(size_t partition = 0) const
|
||||
{
|
||||
if (partition > m_partitions.size())
|
||||
return -1;
|
||||
return m_partitions[partition]->getNodeCount();
|
||||
}
|
||||
if (totalBytes)
|
||||
return (m_progressIdx + (curByte / float(totalBytes))) / float(m_progressTotal);
|
||||
else
|
||||
return m_progressIdx / float(m_progressTotal);
|
||||
}
|
||||
|
||||
inline IPartition* getDataPartition()
|
||||
{
|
||||
for (const std::unique_ptr<IPartition>& part : m_partitions)
|
||||
if (part->getKind() == PartitionKind::Data)
|
||||
return part.get();
|
||||
return nullptr;
|
||||
}
|
||||
virtual ~DiscBuilderBase() = default;
|
||||
DiscBuilderBase(SystemStringView outPath, int64_t discCapacity, FProgress progressCB)
|
||||
: m_outPath(outPath)
|
||||
, m_fileIO(NewFileIO(outPath, discCapacity))
|
||||
, m_discCapacity(discCapacity)
|
||||
, m_progressCB(progressCB) {}
|
||||
DiscBuilderBase(DiscBuilderBase&&) = default;
|
||||
DiscBuilderBase& operator=(DiscBuilderBase&&) = default;
|
||||
|
||||
inline IPartition* getUpdatePartition()
|
||||
{
|
||||
for (const std::unique_ptr<IPartition>& part : m_partitions)
|
||||
if (part->getKind() == PartitionKind::Update)
|
||||
return part.get();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline void extractToDirectory(SystemStringView path, const ExtractionContext& ctx)
|
||||
{
|
||||
for (std::unique_ptr<IPartition>& part : m_partitions)
|
||||
part->extractToDirectory(path, ctx);
|
||||
}
|
||||
|
||||
virtual bool extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const=0;
|
||||
IFileIO& getFileIO() { return *m_fileIO; }
|
||||
};
|
||||
|
||||
class DiscBuilderBase
|
||||
{
|
||||
friend class DiscMergerWii;
|
||||
public:
|
||||
class PartitionBuilderBase
|
||||
{
|
||||
public:
|
||||
virtual ~PartitionBuilderBase() = default;
|
||||
protected:
|
||||
std::unordered_map<SystemString, std::pair<uint64_t,uint64_t>> m_fileOffsetsSizes;
|
||||
std::vector<FSTNode> m_buildNodes;
|
||||
std::vector<std::string> m_buildNames;
|
||||
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(SystemStringView dirIn);
|
||||
bool recursiveBuildNodes(IPartWriteStream& ws, bool system, SystemStringView dirIn);
|
||||
|
||||
bool recursiveBuildFST(SystemStringView dirIn,
|
||||
std::function<void(void)> incParents,
|
||||
size_t parentDirIdx);
|
||||
|
||||
void recursiveMergeNodesPre(const Node* nodeIn, SystemStringView dirIn);
|
||||
bool recursiveMergeNodes(IPartWriteStream& ws, bool system,
|
||||
const Node* nodeIn, SystemStringView dirIn,
|
||||
SystemStringView keyPath);
|
||||
bool recursiveMergeFST(const Node* nodeIn,
|
||||
SystemStringView dirIn, std::function<void(void)> incParents,
|
||||
SystemStringView keyPath);
|
||||
|
||||
static bool RecursiveCalculateTotalSize(uint64_t& totalSz,
|
||||
const Node* nodeIn,
|
||||
SystemStringView dirIn);
|
||||
|
||||
void addBuildName(SystemStringView str)
|
||||
{
|
||||
SystemUTF8Conv utf8View(str);
|
||||
m_buildNames.emplace_back(utf8View.utf8_str());
|
||||
m_buildNameOff += str.size() + 1;
|
||||
}
|
||||
|
||||
DiscBuilderBase& m_parent;
|
||||
PartitionKind m_kind;
|
||||
uint64_t m_dolOffset = 0;
|
||||
uint64_t m_dolSize = 0;
|
||||
bool m_isWii;
|
||||
public:
|
||||
PartitionBuilderBase(DiscBuilderBase& parent, PartitionKind kind, bool isWii)
|
||||
: m_parent(parent), m_kind(kind), m_isWii(isWii)
|
||||
{}
|
||||
virtual std::unique_ptr<IPartWriteStream> beginWriteStream(uint64_t offset)=0;
|
||||