mirror of https://github.com/AxioDL/nod.git
Merge branch 'Minty-Meeo-Shift-JIS-fixes'
This commit is contained in:
commit
8127bddb97
308
driver/main.cpp
308
driver/main.cpp
|
@ -1,7 +1,12 @@
|
||||||
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#if _WIN32
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <io.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <logvisor/logvisor.hpp>
|
#include <logvisor/logvisor.hpp>
|
||||||
|
|
||||||
|
@ -10,14 +15,30 @@
|
||||||
#include <nod/DiscWii.hpp>
|
#include <nod/DiscWii.hpp>
|
||||||
#include <nod/nod.hpp>
|
#include <nod/nod.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
constexpr std::array<nod::Codepage_t, 3> codepages = {
|
||||||
|
CP_US_ASCII,
|
||||||
|
CP_UTF8,
|
||||||
|
CP_SHIFT_JIS,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static void printHelp() {
|
static void printHelp() {
|
||||||
fmt::print(stderr, FMT_STRING(
|
fmt::print(stderr, FMT_STRING(_SYS_STR(
|
||||||
"Usage:\n"
|
"Usage:\n"
|
||||||
" nodtool extract [-f] <image-in> [<dir-out>]\n"
|
" nodtool extract [options] <image-in> [<dir-out>]\n"
|
||||||
" nodtool makegcn <fsroot-in> [<image-out>]\n"
|
" nodtool makegcn [options] <fsroot-in> [<image-out>]\n"
|
||||||
" nodtool makewii <fsroot-in> [<image-out>]\n"
|
" nodtool makewii [options] <fsroot-in> [<image-out>]\n"
|
||||||
" nodtool mergegcn <fsroot-in> <image-in> [<image-out>]\n"
|
" nodtool mergegcn [options] <fsroot-in> <image-in> [<image-out>]\n"
|
||||||
" nodtool mergewii <fsroot-in> <image-in> [<image-out>]\n"));
|
" nodtool mergewii [options] <fsroot-in> <image-in> [<image-out>]\n"
|
||||||
|
"Options:\n"
|
||||||
|
" -f Force (extract only)\n"
|
||||||
|
" -v Verbose details (extract only).\n"
|
||||||
|
" -c <val> Set multi-byte character set of image(s).\n"
|
||||||
|
"Available codepage values:\n"
|
||||||
|
" 0 7-bit ASCII (default)\n"
|
||||||
|
" 1 UTF-8\n"
|
||||||
|
" 2 Shift-JIS\n")));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if NOD_UCS2
|
#if NOD_UCS2
|
||||||
|
@ -32,37 +53,57 @@ int wmain(int argc, wchar_t* argv[])
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
#endif
|
#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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Enable logging to console */
|
/* Enable logging to console */
|
||||||
logvisor::RegisterStandardExceptions();
|
logvisor::RegisterStandardExceptions();
|
||||||
logvisor::RegisterConsoleLogger();
|
logvisor::RegisterConsoleLogger();
|
||||||
|
#if _WIN32
|
||||||
|
_setmode(_fileno(stdin), _O_U16TEXT);
|
||||||
|
_setmode(_fileno(stdout), _O_U16TEXT);
|
||||||
|
_setmode(_fileno(stderr), _O_U16TEXT);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int argidx = 1;
|
||||||
|
nod::SystemString errand;
|
||||||
bool verbose = false;
|
bool verbose = false;
|
||||||
nod::ExtractionContext ctx = {true, [&](std::string_view str, float c) {
|
nod::Codepage_t discLocale = CP_US_ASCII;
|
||||||
|
nod::ExtractionContext ctx = {true, [&](nod::SystemStringView str, float c) {
|
||||||
if (verbose)
|
if (verbose)
|
||||||
fmt::print(stderr, FMT_STRING("Current node: {}, Extraction {:g}% Complete\n"), str,
|
fmt::print(stderr, FMT_STRING(_SYS_STR("Current node: {}, Extraction {:g}% Complete\n")),
|
||||||
c * 100.f);
|
str, c * 100.f);
|
||||||
}};
|
}};
|
||||||
const nod::SystemChar* inDir = nullptr;
|
while (argidx < argc) {
|
||||||
const nod::SystemChar* outDir = _SYS_STR(".");
|
if (!strcasecmp(argv[argidx], _SYS_STR("-f"))) {
|
||||||
|
|
||||||
for (int a = 2; a < argc; ++a) {
|
|
||||||
if (argv[a][0] == '-' && argv[a][1] == 'f')
|
|
||||||
ctx.force = true;
|
ctx.force = true;
|
||||||
else if (argv[a][0] == '-' && argv[a][1] == 'v')
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else if (!strcasecmp(argv[argidx], _SYS_STR("-v"))) {
|
||||||
verbose = true;
|
verbose = true;
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else if (!strcasecmp(argv[argidx], _SYS_STR("-c"))) {
|
||||||
|
if (argidx+1 < argc) {
|
||||||
|
unsigned long cpidx = nod::StrToUL(argv[argidx + 1], NULL, 0);
|
||||||
|
if (cpidx > codepages.size() - 1)
|
||||||
|
nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("Unavailable codepage: {}")), cpidx);
|
||||||
|
discLocale = codepages[cpidx];
|
||||||
|
} else {
|
||||||
|
printHelp();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
argidx += 2;
|
||||||
|
continue;
|
||||||
|
} else if (errand.empty()) {
|
||||||
|
errand = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else if (!inDir)
|
if (errand.empty()) {
|
||||||
inDir = argv[a];
|
printHelp();
|
||||||
else
|
return 1;
|
||||||
outDir = argv[a];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto progFunc = [&](float prog, nod::SystemStringView name, size_t bytes) {
|
auto progFunc = [&](float prog, nod::SystemStringView name, size_t bytes) {
|
||||||
|
@ -74,89 +115,156 @@ int main(int argc, char* argv[])
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!strcasecmp(argv[1], _SYS_STR("extract"))) {
|
if (errand == _SYS_STR("extract")) {
|
||||||
|
nod::SystemString imageIn;
|
||||||
|
nod::SystemString dirOut;
|
||||||
|
while (argidx < argc) {
|
||||||
|
if (imageIn.empty()) {
|
||||||
|
imageIn = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else if (dirOut.empty()) {
|
||||||
|
dirOut = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
printHelp();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dirOut.empty())
|
||||||
|
dirOut = _SYS_STR(".");
|
||||||
|
|
||||||
bool isWii;
|
bool isWii;
|
||||||
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(inDir, isWii);
|
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(imageIn, isWii, discLocale);
|
||||||
if (!disc)
|
if (!disc)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
nod::Mkdir(outDir, 0755);
|
nod::Mkdir(dirOut.c_str(), 0755);
|
||||||
|
|
||||||
nod::IPartition* dataPart = disc->getDataPartition();
|
nod::IPartition* dataPart = disc->getDataPartition();
|
||||||
if (!dataPart)
|
if (!dataPart)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (!dataPart->extractToDirectory(outDir, ctx))
|
if (!dataPart->extractToDirectory(dirOut, ctx))
|
||||||
return 1;
|
return 1;
|
||||||
} else if (!strcasecmp(argv[1], _SYS_STR("makegcn"))) {
|
} else if (errand == _SYS_STR("makegcn")) {
|
||||||
|
nod::SystemString fsrootIn;
|
||||||
|
nod::SystemString imageOut;
|
||||||
|
while (argidx < argc) {
|
||||||
|
if (fsrootIn.empty()) {
|
||||||
|
fsrootIn = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else if (imageOut.empty()) {
|
||||||
|
imageOut = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
printHelp();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (imageOut.empty())
|
||||||
|
imageOut = fsrootIn + _SYS_STR(".gcm");
|
||||||
|
|
||||||
/* Pre-validate path */
|
/* Pre-validate path */
|
||||||
nod::Sstat theStat;
|
nod::Sstat theStat;
|
||||||
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode)) {
|
if (nod::Stat(fsrootIn.c_str(), &theStat) || !S_ISDIR(theStat.st_mode)) {
|
||||||
nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {} as directory")), argv[2]);
|
nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {} as directory")), fsrootIn);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nod::DiscBuilderGCN::CalculateTotalSizeRequired(argv[2]))
|
if (!nod::DiscBuilderGCN::CalculateTotalSizeRequired(fsrootIn, discLocale))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
nod::EBuildResult ret;
|
nod::EBuildResult ret;
|
||||||
|
|
||||||
if (argc < 4) {
|
nod::DiscBuilderGCN b(imageOut, progFunc, discLocale);
|
||||||
nod::SystemString outPath(argv[2]);
|
ret = b.buildFromDirectory(fsrootIn);
|
||||||
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]);
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt::print(FMT_STRING("\n"));
|
fmt::print(FMT_STRING(_SYS_STR("\n")));
|
||||||
if (ret != nod::EBuildResult::Success)
|
if (ret != nod::EBuildResult::Success)
|
||||||
return 1;
|
return 1;
|
||||||
} else if (!strcasecmp(argv[1], _SYS_STR("makewii"))) {
|
} else if (errand == _SYS_STR("makewii")) {
|
||||||
|
nod::SystemString fsrootIn;
|
||||||
|
nod::SystemString imageOut;
|
||||||
|
while (argidx < argc) {
|
||||||
|
if (fsrootIn.empty()) {
|
||||||
|
fsrootIn = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else if (imageOut.empty()) {
|
||||||
|
imageOut = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
printHelp();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (imageOut.empty())
|
||||||
|
imageOut = fsrootIn + _SYS_STR(".iso");
|
||||||
|
|
||||||
/* Pre-validate path */
|
/* Pre-validate path */
|
||||||
nod::Sstat theStat;
|
nod::Sstat theStat;
|
||||||
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode)) {
|
if (nod::Stat(fsrootIn.c_str(), &theStat) || !S_ISDIR(theStat.st_mode)) {
|
||||||
nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {} as directory")), argv[4]);
|
nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {} as directory")), fsrootIn);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dual = false;
|
bool dual = false;
|
||||||
if (!nod::DiscBuilderWii::CalculateTotalSizeRequired(argv[2], dual))
|
if (!nod::DiscBuilderWii::CalculateTotalSizeRequired(fsrootIn, dual, discLocale))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
nod::EBuildResult ret;
|
nod::EBuildResult ret;
|
||||||
|
|
||||||
if (argc < 4) {
|
nod::DiscBuilderWii b(imageOut, dual, progFunc, discLocale);
|
||||||
nod::SystemString outPath(argv[2]);
|
ret = b.buildFromDirectory(fsrootIn);
|
||||||
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]);
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt::print(FMT_STRING("\n"));
|
fmt::print(FMT_STRING(_SYS_STR("\n")));
|
||||||
if (ret != nod::EBuildResult::Success)
|
if (ret != nod::EBuildResult::Success)
|
||||||
return 1;
|
return 1;
|
||||||
} else if (!strcasecmp(argv[1], _SYS_STR("mergegcn"))) {
|
} else if (errand == _SYS_STR("mergegcn")) {
|
||||||
|
nod::SystemString fsrootIn;
|
||||||
|
nod::SystemString imageIn;
|
||||||
|
nod::SystemString imageOut;
|
||||||
|
while (argidx < argc) {
|
||||||
|
if (fsrootIn.empty()) {
|
||||||
|
fsrootIn = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else if (imageIn.empty()) {
|
||||||
|
imageIn = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else if (imageOut.empty()) {
|
||||||
|
imageOut = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
printHelp();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (imageOut.empty())
|
||||||
|
imageOut = fsrootIn + _SYS_STR(".gcm");
|
||||||
|
|
||||||
/* Pre-validate paths */
|
/* Pre-validate paths */
|
||||||
nod::Sstat theStat;
|
nod::Sstat theStat;
|
||||||
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode)) {
|
if (nod::Stat(fsrootIn.c_str(), &theStat) || !S_ISDIR(theStat.st_mode)) {
|
||||||
nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {} as directory")), argv[2]);
|
nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {} as directory")), fsrootIn);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (nod::Stat(argv[3], &theStat) || !S_ISREG(theStat.st_mode)) {
|
if (nod::Stat(imageIn.c_str(), &theStat) || !S_ISREG(theStat.st_mode)) {
|
||||||
nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {} as file")), argv[3]);
|
nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {} as file")), imageIn);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isWii;
|
bool isWii;
|
||||||
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(argv[3], isWii);
|
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(imageIn, isWii, discLocale);
|
||||||
if (!disc) {
|
if (!disc) {
|
||||||
nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to open image {}")), argv[3]);
|
nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to open image {}")), imageIn);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (isWii) {
|
if (isWii) {
|
||||||
|
@ -164,38 +272,55 @@ int main(int argc, char* argv[])
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nod::DiscMergerGCN::CalculateTotalSizeRequired(static_cast<nod::DiscGCN&>(*disc), argv[2]))
|
if (!nod::DiscMergerGCN::CalculateTotalSizeRequired(static_cast<nod::DiscGCN&>(*disc), fsrootIn, discLocale))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
nod::EBuildResult ret;
|
nod::EBuildResult ret;
|
||||||
|
|
||||||
if (argc < 5) {
|
nod::DiscMergerGCN b(imageOut, static_cast<nod::DiscGCN&>(*disc), progFunc, discLocale);
|
||||||
nod::SystemString outPath(argv[2]);
|
ret = b.mergeFromDirectory(fsrootIn);
|
||||||
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]);
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt::print(FMT_STRING("\n"));
|
fmt::print(FMT_STRING(_SYS_STR("\n")));
|
||||||
if (ret != nod::EBuildResult::Success)
|
if (ret != nod::EBuildResult::Success)
|
||||||
return 1;
|
return 1;
|
||||||
} else if (!strcasecmp(argv[1], _SYS_STR("mergewii"))) {
|
} else if (errand == _SYS_STR("mergewii")) {
|
||||||
|
nod::SystemString fsrootIn;
|
||||||
|
nod::SystemString imageIn;
|
||||||
|
nod::SystemString imageOut;
|
||||||
|
while (argidx < argc) {
|
||||||
|
if (fsrootIn.empty()) {
|
||||||
|
fsrootIn = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else if (imageIn.empty()) {
|
||||||
|
imageIn = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else if (imageOut.empty()) {
|
||||||
|
imageOut = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
printHelp();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (imageOut.empty())
|
||||||
|
imageOut = fsrootIn + _SYS_STR(".iso");
|
||||||
|
|
||||||
/* Pre-validate paths */
|
/* Pre-validate paths */
|
||||||
nod::Sstat theStat;
|
nod::Sstat theStat;
|
||||||
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode)) {
|
if (nod::Stat(fsrootIn.c_str(), &theStat) || !S_ISDIR(theStat.st_mode)) {
|
||||||
nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {} as directory")), argv[2]);
|
nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {} as directory")), fsrootIn);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (nod::Stat(argv[3], &theStat) || !S_ISREG(theStat.st_mode)) {
|
if (nod::Stat(imageIn.c_str(), &theStat) || !S_ISREG(theStat.st_mode)) {
|
||||||
nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {} as file")), argv[3]);
|
nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {} as file")), imageIn);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isWii;
|
bool isWii;
|
||||||
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(argv[3], isWii);
|
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(imageIn, isWii, discLocale);
|
||||||
if (!disc) {
|
if (!disc) {
|
||||||
nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to open image {}")), argv[3]);
|
nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to open image {}")), argv[3]);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -206,22 +331,15 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dual = false;
|
bool dual = false;
|
||||||
if (!nod::DiscMergerWii::CalculateTotalSizeRequired(static_cast<nod::DiscWii&>(*disc), argv[2], dual))
|
if (!nod::DiscMergerWii::CalculateTotalSizeRequired(static_cast<nod::DiscWii&>(*disc), fsrootIn, dual, discLocale))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
nod::EBuildResult ret;
|
nod::EBuildResult ret;
|
||||||
|
|
||||||
if (argc < 5) {
|
nod::DiscMergerWii b(imageOut, static_cast<nod::DiscWii&>(*disc), dual, progFunc, discLocale);
|
||||||
nod::SystemString outPath(argv[2]);
|
ret = b.mergeFromDirectory(fsrootIn);
|
||||||
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]);
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt::print(FMT_STRING("\n"));
|
fmt::print(FMT_STRING(_SYS_STR("\n")));
|
||||||
if (ret != nod::EBuildResult::Success)
|
if (ret != nod::EBuildResult::Success)
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -236,7 +236,7 @@ public:
|
||||||
return end();
|
return end();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool extractToDirectory(SystemStringView basePath, const ExtractionContext& ctx) const;
|
bool extractToDirectory(SystemStringView basePath, const ExtractionContext& ctx, Codepage_t codepage) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IPartition {
|
class IPartition {
|
||||||
|
@ -275,6 +275,7 @@ protected:
|
||||||
PartitionKind m_kind;
|
PartitionKind m_kind;
|
||||||
uint64_t m_offset;
|
uint64_t m_offset;
|
||||||
bool m_isWii;
|
bool m_isWii;
|
||||||
|
Codepage_t m_codepage;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
mutable size_t m_curNodeIdx = 0;
|
mutable size_t m_curNodeIdx = 0;
|
||||||
|
@ -289,8 +290,8 @@ public:
|
||||||
return m_curNodeIdx / float(getNodeCount());
|
return m_curNodeIdx / float(getNodeCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
IPartition(const DiscBase& parent, PartitionKind kind, bool isWii, uint64_t offset)
|
IPartition(const DiscBase& parent, PartitionKind kind, bool isWii, uint64_t offset, Codepage_t codepage)
|
||||||
: m_parent(parent), m_kind(kind), m_offset(offset), m_isWii(isWii) {}
|
: m_parent(parent), m_kind(kind), m_offset(offset), m_isWii(isWii), m_codepage(codepage) {}
|
||||||
virtual uint64_t normalizeOffset(uint64_t anOffset) const { return anOffset; }
|
virtual uint64_t normalizeOffset(uint64_t anOffset) const { return anOffset; }
|
||||||
PartitionKind getKind() const { return m_kind; }
|
PartitionKind getKind() const { return m_kind; }
|
||||||
bool isWii() const { return m_isWii; }
|
bool isWii() const { return m_isWii; }
|
||||||
|
@ -405,14 +406,14 @@ public:
|
||||||
bool recursiveMergeNodes(IPartWriteStream& ws, bool system, const Node* nodeIn, SystemStringView dirIn,
|
bool recursiveMergeNodes(IPartWriteStream& ws, bool system, const Node* nodeIn, SystemStringView dirIn,
|
||||||
SystemStringView keyPath);
|
SystemStringView keyPath);
|
||||||
bool recursiveMergeFST(const Node* nodeIn, SystemStringView dirIn, std::function<void(void)> incParents,
|
bool recursiveMergeFST(const Node* nodeIn, SystemStringView dirIn, std::function<void(void)> incParents,
|
||||||
SystemStringView keyPath);
|
size_t parentDirIdx, SystemStringView keyPath);
|
||||||
|
|
||||||
static bool RecursiveCalculateTotalSize(uint64_t& totalSz, const Node* nodeIn, SystemStringView dirIn);
|
static bool RecursiveCalculateTotalSize(uint64_t& totalSz, const Node* nodeIn, SystemStringView dirIn, Codepage_t codepage);
|
||||||
|
|
||||||
void addBuildName(SystemStringView str) {
|
void addBuildName(SystemStringView str) {
|
||||||
SystemUTF8Conv utf8View(str);
|
SystemToDiscLocConv nameView(str, m_codepage);
|
||||||
m_buildNames.emplace_back(utf8View.utf8_str());
|
m_buildNames.emplace_back(nameView.disc_str());
|
||||||
m_buildNameOff += str.size() + 1;
|
m_buildNameOff += nameView.disc_str().size() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscBuilderBase& m_parent;
|
DiscBuilderBase& m_parent;
|
||||||
|
@ -420,15 +421,16 @@ public:
|
||||||
uint64_t m_dolOffset = 0;
|
uint64_t m_dolOffset = 0;
|
||||||
uint64_t m_dolSize = 0;
|
uint64_t m_dolSize = 0;
|
||||||
bool m_isWii;
|
bool m_isWii;
|
||||||
|
Codepage_t m_codepage;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PartitionBuilderBase(DiscBuilderBase& parent, PartitionKind kind, bool isWii)
|
PartitionBuilderBase(DiscBuilderBase& parent, PartitionKind kind, bool isWii, Codepage_t codepage)
|
||||||
: m_parent(parent), m_kind(kind), m_isWii(isWii) {}
|
: m_parent(parent), m_kind(kind), m_isWii(isWii), m_codepage(codepage) {}
|
||||||
virtual std::unique_ptr<IPartWriteStream> beginWriteStream(uint64_t offset) = 0;
|
virtual std::unique_ptr<IPartWriteStream> beginWriteStream(uint64_t offset) = 0;
|
||||||
bool buildFromDirectory(IPartWriteStream& ws, SystemStringView dirIn);
|
bool buildFromDirectory(IPartWriteStream& ws, SystemStringView dirIn);
|
||||||
static std::optional<uint64_t> CalculateTotalSizeBuild(SystemStringView dirIn, PartitionKind kind, bool isWii);
|
static std::optional<uint64_t> CalculateTotalSizeBuild(SystemStringView dirIn, PartitionKind kind, bool isWii, Codepage_t codepage);
|
||||||
bool mergeFromDirectory(IPartWriteStream& ws, const IPartition* partIn, SystemStringView dirIn);
|
bool mergeFromDirectory(IPartWriteStream& ws, const IPartition* partIn, SystemStringView dirIn);
|
||||||
static std::optional<uint64_t> CalculateTotalSizeMerge(const IPartition* partIn, SystemStringView dirIn);
|
static std::optional<uint64_t> CalculateTotalSizeMerge(const IPartition* partIn, SystemStringView dirIn, Codepage_t codepage);
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -7,10 +7,10 @@ class DiscBuilderGCN;
|
||||||
|
|
||||||
class DiscGCN : public DiscBase {
|
class DiscGCN : public DiscBase {
|
||||||
friend class DiscMergerGCN;
|
friend class DiscMergerGCN;
|
||||||
DiscBuilderGCN makeMergeBuilder(SystemStringView outPath, FProgress progressCB);
|
DiscBuilderGCN makeMergeBuilder(SystemStringView outPath, FProgress progressCB, Codepage_t codepage);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DiscGCN(std::unique_ptr<IDiscIO>&& dio, bool& err);
|
DiscGCN(std::unique_ptr<IDiscIO>&& dio, bool& err, Codepage_t codepage = CP_US_ASCII);
|
||||||
bool extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const override;
|
bool extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,9 +18,9 @@ class DiscBuilderGCN : public DiscBuilderBase {
|
||||||
friend class DiscMergerGCN;
|
friend class DiscMergerGCN;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DiscBuilderGCN(SystemStringView outPath, FProgress progressCB);
|
DiscBuilderGCN(SystemStringView outPath, FProgress progressCB, Codepage_t codepage = CP_US_ASCII);
|
||||||
EBuildResult buildFromDirectory(SystemStringView dirIn);
|
EBuildResult buildFromDirectory(SystemStringView dirIn);
|
||||||
static std::optional<uint64_t> CalculateTotalSizeRequired(SystemStringView dirIn);
|
static std::optional<uint64_t> CalculateTotalSizeRequired(SystemStringView dirIn, Codepage_t codepage = CP_US_ASCII);
|
||||||
};
|
};
|
||||||
|
|
||||||
class DiscMergerGCN {
|
class DiscMergerGCN {
|
||||||
|
@ -28,9 +28,9 @@ class DiscMergerGCN {
|
||||||
DiscBuilderGCN m_builder;
|
DiscBuilderGCN m_builder;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DiscMergerGCN(SystemStringView outPath, DiscGCN& sourceDisc, FProgress progressCB);
|
DiscMergerGCN(SystemStringView outPath, DiscGCN& sourceDisc, FProgress progressCB, Codepage_t codepage = CP_US_ASCII);
|
||||||
EBuildResult mergeFromDirectory(SystemStringView dirIn);
|
EBuildResult mergeFromDirectory(SystemStringView dirIn);
|
||||||
static std::optional<uint64_t> CalculateTotalSizeRequired(DiscGCN& sourceDisc, SystemStringView dirIn);
|
static std::optional<uint64_t> CalculateTotalSizeRequired(DiscGCN& sourceDisc, SystemStringView dirIn, Codepage_t codepage = CP_US_ASCII);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace nod
|
} // namespace nod
|
||||||
|
|
|
@ -7,16 +7,16 @@ class DiscBuilderWii;
|
||||||
|
|
||||||
class DiscWii : public DiscBase {
|
class DiscWii : public DiscBase {
|
||||||
public:
|
public:
|
||||||
DiscWii(std::unique_ptr<IDiscIO>&& dio, bool& err);
|
DiscWii(std::unique_ptr<IDiscIO>&& dio, bool& err, Codepage_t codepage = CP_US_ASCII);
|
||||||
DiscBuilderWii makeMergeBuilder(SystemStringView outPath, bool dualLayer, FProgress progressCB);
|
DiscBuilderWii makeMergeBuilder(SystemStringView outPath, bool dualLayer, FProgress progressCB, Codepage_t codepage);
|
||||||
bool extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const override;
|
bool extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DiscBuilderWii : public DiscBuilderBase {
|
class DiscBuilderWii : public DiscBuilderBase {
|
||||||
public:
|
public:
|
||||||
DiscBuilderWii(SystemStringView outPath, bool dualLayer, FProgress progressCB);
|
DiscBuilderWii(SystemStringView outPath, bool dualLayer, FProgress progressCB, Codepage_t codepage = CP_US_ASCII);
|
||||||
EBuildResult buildFromDirectory(SystemStringView dirIn);
|
EBuildResult buildFromDirectory(SystemStringView dirIn);
|
||||||
static std::optional<uint64_t> CalculateTotalSizeRequired(SystemStringView dirIn, bool& dualLayer);
|
static std::optional<uint64_t> CalculateTotalSizeRequired(SystemStringView dirIn, bool& dualLayer, Codepage_t codepage = CP_US_ASCII);
|
||||||
};
|
};
|
||||||
|
|
||||||
class DiscMergerWii {
|
class DiscMergerWii {
|
||||||
|
@ -24,9 +24,9 @@ class DiscMergerWii {
|
||||||
DiscBuilderWii m_builder;
|
DiscBuilderWii m_builder;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DiscMergerWii(SystemStringView outPath, DiscWii& sourceDisc, bool dualLayer, FProgress progressCB);
|
DiscMergerWii(SystemStringView outPath, DiscWii& sourceDisc, bool dualLayer, FProgress progressCB, Codepage_t codepage = CP_US_ASCII);
|
||||||
EBuildResult mergeFromDirectory(SystemStringView dirIn);
|
EBuildResult mergeFromDirectory(SystemStringView dirIn);
|
||||||
static std::optional<uint64_t> CalculateTotalSizeRequired(DiscWii& sourceDisc, SystemStringView dirIn, bool& dualLayer);
|
static std::optional<uint64_t> CalculateTotalSizeRequired(DiscWii& sourceDisc, SystemStringView dirIn, bool& dualLayer, Codepage_t codepage = CP_US_ASCII);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace nod
|
} // namespace nod
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#else
|
#else
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
|
#include <iconv.h>
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/statvfs.h>
|
#include <sys/statvfs.h>
|
||||||
|
@ -75,9 +76,9 @@ extern logvisor::Module LogModule;
|
||||||
/* filesystem char type */
|
/* filesystem char type */
|
||||||
#if _WIN32 && UNICODE
|
#if _WIN32 && UNICODE
|
||||||
#define NOD_UCS2 1
|
#define NOD_UCS2 1
|
||||||
typedef struct _stat Sstat;
|
typedef struct _stat64 Sstat;
|
||||||
static inline int Mkdir(const wchar_t* path, int) { return _wmkdir(path); }
|
static inline int Mkdir(const wchar_t* path, int) { return _wmkdir(path); }
|
||||||
static inline int Stat(const wchar_t* path, Sstat* statout) { return _wstat(path, statout); }
|
static inline int Stat(const wchar_t* path, Sstat* statout) { return _wstati64(path, statout); }
|
||||||
#else
|
#else
|
||||||
typedef struct stat Sstat;
|
typedef struct stat Sstat;
|
||||||
static inline int Mkdir(const char* path, mode_t mode) { return mkdir(path, mode); }
|
static inline int Mkdir(const char* path, mode_t mode) { return mkdir(path, mode); }
|
||||||
|
@ -86,65 +87,164 @@ static inline int Stat(const char* path, Sstat* statout) { return stat(path, sta
|
||||||
|
|
||||||
/* String-converting views */
|
/* String-converting views */
|
||||||
#if NOD_UCS2
|
#if NOD_UCS2
|
||||||
typedef wchar_t SystemChar;
|
#define CP_US_ASCII 20127
|
||||||
typedef std::wstring SystemString;
|
#define CP_SHIFT_JIS 932
|
||||||
typedef std::wstring_view SystemStringView;
|
#define CP_GB_18030 54936
|
||||||
static inline void ToLower(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), towlower); }
|
|
||||||
static inline void ToUpper(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), towupper); }
|
|
||||||
static inline size_t StrLen(const SystemChar* str) { return wcslen(str); }
|
|
||||||
class SystemUTF8Conv {
|
|
||||||
std::string m_utf8;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit SystemUTF8Conv(SystemStringView str) {
|
|
||||||
int len = WideCharToMultiByte(CP_UTF8, 0, str.data(), str.size(), nullptr, 0, nullptr, nullptr);
|
|
||||||
m_utf8.assign(len, '\0');
|
|
||||||
WideCharToMultiByte(CP_UTF8, 0, str.data(), str.size(), &m_utf8[0], len, nullptr, nullptr);
|
|
||||||
}
|
|
||||||
std::string_view utf8_str() const { return m_utf8; }
|
|
||||||
const char* c_str() const { return m_utf8.c_str(); }
|
|
||||||
};
|
|
||||||
class SystemStringConv {
|
|
||||||
std::wstring m_sys;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit SystemStringConv(std::string_view str) {
|
|
||||||
int len = MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), nullptr, 0);
|
|
||||||
m_sys.assign(len, L'\0');
|
|
||||||
MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), &m_sys[0], len);
|
|
||||||
}
|
|
||||||
SystemStringView sys_str() const { return m_sys; }
|
|
||||||
const SystemChar* c_str() const { return m_sys.c_str(); }
|
|
||||||
};
|
|
||||||
#ifndef _SYS_STR
|
#ifndef _SYS_STR
|
||||||
#define _SYS_STR(val) L##val
|
#define _SYS_STR(val) L##val
|
||||||
#endif
|
#endif
|
||||||
|
typedef wchar_t SystemChar;
|
||||||
|
typedef std::wstring SystemString;
|
||||||
|
typedef std::wstring_view SystemStringView;
|
||||||
|
typedef UINT Codepage_t;
|
||||||
|
static inline void ToLower(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), towlower); }
|
||||||
|
static inline void ToUpper(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), towupper); }
|
||||||
|
static inline size_t StrLen(const SystemChar* str) { return wcslen(str); }
|
||||||
|
static inline unsigned long StrToUL(const SystemChar* str, SystemChar** endptr, int base) {return wcstoul(str, endptr, base); }
|
||||||
|
class SystemToDiscLocConv {
|
||||||
|
std::string m_disc_str;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit SystemToDiscLocConv(SystemStringView str, Codepage_t codepage) {
|
||||||
|
if (!IsValidCodePage(codepage))
|
||||||
|
nod::LogModule.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Invalid Codepage ({})")), codepage);
|
||||||
|
|
||||||
|
size_t len;
|
||||||
|
bool failureState = false;
|
||||||
|
switch (codepage) {
|
||||||
|
case CP_UTF8: case CP_GB_18030:
|
||||||
|
len = WideCharToMultiByte(codepage, WC_ERR_INVALID_CHARS, str.data(), str.size(), nullptr, 0, nullptr, nullptr);
|
||||||
|
if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION)
|
||||||
|
failureState = true;
|
||||||
|
break;
|
||||||
|
case CP_UTF7:
|
||||||
|
// WideCharToMultiByte cannot use WC_ERR_INVALID_CHARS nor lpUsedDefaultChar to check for a bad conversion when converting to UTF-7.
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-widechartomultibyte
|
||||||
|
len = WideCharToMultiByte(codepage, 0, str.data(), str.size(), nullptr, 0, nullptr, nullptr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BOOL lpUsedDefaultChar = false;
|
||||||
|
len = WideCharToMultiByte(codepage, 0, str.data(), str.size(), nullptr, 0, nullptr, &lpUsedDefaultChar);
|
||||||
|
if (lpUsedDefaultChar)
|
||||||
|
failureState = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m_disc_str.assign(len, '\0');
|
||||||
|
WideCharToMultiByte(codepage, 0, str.data(), str.size(), &m_disc_str[0], len, nullptr, nullptr);
|
||||||
|
if (failureState)
|
||||||
|
nod::LogModule.report(logvisor::Warning, FMT_STRING(_SYS_STR("Bad conversion to codepage {}: \"{}\"")), codepage, str);
|
||||||
|
|
||||||
|
}
|
||||||
|
std::string_view disc_str() const { return m_disc_str; }
|
||||||
|
const char* c_str() const { return m_disc_str.c_str(); }
|
||||||
|
};
|
||||||
|
class DiscLocToSystemConv {
|
||||||
|
SystemString m_sys_str;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DiscLocToSystemConv(std::string_view str, Codepage_t codepage) {
|
||||||
|
if (!IsValidCodePage(codepage))
|
||||||
|
nod::LogModule.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Invalid Codepage ({})")), codepage);
|
||||||
|
|
||||||
|
bool failureState = false;
|
||||||
|
size_t len = MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, str.data(), str.size(), nullptr, 0);
|
||||||
|
if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION)
|
||||||
|
failureState = true;
|
||||||
|
|
||||||
|
m_sys_str.assign(len, L'\0');
|
||||||
|
MultiByteToWideChar(codepage, 0, str.data(), str.size(), &m_sys_str[0], len);
|
||||||
|
if (failureState)
|
||||||
|
// This will probably never happen, but might as well check.
|
||||||
|
nod::LogModule.report(logvisor::Warning, FMT_STRING(_SYS_STR("Bad conversion from codepage {}: \"{}\"")), codepage, m_sys_str);
|
||||||
|
}
|
||||||
|
SystemStringView sys_str() const { return m_sys_str; }
|
||||||
|
const SystemChar* c_str() const { return m_sys_str.c_str(); }
|
||||||
|
};
|
||||||
#else
|
#else
|
||||||
typedef char SystemChar;
|
#define CP_US_ASCII "US-ASCII"
|
||||||
typedef std::string SystemString;
|
#define CP_UTF8 "UTF-8"
|
||||||
typedef std::string_view SystemStringView;
|
#define CP_SHIFT_JIS "SHIFT-JIS"
|
||||||
static inline void ToLower(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), tolower); }
|
|
||||||
static inline void ToUpper(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), toupper); }
|
|
||||||
static inline size_t StrLen(const SystemChar* str) { return strlen(str); }
|
|
||||||
class SystemUTF8Conv {
|
|
||||||
std::string_view m_utf8;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit SystemUTF8Conv(SystemStringView str) : m_utf8(str) {}
|
|
||||||
std::string_view utf8_str() const { return m_utf8; }
|
|
||||||
const char* c_str() const { return m_utf8.data(); }
|
|
||||||
};
|
|
||||||
class SystemStringConv {
|
|
||||||
SystemStringView m_sys;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit SystemStringConv(std::string_view str) : m_sys(str) {}
|
|
||||||
SystemStringView sys_str() const { return m_sys; }
|
|
||||||
const SystemChar* c_str() const { return m_sys.data(); }
|
|
||||||
};
|
|
||||||
#ifndef _SYS_STR
|
#ifndef _SYS_STR
|
||||||
#define _SYS_STR(val) val
|
#define _SYS_STR(val) val
|
||||||
#endif
|
#endif
|
||||||
|
typedef char SystemChar;
|
||||||
|
typedef std::string SystemString;
|
||||||
|
typedef std::string_view SystemStringView;
|
||||||
|
typedef const char* Codepage_t;
|
||||||
|
static inline void ToLower(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), tolower); }
|
||||||
|
static inline void ToUpper(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), toupper); }
|
||||||
|
static inline size_t StrLen(const SystemChar* str) { return strlen(str); }
|
||||||
|
static inline unsigned long StrToUL(const SystemChar* str, SystemChar** endptr, int base) {return strtoul(str, endptr, base); }
|
||||||
|
static inline bool CodepageConvert(const iconv_t convDesc, std::string_view input, std::string& output)
|
||||||
|
{
|
||||||
|
bool failureState = false;
|
||||||
|
size_t const inBytes = input.size();
|
||||||
|
size_t const outBufferSize = 4 * inBytes;
|
||||||
|
|
||||||
|
std::string outBuffer;
|
||||||
|
outBuffer.resize(outBufferSize);
|
||||||
|
|
||||||
|
auto srcBuffer = input.data();
|
||||||
|
size_t srcBytes = inBytes;
|
||||||
|
auto dstBuffer = outBuffer.data();
|
||||||
|
size_t dstBytes = outBuffer.size();
|
||||||
|
|
||||||
|
while (srcBytes != 0) {
|
||||||
|
size_t const iconvResult =
|
||||||
|
#if defined(__OpenBSD__) || defined(__NetBSD__)
|
||||||
|
iconv(convDesc, reinterpret_cast<const char**>(&srcBuffer), &srcBytes, &dstBuffer, &dstBytes);
|
||||||
|
#else
|
||||||
|
iconv(convDesc, const_cast<char**>(reinterpret_cast<const char**>(&srcBuffer)), &srcBytes, &dstBuffer, &dstBytes);
|
||||||
|
#endif
|
||||||
|
if ((size_t)-1 == iconvResult) {
|
||||||
|
failureState = true;
|
||||||
|
if (EILSEQ == errno || EINVAL == errno) {
|
||||||
|
// Try to skip the bad character
|
||||||
|
if (srcBytes != 0) {
|
||||||
|
--srcBytes;
|
||||||
|
++srcBuffer;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outBuffer.resize(outBufferSize - dstBytes);
|
||||||
|
outBuffer.swap(output);
|
||||||
|
return failureState;
|
||||||
|
}
|
||||||
|
class SystemToDiscLocConv {
|
||||||
|
std::string m_disc_str;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit SystemToDiscLocConv(SystemStringView str, Codepage_t codepage) {
|
||||||
|
const iconv_t convDesc = iconv_open(codepage, CP_UTF8);
|
||||||
|
if (convDesc == (iconv_t)-1)
|
||||||
|
nod::LogModule.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Invalid Codepage \"{}\"")), codepage);
|
||||||
|
|
||||||
|
if (CodepageConvert(convDesc, str, m_disc_str) == true)
|
||||||
|
nod::LogModule.report(logvisor::Warning, FMT_STRING(_SYS_STR("Bad conversion to codepage \"{}\": \"{}\"")), codepage, str);
|
||||||
|
iconv_close(convDesc);
|
||||||
|
}
|
||||||
|
std::string_view disc_str() const { return m_disc_str; }
|
||||||
|
const char* c_str() const { return m_disc_str.data(); }
|
||||||
|
};
|
||||||
|
class DiscLocToSystemConv {
|
||||||
|
SystemString m_sys_str;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DiscLocToSystemConv(std::string_view str, Codepage_t codepage) {
|
||||||
|
const iconv_t convDesc = iconv_open(CP_UTF8, codepage);
|
||||||
|
if (convDesc == (iconv_t)-1)
|
||||||
|
nod::LogModule.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Invalid Codepage \"{}\"")), codepage);
|
||||||
|
|
||||||
|
if (CodepageConvert(convDesc, str, m_sys_str) == true)
|
||||||
|
nod::LogModule.report(logvisor::Warning, FMT_STRING(_SYS_STR("Bad conversion from codepage \"{}\": \"{}\"")), codepage, m_sys_str);
|
||||||
|
iconv_close(convDesc);
|
||||||
|
}
|
||||||
|
SystemStringView sys_str() const { return m_sys_str; }
|
||||||
|
const SystemChar* c_str() const { return m_sys_str.data(); }
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline void Unlink(const SystemChar* file) {
|
static inline void Unlink(const SystemChar* file) {
|
||||||
|
|
|
@ -12,10 +12,10 @@ class DiscBase;
|
||||||
|
|
||||||
struct ExtractionContext final {
|
struct ExtractionContext final {
|
||||||
bool force : 1;
|
bool force : 1;
|
||||||
std::function<void(std::string_view, float)> progressCB;
|
std::function<void(nod::SystemStringView, float)> progressCB;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path);
|
std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path);
|
||||||
std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path, bool& isWii);
|
std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path, bool& isWii, Codepage_t codepage = CP_US_ASCII);
|
||||||
|
|
||||||
} // namespace nod
|
} // namespace nod
|
||||||
|
|
|
@ -126,25 +126,25 @@ std::unique_ptr<uint8_t[]> Node::getBuf() const {
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Node::extractToDirectory(SystemStringView basePath, const ExtractionContext& ctx) const {
|
bool Node::extractToDirectory(SystemStringView basePath, const ExtractionContext& ctx, Codepage_t codepage) const {
|
||||||
SystemStringConv nameView(getName());
|
DiscLocToSystemConv nameView(getName(), codepage);
|
||||||
SystemString path = SystemString(basePath) + _SYS_STR('/') + nameView.sys_str().data();
|
SystemString path = SystemString(basePath) + _SYS_STR('/') + nameView.sys_str().data();
|
||||||
|
|
||||||
if (m_kind == Kind::Directory) {
|
if (m_kind == Kind::Directory) {
|
||||||
++m_parent.m_curNodeIdx;
|
++m_parent.m_curNodeIdx;
|
||||||
if (ctx.progressCB && !getName().empty())
|
if (ctx.progressCB && !getName().empty())
|
||||||
ctx.progressCB(getName(), m_parent.m_curNodeIdx / float(m_parent.getNodeCount()));
|
ctx.progressCB(nameView.sys_str(), m_parent.m_curNodeIdx / float(m_parent.getNodeCount()));
|
||||||
if (Mkdir(path.c_str(), 0755) && errno != EEXIST) {
|
if (Mkdir(path.c_str(), 0755) && errno != EEXIST) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to mkdir '{}'")), path);
|
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to mkdir '{}'")), path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (Node& subnode : *this)
|
for (Node& subnode : *this)
|
||||||
if (!subnode.extractToDirectory(path, ctx))
|
if (!subnode.extractToDirectory(path, ctx, codepage))
|
||||||
return false;
|
return false;
|
||||||
} else if (m_kind == Kind::File) {
|
} else if (m_kind == Kind::File) {
|
||||||
Sstat theStat;
|
Sstat theStat;
|
||||||
if (ctx.progressCB)
|
if (ctx.progressCB)
|
||||||
ctx.progressCB(getName(), m_parent.m_curNodeIdx / float(m_parent.getNodeCount()));
|
ctx.progressCB(nameView.sys_str(), m_parent.m_curNodeIdx / float(m_parent.getNodeCount()));
|
||||||
|
|
||||||
if (ctx.force || Stat(path.c_str(), &theStat)) {
|
if (ctx.force || Stat(path.c_str(), &theStat)) {
|
||||||
std::unique_ptr<IPartReadStream> rs = beginReadStream();
|
std::unique_ptr<IPartReadStream> rs = beginReadStream();
|
||||||
|
@ -153,7 +153,7 @@ bool Node::extractToDirectory(SystemStringView basePath, const ExtractionContext
|
||||||
return false;
|
return false;
|
||||||
ws->copyFromDisc(*rs, m_discLength, [&](float prog) {
|
ws->copyFromDisc(*rs, m_discLength, [&](float prog) {
|
||||||
if (ctx.progressCB)
|
if (ctx.progressCB)
|
||||||
ctx.progressCB(getName(), (m_parent.m_curNodeIdx + prog) / float(m_parent.getNodeCount()));
|
ctx.progressCB(nameView.sys_str(), (m_parent.m_curNodeIdx + prog) / float(m_parent.getNodeCount()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
++m_parent.m_curNodeIdx;
|
++m_parent.m_curNodeIdx;
|
||||||
|
@ -194,7 +194,7 @@ bool IPartition::extractToDirectory(SystemStringView path, const ExtractionConte
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_nodes[0].extractToDirectory(fsPath, ctx);
|
return m_nodes[0].extractToDirectory(fsPath, ctx, m_codepage);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IPartition::extractSysFiles(SystemStringView basePath, const ExtractionContext& ctx) const {
|
bool IPartition::extractSysFiles(SystemStringView basePath, const ExtractionContext& ctx) const {
|
||||||
|
@ -209,7 +209,7 @@ bool IPartition::extractSysFiles(SystemStringView basePath, const ExtractionCont
|
||||||
SystemString apploaderPath = basePathStr + _SYS_STR("/sys/apploader.img");
|
SystemString apploaderPath = basePathStr + _SYS_STR("/sys/apploader.img");
|
||||||
if (ctx.force || Stat(apploaderPath.c_str(), &theStat)) {
|
if (ctx.force || Stat(apploaderPath.c_str(), &theStat)) {
|
||||||
if (ctx.progressCB)
|
if (ctx.progressCB)
|
||||||
ctx.progressCB("apploader.bin", 0.f);
|
ctx.progressCB(_SYS_STR("apploader.bin"), 0.f);
|
||||||
std::unique_ptr<uint8_t[]> buf = getApploaderBuf();
|
std::unique_ptr<uint8_t[]> buf = getApploaderBuf();
|
||||||
auto ws = NewFileIO(apploaderPath)->beginWriteStream();
|
auto ws = NewFileIO(apploaderPath)->beginWriteStream();
|
||||||
if (!ws)
|
if (!ws)
|
||||||
|
@ -221,7 +221,7 @@ bool IPartition::extractSysFiles(SystemStringView basePath, const ExtractionCont
|
||||||
SystemString dolPath = basePathStr + _SYS_STR("/sys/main.dol");
|
SystemString dolPath = basePathStr + _SYS_STR("/sys/main.dol");
|
||||||
if (ctx.force || Stat(dolPath.c_str(), &theStat)) {
|
if (ctx.force || Stat(dolPath.c_str(), &theStat)) {
|
||||||
if (ctx.progressCB)
|
if (ctx.progressCB)
|
||||||
ctx.progressCB("main.dol", 0.f);
|
ctx.progressCB(_SYS_STR("main.dol"), 0.f);
|
||||||
std::unique_ptr<uint8_t[]> buf = getDOLBuf();
|
std::unique_ptr<uint8_t[]> buf = getDOLBuf();
|
||||||
auto ws = NewFileIO(dolPath)->beginWriteStream();
|
auto ws = NewFileIO(dolPath)->beginWriteStream();
|
||||||
if (!ws)
|
if (!ws)
|
||||||
|
@ -233,7 +233,7 @@ bool IPartition::extractSysFiles(SystemStringView basePath, const ExtractionCont
|
||||||
SystemString bootPath = basePathStr + _SYS_STR("/sys/boot.bin");
|
SystemString bootPath = basePathStr + _SYS_STR("/sys/boot.bin");
|
||||||
if (ctx.force || Stat(bootPath.c_str(), &theStat)) {
|
if (ctx.force || Stat(bootPath.c_str(), &theStat)) {
|
||||||
if (ctx.progressCB)
|
if (ctx.progressCB)
|
||||||
ctx.progressCB("boot.bin", 0.f);
|
ctx.progressCB(_SYS_STR("boot.bin"), 0.f);
|
||||||
auto ws = NewFileIO(bootPath)->beginWriteStream();
|
auto ws = NewFileIO(bootPath)->beginWriteStream();
|
||||||
if (!ws)
|
if (!ws)
|
||||||
return false;
|
return false;
|
||||||
|
@ -244,7 +244,7 @@ bool IPartition::extractSysFiles(SystemStringView basePath, const ExtractionCont
|
||||||
SystemString bi2Path = basePathStr + _SYS_STR("/sys/bi2.bin");
|
SystemString bi2Path = basePathStr + _SYS_STR("/sys/bi2.bin");
|
||||||
if (ctx.force || Stat(bi2Path.c_str(), &theStat)) {
|
if (ctx.force || Stat(bi2Path.c_str(), &theStat)) {
|
||||||
if (ctx.progressCB)
|
if (ctx.progressCB)
|
||||||
ctx.progressCB("bi2.bin", 0.f);
|
ctx.progressCB(_SYS_STR("bi2.bin"), 0.f);
|
||||||
|
|
||||||
auto ws = NewFileIO(bi2Path)->beginWriteStream();
|
auto ws = NewFileIO(bi2Path)->beginWriteStream();
|
||||||
if (!ws)
|
if (!ws)
|
||||||
|
@ -406,10 +406,10 @@ void DiscBuilderBase::PartitionBuilderBase::recursiveMergeNodesPre(const Node* n
|
||||||
if (!dirIn.empty()) {
|
if (!dirIn.empty()) {
|
||||||
DirectoryEnumerator dEnum(dirIn, DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
|
DirectoryEnumerator dEnum(dirIn, DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
|
||||||
for (const DirectoryEnumerator::Entry& e : dEnum) {
|
for (const DirectoryEnumerator::Entry& e : dEnum) {
|
||||||
SystemUTF8Conv nameView(e.m_name);
|
SystemToDiscLocConv nameView(e.m_name, m_codepage);
|
||||||
|
|
||||||
if (e.m_isDir) {
|
if (e.m_isDir) {
|
||||||
auto search = dirNodes.find(nameView.utf8_str().data());
|
auto search = dirNodes.find(nameView.disc_str().data());
|
||||||
if (search != dirNodes.cend()) {
|
if (search != dirNodes.cend()) {
|
||||||
recursiveMergeNodesPre(search->second, e.m_path.c_str());
|
recursiveMergeNodesPre(search->second, e.m_path.c_str());
|
||||||
dirNodes.erase(search);
|
dirNodes.erase(search);
|
||||||
|
@ -417,7 +417,7 @@ void DiscBuilderBase::PartitionBuilderBase::recursiveMergeNodesPre(const Node* n
|
||||||
recursiveMergeNodesPre(nullptr, e.m_path.c_str());
|
recursiveMergeNodesPre(nullptr, e.m_path.c_str());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fileNodes.erase(nameView.utf8_str().data());
|
fileNodes.erase(nameView.disc_str().data());
|
||||||
++m_parent.m_progressTotal;
|
++m_parent.m_progressTotal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -452,11 +452,11 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeNodes(IPartWriteStream
|
||||||
if (!dirIn.empty()) {
|
if (!dirIn.empty()) {
|
||||||
DirectoryEnumerator dEnum(dirIn, DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
|
DirectoryEnumerator dEnum(dirIn, DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
|
||||||
for (const DirectoryEnumerator::Entry& e : dEnum) {
|
for (const DirectoryEnumerator::Entry& e : dEnum) {
|
||||||
SystemUTF8Conv nameView(e.m_name);
|
SystemToDiscLocConv nameView(e.m_name, m_codepage);
|
||||||
SystemString chKeyPath = SystemString(keyPath) + _SYS_STR('/') + e.m_name;
|
SystemString chKeyPath = SystemString(keyPath) + _SYS_STR('/') + e.m_name;
|
||||||
|
|
||||||
if (e.m_isDir) {
|
if (e.m_isDir) {
|
||||||
auto search = dirNodes.find(nameView.utf8_str().data());
|
auto search = dirNodes.find(nameView.disc_str().data());
|
||||||
if (search != dirNodes.cend()) {
|
if (search != dirNodes.cend()) {
|
||||||
if (!recursiveMergeNodes(ws, system, search->second, e.m_path.c_str(), chKeyPath))
|
if (!recursiveMergeNodes(ws, system, search->second, e.m_path.c_str(), chKeyPath))
|
||||||
return false;
|
return false;
|
||||||
|
@ -471,7 +471,7 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeNodes(IPartWriteStream
|
||||||
if (system ^ isSys)
|
if (system ^ isSys)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
fileNodes.erase(nameView.utf8_str().data());
|
fileNodes.erase(nameView.disc_str().data());
|
||||||
|
|
||||||
size_t fileSz = ROUND_UP_32(e.m_fileSz);
|
size_t fileSz = ROUND_UP_32(e.m_fileSz);
|
||||||
uint64_t fileOff = userAllocate(fileSz, ws);
|
uint64_t fileOff = userAllocate(fileSz, ws);
|
||||||
|
@ -508,7 +508,7 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeNodes(IPartWriteStream
|
||||||
|
|
||||||
/* Write-through remaining dir nodes */
|
/* Write-through remaining dir nodes */
|
||||||
for (const auto& p : dirNodes) {
|
for (const auto& p : dirNodes) {
|
||||||
SystemStringConv sysName(p.second->getName());
|
DiscLocToSystemConv sysName(p.second->getName(), m_codepage);
|
||||||
SystemString chKeyPath = SystemString(keyPath) + _SYS_STR('/') + sysName.c_str();
|
SystemString chKeyPath = SystemString(keyPath) + _SYS_STR('/') + sysName.c_str();
|
||||||
if (!recursiveMergeNodes(ws, system, p.second, {}, chKeyPath))
|
if (!recursiveMergeNodes(ws, system, p.second, {}, chKeyPath))
|
||||||
return false;
|
return false;
|
||||||
|
@ -517,7 +517,7 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeNodes(IPartWriteStream
|
||||||
/* Write-through remaining file nodes */
|
/* Write-through remaining file nodes */
|
||||||
for (const auto& p : fileNodes) {
|
for (const auto& p : fileNodes) {
|
||||||
const Node& ch = *p.second;
|
const Node& ch = *p.second;
|
||||||
SystemStringConv sysName(ch.getName());
|
DiscLocToSystemConv sysName(ch.getName(), m_codepage);
|
||||||
SystemString chKeyPath = SystemString(keyPath) + _SYS_STR('/') + sysName.c_str();
|
SystemString chKeyPath = SystemString(keyPath) + _SYS_STR('/') + sysName.c_str();
|
||||||
|
|
||||||
bool isDol;
|
bool isDol;
|
||||||
|
@ -565,7 +565,7 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeNodes(IPartWriteStream
|
||||||
|
|
||||||
bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeFST(const Node* nodeIn, SystemStringView dirIn,
|
bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeFST(const Node* nodeIn, SystemStringView dirIn,
|
||||||
std::function<void(void)> incParents,
|
std::function<void(void)> incParents,
|
||||||
SystemStringView keyPath) {
|
size_t parentDirIdx, SystemStringView keyPath) {
|
||||||
/* Build map of existing nodes to write-through later */
|
/* Build map of existing nodes to write-through later */
|
||||||
std::unordered_map<std::string, const Node*> fileNodes;
|
std::unordered_map<std::string, const Node*> fileNodes;
|
||||||
std::unordered_map<std::string, const Node*> dirNodes;
|
std::unordered_map<std::string, const Node*> dirNodes;
|
||||||
|
@ -584,23 +584,23 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeFST(const Node* nodeIn
|
||||||
if (!dirIn.empty()) {
|
if (!dirIn.empty()) {
|
||||||
DirectoryEnumerator dEnum(dirIn, DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
|
DirectoryEnumerator dEnum(dirIn, DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
|
||||||
for (const DirectoryEnumerator::Entry& e : dEnum) {
|
for (const DirectoryEnumerator::Entry& e : dEnum) {
|
||||||
SystemUTF8Conv nameView(e.m_name);
|
SystemToDiscLocConv nameView(e.m_name, m_codepage);
|
||||||
SystemString chKeyPath = SystemString(keyPath) + _SYS_STR('/') + e.m_name;
|
SystemString chKeyPath = SystemString(keyPath) + _SYS_STR('/') + e.m_name;
|
||||||
|
|
||||||
if (e.m_isDir) {
|
if (e.m_isDir) {
|
||||||
size_t dirNodeIdx = m_buildNodes.size();
|
size_t dirNodeIdx = m_buildNodes.size();
|
||||||
m_buildNodes.emplace_back(true, m_buildNameOff, 0, dirNodeIdx + 1);
|
m_buildNodes.emplace_back(true, m_buildNameOff, parentDirIdx, dirNodeIdx + 1);
|
||||||
addBuildName(e.m_name);
|
addBuildName(e.m_name);
|
||||||
incParents();
|
incParents();
|
||||||
|
|
||||||
auto search = dirNodes.find(nameView.utf8_str().data());
|
auto search = dirNodes.find(nameView.disc_str().data());
|
||||||
if (search != dirNodes.cend()) {
|
if (search != dirNodes.cend()) {
|
||||||
if (!recursiveMergeFST(search->second, e.m_path.c_str(),
|
if (!recursiveMergeFST(search->second, e.m_path.c_str(),
|
||||||
[&]() {
|
[&]() {
|
||||||
m_buildNodes[dirNodeIdx].incrementLength();
|
m_buildNodes[dirNodeIdx].incrementLength();
|
||||||
incParents();
|
incParents();
|
||||||
},
|
},
|
||||||
chKeyPath))
|
dirNodeIdx, chKeyPath))
|
||||||
return false;
|
return false;
|
||||||
dirNodes.erase(search);
|
dirNodes.erase(search);
|
||||||
} else {
|
} else {
|
||||||
|
@ -609,11 +609,11 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeFST(const Node* nodeIn
|
||||||
m_buildNodes[dirNodeIdx].incrementLength();
|
m_buildNodes[dirNodeIdx].incrementLength();
|
||||||
incParents();
|
incParents();
|
||||||
},
|
},
|
||||||
chKeyPath))
|
dirNodeIdx, chKeyPath))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fileNodes.erase(nameView.utf8_str().data());
|
fileNodes.erase(nameView.disc_str().data());
|
||||||
std::pair<uint64_t, uint64_t> fileOffSz = m_fileOffsetsSizes.at(chKeyPath);
|
std::pair<uint64_t, uint64_t> fileOffSz = m_fileOffsetsSizes.at(chKeyPath);
|
||||||
m_buildNodes.emplace_back(false, m_buildNameOff, packOffset(fileOffSz.first), fileOffSz.second);
|
m_buildNodes.emplace_back(false, m_buildNameOff, packOffset(fileOffSz.first), fileOffSz.second);
|
||||||
addBuildName(e.m_name);
|
addBuildName(e.m_name);
|
||||||
|
@ -624,11 +624,11 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeFST(const Node* nodeIn
|
||||||
|
|
||||||
/* Write-through remaining dir nodes */
|
/* Write-through remaining dir nodes */
|
||||||
for (const auto& p : dirNodes) {
|
for (const auto& p : dirNodes) {
|
||||||
SystemStringConv sysName(p.second->getName());
|
DiscLocToSystemConv sysName(p.second->getName(), m_codepage);
|
||||||
SystemString chKeyPath = SystemString(keyPath) + _SYS_STR('/') + sysName.sys_str().data();
|
SystemString chKeyPath = SystemString(keyPath) + _SYS_STR('/') + sysName.sys_str().data();
|
||||||
|
|
||||||
size_t dirNodeIdx = m_buildNodes.size();
|
size_t dirNodeIdx = m_buildNodes.size();
|
||||||
m_buildNodes.emplace_back(true, m_buildNameOff, 0, dirNodeIdx + 1);
|
m_buildNodes.emplace_back(true, m_buildNameOff, parentDirIdx, dirNodeIdx + 1);
|
||||||
addBuildName(sysName.sys_str());
|
addBuildName(sysName.sys_str());
|
||||||
incParents();
|
incParents();
|
||||||
|
|
||||||
|
@ -637,14 +637,14 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeFST(const Node* nodeIn
|
||||||
m_buildNodes[dirNodeIdx].incrementLength();
|
m_buildNodes[dirNodeIdx].incrementLength();
|
||||||
incParents();
|
incParents();
|
||||||
},
|
},
|
||||||
chKeyPath))
|
dirNodeIdx, chKeyPath))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write-through remaining file nodes */
|
/* Write-through remaining file nodes */
|
||||||
for (const auto& p : fileNodes) {
|
for (const auto& p : fileNodes) {
|
||||||
const Node& ch = *p.second;
|
const Node& ch = *p.second;
|
||||||
SystemStringConv sysName(ch.getName());
|
DiscLocToSystemConv sysName(ch.getName(), m_codepage);
|
||||||
SystemString chKeyPath = SystemString(keyPath) + _SYS_STR('/') + sysName.sys_str().data();
|
SystemString chKeyPath = SystemString(keyPath) + _SYS_STR('/') + sysName.sys_str().data();
|
||||||
|
|
||||||
std::pair<uint64_t, uint64_t> fileOffSz = m_fileOffsetsSizes.at(chKeyPath);
|
std::pair<uint64_t, uint64_t> fileOffSz = m_fileOffsetsSizes.at(chKeyPath);
|
||||||
|
@ -657,7 +657,7 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeFST(const Node* nodeIn
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DiscBuilderBase::PartitionBuilderBase::RecursiveCalculateTotalSize(uint64_t& totalSz, const Node* nodeIn,
|
bool DiscBuilderBase::PartitionBuilderBase::RecursiveCalculateTotalSize(uint64_t& totalSz, const Node* nodeIn,
|
||||||
SystemStringView dirIn) {
|
SystemStringView dirIn, Codepage_t codepage) {
|
||||||
/* Build map of existing nodes to write-through later */
|
/* Build map of existing nodes to write-through later */
|
||||||
std::unordered_map<std::string, const Node*> fileNodes;
|
std::unordered_map<std::string, const Node*> fileNodes;
|
||||||
std::unordered_map<std::string, const Node*> dirNodes;
|
std::unordered_map<std::string, const Node*> dirNodes;
|
||||||
|
@ -676,20 +676,20 @@ bool DiscBuilderBase::PartitionBuilderBase::RecursiveCalculateTotalSize(uint64_t
|
||||||
if (!dirIn.empty()) {
|
if (!dirIn.empty()) {
|
||||||
DirectoryEnumerator dEnum(dirIn, DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
|
DirectoryEnumerator dEnum(dirIn, DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
|
||||||
for (const DirectoryEnumerator::Entry& e : dEnum) {
|
for (const DirectoryEnumerator::Entry& e : dEnum) {
|
||||||
SystemUTF8Conv nameView(e.m_name);
|
SystemToDiscLocConv nameView(e.m_name, codepage);
|
||||||
|
|
||||||
if (e.m_isDir) {
|
if (e.m_isDir) {
|
||||||
auto search = dirNodes.find(nameView.utf8_str().data());
|
auto search = dirNodes.find(nameView.disc_str().data());
|
||||||
if (search != dirNodes.cend()) {
|
if (search != dirNodes.cend()) {
|
||||||
if (!RecursiveCalculateTotalSize(totalSz, search->second, e.m_path.c_str()))
|
if (!RecursiveCalculateTotalSize(totalSz, search->second, e.m_path.c_str(), codepage))
|
||||||
return false;
|
return false;
|
||||||
dirNodes.erase(search);
|
dirNodes.erase(search);
|
||||||
} else {
|
} else {
|
||||||
if (!RecursiveCalculateTotalSize(totalSz, nullptr, e.m_path.c_str()))
|
if (!RecursiveCalculateTotalSize(totalSz, nullptr, e.m_path.c_str(), codepage))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fileNodes.erase(nameView.utf8_str().data());
|
fileNodes.erase(nameView.disc_str().data());
|
||||||
totalSz += ROUND_UP_32(e.m_fileSz);
|
totalSz += ROUND_UP_32(e.m_fileSz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -697,7 +697,7 @@ bool DiscBuilderBase::PartitionBuilderBase::RecursiveCalculateTotalSize(uint64_t
|
||||||
|
|
||||||
/* Write-through remaining dir nodes */
|
/* Write-through remaining dir nodes */
|
||||||
for (const auto& p : dirNodes) {
|
for (const auto& p : dirNodes) {
|
||||||
if (!RecursiveCalculateTotalSize(totalSz, p.second, {}))
|
if (!RecursiveCalculateTotalSize(totalSz, p.second, {}, codepage))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -770,7 +770,7 @@ bool DiscBuilderBase::PartitionBuilderBase::buildFromDirectory(IPartWriteStream&
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<uint64_t> DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeBuild(SystemStringView dirIn,
|
std::optional<uint64_t> DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeBuild(SystemStringView dirIn,
|
||||||
PartitionKind kind, bool isWii) {
|
PartitionKind kind, bool isWii, Codepage_t codepage) {
|
||||||
SystemString dirStr(dirIn);
|
SystemString dirStr(dirIn);
|
||||||
SystemString basePath = isWii ? dirStr + _SYS_STR("/") + getKindString(kind) : dirStr;
|
SystemString basePath = isWii ? dirStr + _SYS_STR("/") + getKindString(kind) : dirStr;
|
||||||
SystemString dolIn = basePath + _SYS_STR("/sys/main.dol");
|
SystemString dolIn = basePath + _SYS_STR("/sys/main.dol");
|
||||||
|
@ -782,7 +782,7 @@ std::optional<uint64_t> DiscBuilderBase::PartitionBuilderBase::CalculateTotalSiz
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
uint64_t totalSz = ROUND_UP_32(dolStat.st_size);
|
uint64_t totalSz = ROUND_UP_32(dolStat.st_size);
|
||||||
if (!RecursiveCalculateTotalSize(totalSz, nullptr, filesIn.c_str()))
|
if (!RecursiveCalculateTotalSize(totalSz, nullptr, filesIn.c_str(), codepage))
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
return totalSz;
|
return totalSz;
|
||||||
}
|
}
|
||||||
|
@ -837,20 +837,20 @@ bool DiscBuilderBase::PartitionBuilderBase::mergeFromDirectory(IPartWriteStream&
|
||||||
return false;
|
return false;
|
||||||
if (!recursiveMergeNodes(ws, false, &partIn->getFSTRoot(), filesIn.c_str(), keyPath))
|
if (!recursiveMergeNodes(ws, false, &partIn->getFSTRoot(), filesIn.c_str(), keyPath))
|
||||||
return false;
|
return false;
|
||||||
if (!recursiveMergeFST(&partIn->getFSTRoot(), filesIn.c_str(), [&]() { m_buildNodes[0].incrementLength(); }, keyPath))
|
if (!recursiveMergeFST(&partIn->getFSTRoot(), filesIn.c_str(), [&]() { m_buildNodes[0].incrementLength(); }, 0, keyPath))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<uint64_t> DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeMerge(const IPartition* partIn,
|
std::optional<uint64_t> DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeMerge(const IPartition* partIn,
|
||||||
SystemStringView dirIn) {
|
SystemStringView dirIn, Codepage_t codepage) {
|
||||||
SystemString dirStr(dirIn);
|
SystemString dirStr(dirIn);
|
||||||
SystemString basePath = partIn->isWii() ? dirStr + _SYS_STR("/") + getKindString(partIn->getKind()) : dirStr;
|
SystemString basePath = partIn->isWii() ? dirStr + _SYS_STR("/") + getKindString(partIn->getKind()) : dirStr;
|
||||||
SystemString filesIn = basePath + _SYS_STR("/files");
|
SystemString filesIn = basePath + _SYS_STR("/files");
|
||||||
|
|
||||||
uint64_t totalSz = ROUND_UP_32(partIn->getDOLSize());
|
uint64_t totalSz = ROUND_UP_32(partIn->getDOLSize());
|
||||||
if (!RecursiveCalculateTotalSize(totalSz, &partIn->getFSTRoot(), filesIn.c_str()))
|
if (!RecursiveCalculateTotalSize(totalSz, &partIn->getFSTRoot(), filesIn.c_str(), codepage))
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
return totalSz;
|
return totalSz;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,8 @@ namespace nod {
|
||||||
|
|
||||||
class PartitionGCN : public IPartition {
|
class PartitionGCN : public IPartition {
|
||||||
public:
|
public:
|
||||||
PartitionGCN(const DiscGCN& parent, uint64_t offset, bool& err)
|
PartitionGCN(const DiscGCN& parent, uint64_t offset, bool& err, Codepage_t codepage)
|
||||||
: IPartition(parent, PartitionKind::Data, false, offset) {
|
: IPartition(parent, PartitionKind::Data, false, offset, codepage) {
|
||||||
/* GCN-specific header reads */
|
/* GCN-specific header reads */
|
||||||
std::unique_ptr<IPartReadStream> s = beginReadStream(0x0);
|
std::unique_ptr<IPartReadStream> s = beginReadStream(0x0);
|
||||||
if (!s) {
|
if (!s) {
|
||||||
|
@ -118,16 +118,16 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
DiscGCN::DiscGCN(std::unique_ptr<IDiscIO>&& dio, bool& err) : DiscBase(std::move(dio), err) {
|
DiscGCN::DiscGCN(std::unique_ptr<IDiscIO>&& dio, bool& err, Codepage_t codepage) : DiscBase(std::move(dio), err) {
|
||||||
if (err)
|
if (err)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* One lone partition for GCN */
|
/* One lone partition for GCN */
|
||||||
m_partitions.emplace_back(std::make_unique<PartitionGCN>(*this, 0, err));
|
m_partitions.emplace_back(std::make_unique<PartitionGCN>(*this, 0, err, codepage));
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscBuilderGCN DiscGCN::makeMergeBuilder(SystemStringView outPath, FProgress progressCB) {
|
DiscBuilderGCN DiscGCN::makeMergeBuilder(SystemStringView outPath, FProgress progressCB, Codepage_t codepage) {
|
||||||
return DiscBuilderGCN(outPath, progressCB);
|
return DiscBuilderGCN(outPath, progressCB, codepage);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DiscGCN::extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const { return true; }
|
bool DiscGCN::extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const { return true; }
|
||||||
|
@ -161,8 +161,8 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PartitionBuilderGCN(DiscBuilderBase& parent)
|
PartitionBuilderGCN(DiscBuilderBase& parent, Codepage_t codepage)
|
||||||
: DiscBuilderBase::PartitionBuilderBase(parent, PartitionKind::Data, false) {}
|
: DiscBuilderBase::PartitionBuilderBase(parent, PartitionKind::Data, false, codepage) {}
|
||||||
|
|
||||||
uint64_t userAllocate(uint64_t reqSz, IPartWriteStream& ws) override {
|
uint64_t userAllocate(uint64_t reqSz, IPartWriteStream& ws) override {
|
||||||
m_curUser -= reqSz;
|
m_curUser -= reqSz;
|
||||||
|
@ -372,8 +372,8 @@ EBuildResult DiscBuilderGCN::buildFromDirectory(SystemStringView dirIn) {
|
||||||
return pb.buildFromDirectory(dirIn) ? EBuildResult::Success : EBuildResult::Failed;
|
return pb.buildFromDirectory(dirIn) ? EBuildResult::Success : EBuildResult::Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<uint64_t> DiscBuilderGCN::CalculateTotalSizeRequired(SystemStringView dirIn) {
|
std::optional<uint64_t> DiscBuilderGCN::CalculateTotalSizeRequired(SystemStringView dirIn, Codepage_t codepage) {
|
||||||
std::optional<uint64_t> sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeBuild(dirIn, PartitionKind::Data, false);
|
std::optional<uint64_t> sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeBuild(dirIn, PartitionKind::Data, false, codepage);
|
||||||
if (!sz)
|
if (!sz)
|
||||||
return sz;
|
return sz;
|
||||||
*sz += 0x30000;
|
*sz += 0x30000;
|
||||||
|
@ -384,13 +384,13 @@ std::optional<uint64_t> DiscBuilderGCN::CalculateTotalSizeRequired(SystemStringV
|
||||||
return sz;
|
return sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscBuilderGCN::DiscBuilderGCN(SystemStringView outPath, FProgress progressCB)
|
DiscBuilderGCN::DiscBuilderGCN(SystemStringView outPath, FProgress progressCB, Codepage_t codepage)
|
||||||
: DiscBuilderBase(outPath, 0x57058000, progressCB) {
|
: DiscBuilderBase(outPath, 0x57058000, progressCB) {
|
||||||
m_partitions.emplace_back(std::make_unique<PartitionBuilderGCN>(*this));
|
m_partitions.emplace_back(std::make_unique<PartitionBuilderGCN>(*this, codepage));
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscMergerGCN::DiscMergerGCN(SystemStringView outPath, DiscGCN& sourceDisc, FProgress progressCB)
|
DiscMergerGCN::DiscMergerGCN(SystemStringView outPath, DiscGCN& sourceDisc, FProgress progressCB, Codepage_t codepage)
|
||||||
: m_sourceDisc(sourceDisc), m_builder(sourceDisc.makeMergeBuilder(outPath, progressCB)) {}
|
: m_sourceDisc(sourceDisc), m_builder(sourceDisc.makeMergeBuilder(outPath, progressCB, codepage)) {}
|
||||||
|
|
||||||
EBuildResult DiscMergerGCN::mergeFromDirectory(SystemStringView dirIn) {
|
EBuildResult DiscMergerGCN::mergeFromDirectory(SystemStringView dirIn) {
|
||||||
if (!m_builder.getFileIO().beginWriteStream())
|
if (!m_builder.getFileIO().beginWriteStream())
|
||||||
|
@ -416,8 +416,8 @@ EBuildResult DiscMergerGCN::mergeFromDirectory(SystemStringView dirIn) {
|
||||||
: EBuildResult::Failed;
|
: EBuildResult::Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<uint64_t> DiscMergerGCN::CalculateTotalSizeRequired(DiscGCN& sourceDisc, SystemStringView dirIn) {
|
std::optional<uint64_t> DiscMergerGCN::CalculateTotalSizeRequired(DiscGCN& sourceDisc, SystemStringView dirIn, Codepage_t codepage) {
|
||||||
std::optional<uint64_t> sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeMerge(sourceDisc.getDataPartition(), dirIn);
|
std::optional<uint64_t> sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeMerge(sourceDisc.getDataPartition(), dirIn, codepage);
|
||||||
if (!sz)
|
if (!sz)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
*sz += 0x30000;
|
*sz += 0x30000;
|
||||||
|
|
|
@ -241,8 +241,8 @@ class PartitionWii : public IPartition {
|
||||||
uint8_t m_decKey[16];
|
uint8_t m_decKey[16];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PartitionWii(const DiscWii& parent, PartitionKind kind, uint64_t offset, bool& err)
|
PartitionWii(const DiscWii& parent, PartitionKind kind, uint64_t offset, bool& err, Codepage_t codepage)
|
||||||
: IPartition(parent, kind, true, offset) {
|
: IPartition(parent, kind, true, offset, codepage) {
|
||||||
std::unique_ptr<IReadStream> s = parent.getDiscIO().beginReadStream(offset);
|
std::unique_ptr<IReadStream> s = parent.getDiscIO().beginReadStream(offset);
|
||||||
if (!s) {
|
if (!s) {
|
||||||
err = true;
|
err = true;
|
||||||
|
@ -447,7 +447,7 @@ public:
|
||||||
SystemString ticketPath = basePathStr + _SYS_STR("/ticket.bin");
|
SystemString ticketPath = basePathStr + _SYS_STR("/ticket.bin");
|
||||||
if (ctx.force || Stat(ticketPath.c_str(), &theStat)) {
|
if (ctx.force || Stat(ticketPath.c_str(), &theStat)) {
|
||||||
if (ctx.progressCB)
|
if (ctx.progressCB)
|
||||||
ctx.progressCB("ticket.bin", 0.f);
|
ctx.progressCB(_SYS_STR("ticket.bin"), 0.f);
|
||||||
auto ws = NewFileIO(ticketPath)->beginWriteStream();
|
auto ws = NewFileIO(ticketPath)->beginWriteStream();
|
||||||
if (!ws)
|
if (!ws)
|
||||||
return false;
|
return false;
|
||||||
|
@ -458,7 +458,7 @@ public:
|
||||||
SystemString tmdPath = basePathStr + _SYS_STR("/tmd.bin");
|
SystemString tmdPath = basePathStr + _SYS_STR("/tmd.bin");
|
||||||
if (ctx.force || Stat(tmdPath.c_str(), &theStat)) {
|
if (ctx.force || Stat(tmdPath.c_str(), &theStat)) {
|
||||||
if (ctx.progressCB)
|
if (ctx.progressCB)
|
||||||
ctx.progressCB("tmd.bin", 0.f);
|
ctx.progressCB(_SYS_STR("tmd.bin"), 0.f);
|
||||||
auto ws = NewFileIO(tmdPath)->beginWriteStream();
|
auto ws = NewFileIO(tmdPath)->beginWriteStream();
|
||||||
if (!ws)
|
if (!ws)
|
||||||
return false;
|
return false;
|
||||||
|
@ -469,7 +469,7 @@ public:
|
||||||
SystemString certPath = basePathStr + _SYS_STR("/cert.bin");
|
SystemString certPath = basePathStr + _SYS_STR("/cert.bin");
|
||||||
if (ctx.force || Stat(certPath.c_str(), &theStat)) {
|
if (ctx.force || Stat(certPath.c_str(), &theStat)) {
|
||||||
if (ctx.progressCB)
|
if (ctx.progressCB)
|
||||||
ctx.progressCB("cert.bin", 0.f);
|
ctx.progressCB(_SYS_STR("cert.bin"), 0.f);
|
||||||
auto ws = NewFileIO(certPath)->beginWriteStream();
|
auto ws = NewFileIO(certPath)->beginWriteStream();
|
||||||
if (!ws)
|
if (!ws)
|
||||||
return false;
|
return false;
|
||||||
|
@ -482,7 +482,7 @@ public:
|
||||||
SystemString h3Path = basePathStr + _SYS_STR("/h3.bin");
|
SystemString h3Path = basePathStr + _SYS_STR("/h3.bin");
|
||||||
if (ctx.force || Stat(h3Path.c_str(), &theStat)) {
|
if (ctx.force || Stat(h3Path.c_str(), &theStat)) {
|
||||||
if (ctx.progressCB)
|
if (ctx.progressCB)
|
||||||
ctx.progressCB("h3.bin", 0.f);
|
ctx.progressCB(_SYS_STR("h3.bin"), 0.f);
|
||||||
auto ws = NewFileIO(h3Path)->beginWriteStream();
|
auto ws = NewFileIO(h3Path)->beginWriteStream();
|
||||||
if (!ws)
|
if (!ws)
|
||||||
return false;
|
return false;
|
||||||
|
@ -493,7 +493,7 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
DiscWii::DiscWii(std::unique_ptr<IDiscIO>&& dio, bool& err) : DiscBase(std::move(dio), err) {
|
DiscWii::DiscWii(std::unique_ptr<IDiscIO>&& dio, bool& err, Codepage_t codepage) : DiscBase(std::move(dio), err) {
|
||||||
if (err)
|
if (err)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -543,14 +543,14 @@ DiscWii::DiscWii(std::unique_ptr<IDiscIO>&& dio, bool& err) : DiscBase(std::move
|
||||||
err = true;
|
err = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_partitions.emplace_back(std::make_unique<PartitionWii>(*this, kind, part.partDataOff << 2, err));
|
m_partitions.emplace_back(std::make_unique<PartitionWii>(*this, kind, part.partDataOff << 2, err, codepage));
|
||||||
if (err)
|
if (err)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscBuilderWii DiscWii::makeMergeBuilder(SystemStringView outPath, bool dualLayer, FProgress progressCB) {
|
DiscBuilderWii DiscWii::makeMergeBuilder(SystemStringView outPath, bool dualLayer, FProgress progressCB, Codepage_t codepage) {
|
||||||
return DiscBuilderWii(outPath, dualLayer, progressCB);
|
return DiscBuilderWii(outPath, dualLayer, progressCB, codepage);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DiscWii::extractDiscHeaderFiles(SystemStringView basePath, const ExtractionContext& ctx) const {
|
bool DiscWii::extractDiscHeaderFiles(SystemStringView basePath, const ExtractionContext& ctx) const {
|
||||||
|
@ -567,7 +567,7 @@ bool DiscWii::extractDiscHeaderFiles(SystemStringView basePath, const Extraction
|
||||||
SystemString headerPath = basePathStr + _SYS_STR("/disc/header.bin");
|
SystemString headerPath = basePathStr + _SYS_STR("/disc/header.bin");
|
||||||
if (ctx.force || Stat(headerPath.c_str(), &theStat)) {
|
if (ctx.force || Stat(headerPath.c_str(), &theStat)) {
|
||||||
if (ctx.progressCB)
|
if (ctx.progressCB)
|
||||||
ctx.progressCB("header.bin", 0.f);
|
ctx.progressCB(_SYS_STR("header.bin"), 0.f);
|
||||||
std::unique_ptr<IReadStream> rs = getDiscIO().beginReadStream(0x0);
|
std::unique_ptr<IReadStream> rs = getDiscIO().beginReadStream(0x0);
|
||||||
if (!rs)
|
if (!rs)
|
||||||
return false;
|
return false;
|
||||||
|
@ -583,7 +583,7 @@ bool DiscWii::extractDiscHeaderFiles(SystemStringView basePath, const Extraction
|
||||||
SystemString regionPath = basePathStr + _SYS_STR("/disc/region.bin");
|
SystemString regionPath = basePathStr + _SYS_STR("/disc/region.bin");
|
||||||
if (ctx.force || Stat(regionPath.c_str(), &theStat)) {
|
if (ctx.force || Stat(regionPath.c_str(), &theStat)) {
|
||||||
if (ctx.progressCB)
|
if (ctx.progressCB)
|
||||||
ctx.progressCB("header.bin", 0.f);
|
ctx.progressCB(_SYS_STR("header.bin"), 0.f);
|
||||||
std::unique_ptr<IReadStream> rs = getDiscIO().beginReadStream(0x4E000);
|
std::unique_ptr<IReadStream> rs = getDiscIO().beginReadStream(0x4E000);
|
||||||
if (!rs)
|
if (!rs)
|
||||||
return false;
|
return false;
|
||||||
|
@ -746,8 +746,8 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PartitionBuilderWii(DiscBuilderBase& parent, PartitionKind kind, uint64_t baseOffset)
|
PartitionBuilderWii(DiscBuilderBase& parent, PartitionKind kind, uint64_t baseOffset, Codepage_t codepage)
|
||||||
: DiscBuilderBase::PartitionBuilderBase(parent, kind, true), m_baseOffset(baseOffset), m_aes(NewAES()) {}
|
: DiscBuilderBase::PartitionBuilderBase(parent, kind, true, codepage), m_baseOffset(baseOffset), m_aes(NewAES()) {}
|
||||||
|
|
||||||
uint64_t getCurUserEnd() const { return m_curUser; }
|
uint64_t getCurUserEnd() const { return m_curUser; }
|
||||||
|
|
||||||
|
@ -1235,8 +1235,8 @@ EBuildResult DiscBuilderWii::buildFromDirectory(SystemStringView dirIn) {
|
||||||
return EBuildResult::Success;
|
return EBuildResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<uint64_t> DiscBuilderWii::CalculateTotalSizeRequired(SystemStringView dirIn, bool& dualLayer) {
|
std::optional<uint64_t> DiscBuilderWii::CalculateTotalSizeRequired(SystemStringView dirIn, bool& dualLayer, Codepage_t codepage) {
|
||||||
std::optional<uint64_t> sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeBuild(dirIn, PartitionKind::Data, true);
|
std::optional<uint64_t> sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeBuild(dirIn, PartitionKind::Data, true, codepage);
|
||||||
if (!sz)
|
if (!sz)
|
||||||
return sz;
|
return sz;
|
||||||
auto szDiv = nod::div(*sz, uint64_t(0x1F0000));
|
auto szDiv = nod::div(*sz, uint64_t(0x1F0000));
|
||||||
|
@ -1252,13 +1252,13 @@ std::optional<uint64_t> DiscBuilderWii::CalculateTotalSizeRequired(SystemStringV
|
||||||
return sz;
|
return sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscBuilderWii::DiscBuilderWii(SystemStringView outPath, bool dualLayer, FProgress progressCB)
|
DiscBuilderWii::DiscBuilderWii(SystemStringView outPath, bool dualLayer, FProgress progressCB, Codepage_t codepage)
|
||||||
: DiscBuilderBase(outPath, dualLayer ? 0x1FB4E0000 : 0x118240000, progressCB) {
|
: DiscBuilderBase(outPath, dualLayer ? 0x1FB4E0000 : 0x118240000, progressCB) {
|
||||||
m_partitions.emplace_back(std::make_unique<PartitionBuilderWii>(*this, PartitionKind::Data, 0x200000));
|
m_partitions.emplace_back(std::make_unique<PartitionBuilderWii>(*this, PartitionKind::Data, 0x200000, codepage));
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscMergerWii::DiscMergerWii(SystemStringView outPath, DiscWii& sourceDisc, bool dualLayer, FProgress progressCB)
|
DiscMergerWii::DiscMergerWii(SystemStringView outPath, DiscWii& sourceDisc, bool dualLayer, FProgress progressCB, Codepage_t codepage)
|
||||||
: m_sourceDisc(sourceDisc), m_builder(sourceDisc.makeMergeBuilder(outPath, dualLayer, progressCB)) {}
|
: m_sourceDisc(sourceDisc), m_builder(sourceDisc.makeMergeBuilder(outPath, dualLayer, progressCB, codepage)) {}
|
||||||
|
|
||||||
EBuildResult DiscMergerWii::mergeFromDirectory(SystemStringView dirIn) {
|
EBuildResult DiscMergerWii::mergeFromDirectory(SystemStringView dirIn) {
|
||||||
PartitionBuilderWii& pb = static_cast<PartitionBuilderWii&>(*m_builder.m_partitions[0]);
|
PartitionBuilderWii& pb = static_cast<PartitionBuilderWii&>(*m_builder.m_partitions[0]);
|
||||||
|
@ -1342,8 +1342,8 @@ EBuildResult DiscMergerWii::mergeFromDirectory(SystemStringView dirIn) {
|
||||||
return EBuildResult::Success;
|
return EBuildResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<uint64_t> DiscMergerWii::CalculateTotalSizeRequired(DiscWii& sourceDisc, SystemStringView dirIn, bool& dualLayer) {
|
std::optional<uint64_t> DiscMergerWii::CalculateTotalSizeRequired(DiscWii& sourceDisc, SystemStringView dirIn, bool& dualLayer, Codepage_t codepage) {
|
||||||
std::optional<uint64_t> sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeMerge(sourceDisc.getDataPartition(), dirIn);
|
std::optional<uint64_t> sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeMerge(sourceDisc.getDataPartition(), dirIn, codepage);
|
||||||
if (!sz)
|
if (!sz)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
auto szDiv = nod::div(*sz, uint64_t(0x1F0000));
|
auto szDiv = nod::div(*sz, uint64_t(0x1F0000));
|
||||||
|
|
|
@ -14,7 +14,7 @@ std::unique_ptr<IDiscIO> NewDiscIOISO(SystemStringView path);
|
||||||
std::unique_ptr<IDiscIO> NewDiscIOWBFS(SystemStringView path);
|
std::unique_ptr<IDiscIO> NewDiscIOWBFS(SystemStringView path);
|
||||||
std::unique_ptr<IDiscIO> NewDiscIONFS(SystemStringView path);
|
std::unique_ptr<IDiscIO> NewDiscIONFS(SystemStringView path);
|
||||||
|
|
||||||
std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path, bool& isWii) {
|
std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path, bool& isWii, Codepage_t codepage) {
|
||||||
/* Temporary file handle to determine image type */
|
/* Temporary file handle to determine image type */
|
||||||
std::unique_ptr<IFileIO> fio = NewFileIO(path);
|
std::unique_ptr<IFileIO> fio = NewFileIO(path);
|
||||||
if (!fio->exists()) {
|
if (!fio->exists()) {
|
||||||
|
@ -67,13 +67,13 @@ std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path, bool& isWii)
|
||||||
bool err = false;
|
bool err = false;
|
||||||
std::unique_ptr<DiscBase> ret;
|
std::unique_ptr<DiscBase> ret;
|
||||||
if (isWii) {
|
if (isWii) {
|
||||||
ret = std::make_unique<DiscWii>(std::move(discIO), err);
|
ret = std::make_unique<DiscWii>(std::move(discIO), err, codepage);
|
||||||
if (err)
|
if (err)
|
||||||
return {};
|
return {};
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = std::make_unique<DiscGCN>(std::move(discIO), err);
|
ret = std::make_unique<DiscGCN>(std::move(discIO), err, codepage);
|
||||||
if (err)
|
if (err)
|
||||||
return {};
|
return {};
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -81,7 +81,7 @@ std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path, bool& isWii)
|
||||||
|
|
||||||
std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path) {
|
std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path) {
|
||||||
bool isWii;
|
bool isWii;
|
||||||
return OpenDiscFromImage(path, isWii);
|
return OpenDiscFromImage(path, isWii, CP_US_ASCII);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace nod
|
} // namespace nod
|
||||||
|
|
Loading…
Reference in New Issue