mirror of https://github.com/AxioDL/nod.git
Use UTF-8 exclusively internally; replace iconv with OSUTF
Filenames are now unconditionally encoded/decoded as Shift-JIS, which provides a reasonable fallback to 7-bit ASCII.
This commit is contained in:
parent
a525f60775
commit
c1635245b8
|
@ -4,3 +4,7 @@ version.h
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.autosave
|
*.autosave
|
||||||
docs/*
|
docs/*
|
||||||
|
.idea/
|
||||||
|
cmake-build-*
|
||||||
|
build/
|
||||||
|
out/
|
|
@ -9,7 +9,7 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||||
_SCL_SECURE_NO_DEPRECATE=1 _CRT_NONSTDC_NO_WARNINGS=1
|
_SCL_SECURE_NO_DEPRECATE=1 _CRT_NONSTDC_NO_WARNINGS=1
|
||||||
_ENABLE_EXTENDED_ALIGNED_STORAGE=1 NOMINMAX=1)
|
_ENABLE_EXTENDED_ALIGNED_STORAGE=1 NOMINMAX=1)
|
||||||
add_compile_options(/IGNORE:4221 /wd4018 /wd4800 /wd4005 /wd4311 /wd4068
|
add_compile_options(/IGNORE:4221 /wd4018 /wd4800 /wd4005 /wd4311 /wd4068
|
||||||
/wd4267 /wd4244 /wd4200 /wd4305 /wd4067 /wd4146 /wd4309 /wd4805 ${VS_OPTIONS})
|
/wd4267 /wd4244 /wd4200 /wd4305 /wd4067 /wd4146 /wd4309 /wd4805 /utf-8 ${VS_OPTIONS})
|
||||||
|
|
||||||
add_compile_options(
|
add_compile_options(
|
||||||
# Disable exceptions
|
# Disable exceptions
|
||||||
|
|
|
@ -34,7 +34,7 @@ a content pipeline using the `nod::DiscBuilderBase` interface.
|
||||||
```cpp
|
```cpp
|
||||||
/* Sample logging lambda for progress feedback */
|
/* Sample logging lambda for progress feedback */
|
||||||
size_t lastIdx = -1;
|
size_t lastIdx = -1;
|
||||||
auto progFunc = [&](size_t idx, const nod::SystemString& name, size_t bytes)
|
auto progFunc = [&](size_t idx, const std::string& name, size_t bytes)
|
||||||
{
|
{
|
||||||
if (idx != lastIdx)
|
if (idx != lastIdx)
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,9 +3,11 @@ add_executable(nodtool main.cpp)
|
||||||
target_link_libraries(nodtool nod logvisor)
|
target_link_libraries(nodtool nod logvisor)
|
||||||
if (NOT WIN32)
|
if (NOT WIN32)
|
||||||
target_link_libraries(nodtool pthread)
|
target_link_libraries(nodtool pthread)
|
||||||
if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||||
target_link_libraries(nodtool execinfo)
|
target_link_libraries(nodtool execinfo)
|
||||||
else()
|
else ()
|
||||||
target_link_libraries(nodtool dl)
|
target_link_libraries(nodtool dl)
|
||||||
endif()
|
endif ()
|
||||||
endif()
|
else ()
|
||||||
|
target_sources(nodtool PRIVATE app.manifest)
|
||||||
|
endif ()
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<assemblyIdentity type="win32" name="..." version="6.0.0.0"/>
|
||||||
|
<application>
|
||||||
|
<windowsSettings>
|
||||||
|
<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
|
||||||
|
</windowsSettings>
|
||||||
|
</application>
|
||||||
|
</assembly>
|
163
driver/main.cpp
163
driver/main.cpp
|
@ -15,16 +15,8 @@
|
||||||
#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(_SYS_STR(
|
fmt::print(stderr, FMT_STRING(
|
||||||
"Usage:\n"
|
"Usage:\n"
|
||||||
" nodtool extract [options] <image-in> [<dir-out>]\n"
|
" nodtool extract [options] <image-in> [<dir-out>]\n"
|
||||||
" nodtool makegcn [options] <fsroot-in> [<image-out>]\n"
|
" nodtool makegcn [options] <fsroot-in> [<image-out>]\n"
|
||||||
|
@ -33,65 +25,40 @@ static void printHelp() {
|
||||||
" nodtool mergewii [options] <fsroot-in> <image-in> [<image-out>]\n"
|
" nodtool mergewii [options] <fsroot-in> <image-in> [<image-out>]\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
" -f Force (extract only)\n"
|
" -f Force (extract only)\n"
|
||||||
" -v Verbose details (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 _MSC_VER
|
||||||
#ifdef strcasecmp
|
#include <nowide/args.hpp>
|
||||||
#undef strcasecmp
|
|
||||||
#endif
|
|
||||||
#define strcasecmp _wcsicmp
|
|
||||||
#define PRISize "Iu"
|
#define PRISize "Iu"
|
||||||
int wmain(int argc, wchar_t* argv[])
|
int main(int argc, char* argv[]) {
|
||||||
|
nowide::args _(argc, argv);
|
||||||
#else
|
#else
|
||||||
#define PRISize "zu"
|
#define PRISize "zu"
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[]) {
|
||||||
#endif
|
#endif
|
||||||
{
|
|
||||||
/* 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;
|
int argidx = 1;
|
||||||
nod::SystemString errand;
|
std::string errand;
|
||||||
bool verbose = false;
|
bool verbose = false;
|
||||||
nod::Codepage_t discLocale = CP_US_ASCII;
|
nod::ExtractionContext ctx = {true, [&](std::string_view str, float c) {
|
||||||
nod::ExtractionContext ctx = {true, [&](nod::SystemStringView str, float c) {
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
fmt::print(stderr, FMT_STRING(_SYS_STR("Current node: {}, Extraction {:g}% Complete\n")),
|
fmt::print(stderr, FMT_STRING("Current node: {}, Extraction {:g}% Complete\n"),
|
||||||
str, c * 100.f);
|
str, c * 100.f);
|
||||||
}};
|
}};
|
||||||
while (argidx < argc) {
|
while (argidx < argc) {
|
||||||
if (!strcasecmp(argv[argidx], _SYS_STR("-f"))) {
|
if (!nod::StrCaseCmp(argv[argidx], "-f")) {
|
||||||
ctx.force = true;
|
ctx.force = true;
|
||||||
++argidx;
|
++argidx;
|
||||||
continue;
|
continue;
|
||||||
} else if (!strcasecmp(argv[argidx], _SYS_STR("-v"))) {
|
} else if (!nod::StrCaseCmp(argv[argidx], "-v")) {
|
||||||
verbose = true;
|
verbose = true;
|
||||||
++argidx;
|
++argidx;
|
||||||
continue;
|
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()) {
|
} else if (errand.empty()) {
|
||||||
errand = argv[argidx];
|
errand = argv[argidx];
|
||||||
++argidx;
|
++argidx;
|
||||||
|
@ -106,18 +73,18 @@ int main(int argc, char* argv[])
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto progFunc = [&](float prog, nod::SystemStringView name, size_t bytes) {
|
auto progFunc = [&](float prog, std::string_view name, size_t bytes) {
|
||||||
fmt::print(FMT_STRING(_SYS_STR("\r ")));
|
fmt::print(FMT_STRING("\r "));
|
||||||
if (bytes != SIZE_MAX)
|
if (bytes != SIZE_MAX)
|
||||||
fmt::print(FMT_STRING(_SYS_STR("\r{:g}% {} {} B")), prog * 100.f, name, bytes);
|
fmt::print(FMT_STRING("\r{:g}% {} {} B"), prog * 100.f, name, bytes);
|
||||||
else
|
else
|
||||||
fmt::print(FMT_STRING(_SYS_STR("\r{:g}% {}")), prog * 100.f, name);
|
fmt::print(FMT_STRING("\r{:g}% {}"), prog * 100.f, name);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (errand == _SYS_STR("extract")) {
|
if (errand == "extract") {
|
||||||
nod::SystemString imageIn;
|
std::string imageIn;
|
||||||
nod::SystemString dirOut;
|
std::string dirOut;
|
||||||
while (argidx < argc) {
|
while (argidx < argc) {
|
||||||
if (imageIn.empty()) {
|
if (imageIn.empty()) {
|
||||||
imageIn = argv[argidx];
|
imageIn = argv[argidx];
|
||||||
|
@ -133,10 +100,10 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dirOut.empty())
|
if (dirOut.empty())
|
||||||
dirOut = _SYS_STR(".");
|
dirOut = ".";
|
||||||
|
|
||||||
bool isWii;
|
bool isWii;
|
||||||
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(imageIn, isWii, discLocale);
|
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(imageIn, isWii);
|
||||||
if (!disc)
|
if (!disc)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
@ -148,9 +115,9 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
if (!dataPart->extractToDirectory(dirOut, ctx))
|
if (!dataPart->extractToDirectory(dirOut, ctx))
|
||||||
return 1;
|
return 1;
|
||||||
} else if (errand == _SYS_STR("makegcn")) {
|
} else if (errand == "makegcn") {
|
||||||
nod::SystemString fsrootIn;
|
std::string fsrootIn;
|
||||||
nod::SystemString imageOut;
|
std::string imageOut;
|
||||||
while (argidx < argc) {
|
while (argidx < argc) {
|
||||||
if (fsrootIn.empty()) {
|
if (fsrootIn.empty()) {
|
||||||
fsrootIn = argv[argidx];
|
fsrootIn = argv[argidx];
|
||||||
|
@ -166,29 +133,29 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (imageOut.empty())
|
if (imageOut.empty())
|
||||||
imageOut = fsrootIn + _SYS_STR(".gcm");
|
imageOut = fsrootIn + ".gcm";
|
||||||
|
|
||||||
/* Pre-validate path */
|
/* Pre-validate path */
|
||||||
nod::Sstat theStat;
|
nod::Sstat theStat;
|
||||||
if (nod::Stat(fsrootIn.c_str(), &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")), fsrootIn);
|
nod::LogModule.report(logvisor::Error, FMT_STRING("unable to stat {} as directory"), fsrootIn);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nod::DiscBuilderGCN::CalculateTotalSizeRequired(fsrootIn, discLocale))
|
if (!nod::DiscBuilderGCN::CalculateTotalSizeRequired(fsrootIn))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
nod::EBuildResult ret;
|
nod::EBuildResult ret;
|
||||||
|
|
||||||
nod::DiscBuilderGCN b(imageOut, progFunc, discLocale);
|
nod::DiscBuilderGCN b(imageOut, progFunc);
|
||||||
ret = b.buildFromDirectory(fsrootIn);
|
ret = b.buildFromDirectory(fsrootIn);
|
||||||
|
|
||||||
fmt::print(FMT_STRING(_SYS_STR("\n")));
|
fmt::print(FMT_STRING("\n"));
|
||||||
if (ret != nod::EBuildResult::Success)
|
if (ret != nod::EBuildResult::Success)
|
||||||
return 1;
|
return 1;
|
||||||
} else if (errand == _SYS_STR("makewii")) {
|
} else if (errand == "makewii") {
|
||||||
nod::SystemString fsrootIn;
|
std::string fsrootIn;
|
||||||
nod::SystemString imageOut;
|
std::string imageOut;
|
||||||
while (argidx < argc) {
|
while (argidx < argc) {
|
||||||
if (fsrootIn.empty()) {
|
if (fsrootIn.empty()) {
|
||||||
fsrootIn = argv[argidx];
|
fsrootIn = argv[argidx];
|
||||||
|
@ -204,31 +171,31 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (imageOut.empty())
|
if (imageOut.empty())
|
||||||
imageOut = fsrootIn + _SYS_STR(".iso");
|
imageOut = fsrootIn + ".iso";
|
||||||
|
|
||||||
/* Pre-validate path */
|
/* Pre-validate path */
|
||||||
nod::Sstat theStat;
|
nod::Sstat theStat;
|
||||||
if (nod::Stat(fsrootIn.c_str(), &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")), fsrootIn);
|
nod::LogModule.report(logvisor::Error, FMT_STRING("unable to stat {} as directory"), fsrootIn);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dual = false;
|
bool dual = false;
|
||||||
if (!nod::DiscBuilderWii::CalculateTotalSizeRequired(fsrootIn, dual, discLocale))
|
if (!nod::DiscBuilderWii::CalculateTotalSizeRequired(fsrootIn, dual))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
nod::EBuildResult ret;
|
nod::EBuildResult ret;
|
||||||
|
|
||||||
nod::DiscBuilderWii b(imageOut, dual, progFunc, discLocale);
|
nod::DiscBuilderWii b(imageOut, dual, progFunc);
|
||||||
ret = b.buildFromDirectory(fsrootIn);
|
ret = b.buildFromDirectory(fsrootIn);
|
||||||
|
|
||||||
fmt::print(FMT_STRING(_SYS_STR("\n")));
|
fmt::print(FMT_STRING("\n"));
|
||||||
if (ret != nod::EBuildResult::Success)
|
if (ret != nod::EBuildResult::Success)
|
||||||
return 1;
|
return 1;
|
||||||
} else if (errand == _SYS_STR("mergegcn")) {
|
} else if (errand == "mergegcn") {
|
||||||
nod::SystemString fsrootIn;
|
std::string fsrootIn;
|
||||||
nod::SystemString imageIn;
|
std::string imageIn;
|
||||||
nod::SystemString imageOut;
|
std::string imageOut;
|
||||||
while (argidx < argc) {
|
while (argidx < argc) {
|
||||||
if (fsrootIn.empty()) {
|
if (fsrootIn.empty()) {
|
||||||
fsrootIn = argv[argidx];
|
fsrootIn = argv[argidx];
|
||||||
|
@ -248,45 +215,45 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (imageOut.empty())
|
if (imageOut.empty())
|
||||||
imageOut = fsrootIn + _SYS_STR(".gcm");
|
imageOut = fsrootIn + ".gcm";
|
||||||
|
|
||||||
/* Pre-validate paths */
|
/* Pre-validate paths */
|
||||||
nod::Sstat theStat;
|
nod::Sstat theStat;
|
||||||
if (nod::Stat(fsrootIn.c_str(), &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")), fsrootIn);
|
nod::LogModule.report(logvisor::Error, FMT_STRING("unable to stat {} as directory"), fsrootIn);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (nod::Stat(imageIn.c_str(), &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")), imageIn);
|
nod::LogModule.report(logvisor::Error, FMT_STRING("unable to stat {} as file"), imageIn);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isWii;
|
bool isWii;
|
||||||
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(imageIn, isWii, discLocale);
|
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(imageIn, isWii);
|
||||||
if (!disc) {
|
if (!disc) {
|
||||||
nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to open image {}")), imageIn);
|
nod::LogModule.report(logvisor::Error, FMT_STRING("unable to open image {}"), imageIn);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (isWii) {
|
if (isWii) {
|
||||||
nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("Wii images should be merged with 'mergewii'")));
|
nod::LogModule.report(logvisor::Error, FMT_STRING("Wii images should be merged with 'mergewii'"));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nod::DiscMergerGCN::CalculateTotalSizeRequired(static_cast<nod::DiscGCN&>(*disc), fsrootIn, discLocale))
|
if (!nod::DiscMergerGCN::CalculateTotalSizeRequired(static_cast<nod::DiscGCN&>(*disc), fsrootIn))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
nod::EBuildResult ret;
|
nod::EBuildResult ret;
|
||||||
|
|
||||||
nod::DiscMergerGCN b(imageOut, static_cast<nod::DiscGCN&>(*disc), progFunc, discLocale);
|
nod::DiscMergerGCN b(imageOut, static_cast<nod::DiscGCN&>(*disc), progFunc);
|
||||||
ret = b.mergeFromDirectory(fsrootIn);
|
ret = b.mergeFromDirectory(fsrootIn);
|
||||||
|
|
||||||
fmt::print(FMT_STRING(_SYS_STR("\n")));
|
fmt::print(FMT_STRING("\n"));
|
||||||
if (ret != nod::EBuildResult::Success)
|
if (ret != nod::EBuildResult::Success)
|
||||||
return 1;
|
return 1;
|
||||||
} else if (errand == _SYS_STR("mergewii")) {
|
} else if (errand == "mergewii") {
|
||||||
nod::SystemString fsrootIn;
|
std::string fsrootIn;
|
||||||
nod::SystemString imageIn;
|
std::string imageIn;
|
||||||
nod::SystemString imageOut;
|
std::string imageOut;
|
||||||
while (argidx < argc) {
|
while (argidx < argc) {
|
||||||
if (fsrootIn.empty()) {
|
if (fsrootIn.empty()) {
|
||||||
fsrootIn = argv[argidx];
|
fsrootIn = argv[argidx];
|
||||||
|
@ -306,40 +273,40 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (imageOut.empty())
|
if (imageOut.empty())
|
||||||
imageOut = fsrootIn + _SYS_STR(".iso");
|
imageOut = fsrootIn + ".iso";
|
||||||
|
|
||||||
/* Pre-validate paths */
|
/* Pre-validate paths */
|
||||||
nod::Sstat theStat;
|
nod::Sstat theStat;
|
||||||
if (nod::Stat(fsrootIn.c_str(), &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")), fsrootIn);
|
nod::LogModule.report(logvisor::Error, FMT_STRING("unable to stat {} as directory"), fsrootIn);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (nod::Stat(imageIn.c_str(), &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")), imageIn);
|
nod::LogModule.report(logvisor::Error, FMT_STRING("unable to stat {} as file"), imageIn);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isWii;
|
bool isWii;
|
||||||
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(imageIn, isWii, discLocale);
|
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(imageIn, isWii);
|
||||||
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("unable to open image {}"), argv[3]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (!isWii) {
|
if (!isWii) {
|
||||||
nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("GameCube images should be merged with 'mergegcn'")));
|
nod::LogModule.report(logvisor::Error, FMT_STRING("GameCube images should be merged with 'mergegcn'"));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dual = false;
|
bool dual = false;
|
||||||
if (!nod::DiscMergerWii::CalculateTotalSizeRequired(static_cast<nod::DiscWii&>(*disc), fsrootIn, dual, discLocale))
|
if (!nod::DiscMergerWii::CalculateTotalSizeRequired(static_cast<nod::DiscWii&>(*disc), fsrootIn, dual))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
nod::EBuildResult ret;
|
nod::EBuildResult ret;
|
||||||
|
|
||||||
nod::DiscMergerWii b(imageOut, static_cast<nod::DiscWii&>(*disc), dual, progFunc, discLocale);
|
nod::DiscMergerWii b(imageOut, static_cast<nod::DiscWii&>(*disc), dual, progFunc);
|
||||||
ret = b.mergeFromDirectory(fsrootIn);
|
ret = b.mergeFromDirectory(fsrootIn);
|
||||||
|
|
||||||
fmt::print(FMT_STRING(_SYS_STR("\n")));
|
fmt::print(FMT_STRING("\n"));
|
||||||
if (ret != nod::EBuildResult::Success)
|
if (ret != nod::EBuildResult::Success)
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -347,6 +314,6 @@ int main(int argc, char* argv[])
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
nod::LogModule.report(logvisor::Info, FMT_STRING(_SYS_STR("Success!")));
|
nod::LogModule.report(logvisor::Info, FMT_STRING("Success!"));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,46 +9,44 @@
|
||||||
|
|
||||||
namespace nod {
|
namespace nod {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Case-insensitive comparator for std::map sorting
|
||||||
|
*/
|
||||||
struct CaseInsensitiveCompare {
|
struct CaseInsensitiveCompare {
|
||||||
|
// Allow heterogeneous lookup with maps that use this comparator.
|
||||||
|
using is_transparent = void;
|
||||||
|
|
||||||
bool operator()(std::string_view lhs, std::string_view rhs) const {
|
bool operator()(std::string_view lhs, std::string_view rhs) const {
|
||||||
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](char lhs, char rhs) {
|
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](char lhs, char rhs) {
|
||||||
return std::tolower(static_cast<unsigned char>(lhs)) < std::tolower(static_cast<unsigned char>(rhs));
|
return std::tolower(static_cast<unsigned char>(lhs)) < std::tolower(static_cast<unsigned char>(rhs));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#if _WIN32
|
|
||||||
bool operator()(std::wstring_view lhs, std::wstring_view rhs) const {
|
|
||||||
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](wchar_t lhs, wchar_t rhs) {
|
|
||||||
return std::towlower(lhs) < std::towlower(rhs);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DirectoryEnumerator {
|
class DirectoryEnumerator {
|
||||||
public:
|
public:
|
||||||
enum class Mode { Native, DirsSorted, FilesSorted, DirsThenFilesSorted };
|
enum class Mode { Native, DirsSorted, FilesSorted, DirsThenFilesSorted };
|
||||||
struct Entry {
|
struct Entry {
|
||||||
SystemString m_path;
|
std::string m_path;
|
||||||
SystemString m_name;
|
std::string m_name;
|
||||||
size_t m_fileSz;
|
size_t m_fileSz;
|
||||||
bool m_isDir;
|
bool m_isDir;
|
||||||
|
|
||||||
Entry(const SystemString& path, const SystemChar* name, size_t sz, bool isDir)
|
Entry(std::string path, std::string name, size_t sz, bool isDir)
|
||||||
: m_path(path), m_name(name), m_fileSz(sz), m_isDir(isDir) {}
|
: m_path(std::move(path)), m_name(std::move(name)), m_fileSz(sz), m_isDir(isDir) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Entry> m_entries;
|
std::vector<Entry> m_entries;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DirectoryEnumerator(SystemStringView path, Mode mode = Mode::DirsThenFilesSorted, bool sizeSort = false,
|
DirectoryEnumerator(std::string_view path, Mode mode = Mode::DirsThenFilesSorted, bool sizeSort = false,
|
||||||
bool reverse = false, bool noHidden = false);
|
bool reverse = false, bool noHidden = false);
|
||||||
|
|
||||||
operator bool() const { return m_entries.size() != 0; }
|
explicit operator bool() const { return !m_entries.empty(); }
|
||||||
size_t size() const { return m_entries.size(); }
|
[[nodiscard]] size_t size() const { return m_entries.size(); }
|
||||||
std::vector<Entry>::const_iterator begin() const { return m_entries.cbegin(); }
|
[[nodiscard]] std::vector<Entry>::const_iterator begin() const { return m_entries.cbegin(); }
|
||||||
std::vector<Entry>::const_iterator end() const { return m_entries.cend(); }
|
[[nodiscard]] std::vector<Entry>::const_iterator end() const { return m_entries.cend(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace nod
|
} // namespace nod
|
||||||
|
|
|
@ -12,16 +12,17 @@
|
||||||
|
|
||||||
#include "nod/IDiscIO.hpp"
|
#include "nod/IDiscIO.hpp"
|
||||||
#include "nod/IFileIO.hpp"
|
#include "nod/IFileIO.hpp"
|
||||||
|
#include "nod/OSUTF.h"
|
||||||
#include "nod/Util.hpp"
|
#include "nod/Util.hpp"
|
||||||
|
|
||||||
namespace nod {
|
namespace nod {
|
||||||
|
|
||||||
using FProgress = std::function<void(float totalProg, SystemStringView fileName, size_t fileBytesXfered)>;
|
using FProgress = std::function<void(float totalProg, std::string_view 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);
|
const char* getKindString(PartitionKind kind);
|
||||||
|
|
||||||
class FSTNode {
|
class FSTNode {
|
||||||
uint32_t typeAndNameOffset;
|
uint32_t typeAndNameOffset;
|
||||||
|
@ -236,7 +237,7 @@ public:
|
||||||
return end();
|
return end();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool extractToDirectory(SystemStringView basePath, const ExtractionContext& ctx, Codepage_t codepage = CP_US_ASCII) const;
|
bool extractToDirectory(std::string_view basePath, const ExtractionContext& ctx) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IPartition {
|
class IPartition {
|
||||||
|
@ -275,7 +276,6 @@ 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;
|
||||||
|
@ -290,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, Codepage_t codepage)
|
IPartition(const DiscBase& parent, PartitionKind kind, bool isWii, uint64_t offset)
|
||||||
: m_parent(parent), m_kind(kind), m_offset(offset), m_isWii(isWii), m_codepage(codepage) {}
|
: m_parent(parent), m_kind(kind), m_offset(offset), m_isWii(isWii) {}
|
||||||
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; }
|
||||||
|
@ -308,7 +308,7 @@ public:
|
||||||
}
|
}
|
||||||
const Node& getFSTRoot() const { return m_nodes[0]; }
|
const Node& getFSTRoot() const { return m_nodes[0]; }
|
||||||
Node& getFSTRoot() { return m_nodes[0]; }
|
Node& getFSTRoot() { return m_nodes[0]; }
|
||||||
bool extractToDirectory(SystemStringView path, const ExtractionContext& ctx);
|
bool extractToDirectory(std::string_view path, const ExtractionContext& ctx);
|
||||||
|
|
||||||
uint64_t getDOLSize() const { return m_dolSz; }
|
uint64_t getDOLSize() const { return m_dolSz; }
|
||||||
std::unique_ptr<uint8_t[]> getDOLBuf() const {
|
std::unique_ptr<uint8_t[]> getDOLBuf() const {
|
||||||
|
@ -334,8 +334,8 @@ public:
|
||||||
size_t getNodeCount() const { return m_nodes.size(); }
|
size_t getNodeCount() const { return m_nodes.size(); }
|
||||||
const Header& getHeader() const { return m_header; }
|
const Header& getHeader() const { return m_header; }
|
||||||
const BI2Header& getBI2() const { return m_bi2Header; }
|
const BI2Header& getBI2() const { return m_bi2Header; }
|
||||||
virtual bool extractCryptoFiles(SystemStringView path, const ExtractionContext& ctx) const { return true; }
|
virtual bool extractCryptoFiles(std::string_view path, const ExtractionContext& ctx) const { return true; }
|
||||||
bool extractSysFiles(SystemStringView path, const ExtractionContext& ctx) const;
|
bool extractSysFiles(std::string_view path, const ExtractionContext& ctx) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DiscBase {
|
class DiscBase {
|
||||||
|
@ -373,12 +373,12 @@ public:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void extractToDirectory(SystemStringView path, const ExtractionContext& ctx) {
|
void extractToDirectory(std::string_view path, const ExtractionContext& ctx) {
|
||||||
for (std::unique_ptr<IPartition>& part : m_partitions)
|
for (std::unique_ptr<IPartition>& part : m_partitions)
|
||||||
part->extractToDirectory(path, ctx);
|
part->extractToDirectory(path, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const = 0;
|
virtual bool extractDiscHeaderFiles(std::string_view path, const ExtractionContext& ctx) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DiscBuilderBase {
|
class DiscBuilderBase {
|
||||||
|
@ -390,30 +390,30 @@ public:
|
||||||
virtual ~PartitionBuilderBase() = default;
|
virtual ~PartitionBuilderBase() = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unordered_map<SystemString, std::pair<uint64_t, uint64_t>> m_fileOffsetsSizes;
|
std::unordered_map<std::string, std::pair<uint64_t, uint64_t>> m_fileOffsetsSizes;
|
||||||
std::vector<FSTNode> m_buildNodes;
|
std::vector<FSTNode> m_buildNodes;
|
||||||
std::vector<std::string> m_buildNames;
|
std::vector<std::string> m_buildNames;
|
||||||
size_t m_buildNameOff = 0;
|
size_t m_buildNameOff = 0;
|
||||||
virtual uint64_t userAllocate(uint64_t reqSz, IPartWriteStream& ws) = 0;
|
virtual uint64_t userAllocate(uint64_t reqSz, IPartWriteStream& ws) = 0;
|
||||||
virtual uint32_t packOffset(uint64_t offset) const = 0;
|
virtual uint32_t packOffset(uint64_t offset) const = 0;
|
||||||
|
|
||||||
void recursiveBuildNodesPre(SystemStringView dirIn);
|
void recursiveBuildNodesPre(std::string_view dirIn);
|
||||||
bool recursiveBuildNodes(IPartWriteStream& ws, bool system, SystemStringView dirIn);
|
bool recursiveBuildNodes(IPartWriteStream& ws, bool system, std::string_view dirIn);
|
||||||
|
|
||||||
bool recursiveBuildFST(SystemStringView dirIn, std::function<void(void)> incParents, size_t parentDirIdx);
|
bool recursiveBuildFST(std::string_view dirIn, std::function<void(void)> incParents, size_t parentDirIdx);
|
||||||
|
|
||||||
void recursiveMergeNodesPre(const Node* nodeIn, SystemStringView dirIn);
|
void recursiveMergeNodesPre(const Node* nodeIn, std::string_view dirIn);
|
||||||
bool recursiveMergeNodes(IPartWriteStream& ws, bool system, const Node* nodeIn, SystemStringView dirIn,
|
bool recursiveMergeNodes(IPartWriteStream& ws, bool system, const Node* nodeIn, std::string_view dirIn,
|
||||||
SystemStringView keyPath);
|
std::string_view keyPath);
|
||||||
bool recursiveMergeFST(const Node* nodeIn, SystemStringView dirIn, std::function<void(void)> incParents,
|
bool recursiveMergeFST(const Node* nodeIn, std::string_view dirIn, std::function<void(void)> incParents,
|
||||||
size_t parentDirIdx, SystemStringView keyPath);
|
size_t parentDirIdx, std::string_view keyPath);
|
||||||
|
|
||||||
static bool RecursiveCalculateTotalSize(uint64_t& totalSz, const Node* nodeIn, SystemStringView dirIn, Codepage_t codepage);
|
static bool RecursiveCalculateTotalSize(uint64_t& totalSz, const Node* nodeIn, std::string_view dirIn);
|
||||||
|
|
||||||
void addBuildName(SystemStringView str) {
|
void addBuildName(std::string_view str) {
|
||||||
SystemToDiscLocConv nameView(str, m_codepage);
|
UTF8ToSJIS nameView(str);
|
||||||
m_buildNames.emplace_back(nameView.disc_str());
|
m_buildNames.emplace_back(nameView.str());
|
||||||
m_buildNameOff += nameView.disc_str().size() + 1;
|
m_buildNameOff += nameView.str().size() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscBuilderBase& m_parent;
|
DiscBuilderBase& m_parent;
|
||||||
|
@ -421,20 +421,19 @@ 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, Codepage_t codepage)
|
PartitionBuilderBase(DiscBuilderBase& parent, PartitionKind kind, bool isWii)
|
||||||
: m_parent(parent), m_kind(kind), m_isWii(isWii), m_codepage(codepage) {}
|
: m_parent(parent), m_kind(kind), m_isWii(isWii) {}
|
||||||
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, std::string_view dirIn);
|
||||||
static std::optional<uint64_t> CalculateTotalSizeBuild(SystemStringView dirIn, PartitionKind kind, bool isWii, Codepage_t codepage);
|
static std::optional<uint64_t> CalculateTotalSizeBuild(std::string_view dirIn, PartitionKind kind, bool isWii);
|
||||||
bool mergeFromDirectory(IPartWriteStream& ws, const IPartition* partIn, SystemStringView dirIn);
|
bool mergeFromDirectory(IPartWriteStream& ws, const IPartition* partIn, std::string_view dirIn);
|
||||||
static std::optional<uint64_t> CalculateTotalSizeMerge(const IPartition* partIn, SystemStringView dirIn, Codepage_t codepage);
|
static std::optional<uint64_t> CalculateTotalSizeMerge(const IPartition* partIn, std::string_view dirIn);
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SystemString m_outPath;
|
std::string m_outPath;
|
||||||
std::unique_ptr<IFileIO> m_fileIO;
|
std::unique_ptr<IFileIO> m_fileIO;
|
||||||
std::vector<std::unique_ptr<PartitionBuilderBase>> m_partitions;
|
std::vector<std::unique_ptr<PartitionBuilderBase>> m_partitions;
|
||||||
int64_t m_discCapacity;
|
int64_t m_discCapacity;
|
||||||
|
@ -457,7 +456,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~DiscBuilderBase() = default;
|
virtual ~DiscBuilderBase() = default;
|
||||||
DiscBuilderBase(SystemStringView outPath, int64_t discCapacity, FProgress progressCB)
|
DiscBuilderBase(std::string_view outPath, int64_t discCapacity, FProgress progressCB)
|
||||||
: m_outPath(outPath)
|
: m_outPath(outPath)
|
||||||
, m_fileIO(NewFileIO(outPath, discCapacity))
|
, m_fileIO(NewFileIO(outPath, discCapacity))
|
||||||
, m_discCapacity(discCapacity)
|
, m_discCapacity(discCapacity)
|
||||||
|
|
|
@ -7,20 +7,20 @@ class DiscBuilderGCN;
|
||||||
|
|
||||||
class DiscGCN : public DiscBase {
|
class DiscGCN : public DiscBase {
|
||||||
friend class DiscMergerGCN;
|
friend class DiscMergerGCN;
|
||||||
DiscBuilderGCN makeMergeBuilder(SystemStringView outPath, FProgress progressCB, Codepage_t codepage);
|
DiscBuilderGCN makeMergeBuilder(std::string_view outPath, FProgress progressCB);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DiscGCN(std::unique_ptr<IDiscIO>&& dio, bool& err, Codepage_t codepage = CP_US_ASCII);
|
DiscGCN(std::unique_ptr<IDiscIO>&& dio, bool& err);
|
||||||
bool extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const override;
|
bool extractDiscHeaderFiles(std::string_view path, const ExtractionContext& ctx) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DiscBuilderGCN : public DiscBuilderBase {
|
class DiscBuilderGCN : public DiscBuilderBase {
|
||||||
friend class DiscMergerGCN;
|
friend class DiscMergerGCN;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DiscBuilderGCN(SystemStringView outPath, FProgress progressCB, Codepage_t codepage = CP_US_ASCII);
|
DiscBuilderGCN(std::string_view outPath, FProgress progressCB);
|
||||||
EBuildResult buildFromDirectory(SystemStringView dirIn);
|
EBuildResult buildFromDirectory(std::string_view dirIn);
|
||||||
static std::optional<uint64_t> CalculateTotalSizeRequired(SystemStringView dirIn, Codepage_t codepage = CP_US_ASCII);
|
static std::optional<uint64_t> CalculateTotalSizeRequired(std::string_view dirIn);
|
||||||
};
|
};
|
||||||
|
|
||||||
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, Codepage_t codepage = CP_US_ASCII);
|
DiscMergerGCN(std::string_view outPath, DiscGCN& sourceDisc, FProgress progressCB);
|
||||||
EBuildResult mergeFromDirectory(SystemStringView dirIn);
|
EBuildResult mergeFromDirectory(std::string_view dirIn);
|
||||||
static std::optional<uint64_t> CalculateTotalSizeRequired(DiscGCN& sourceDisc, SystemStringView dirIn, Codepage_t codepage = CP_US_ASCII);
|
static std::optional<uint64_t> CalculateTotalSizeRequired(DiscGCN& sourceDisc, std::string_view dirIn);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // 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, Codepage_t codepage = CP_US_ASCII);
|
DiscWii(std::unique_ptr<IDiscIO>&& dio, bool& err);
|
||||||
DiscBuilderWii makeMergeBuilder(SystemStringView outPath, bool dualLayer, FProgress progressCB, Codepage_t codepage);
|
DiscBuilderWii makeMergeBuilder(std::string_view outPath, bool dualLayer, FProgress progressCB);
|
||||||
bool extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const override;
|
bool extractDiscHeaderFiles(std::string_view path, const ExtractionContext& ctx) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DiscBuilderWii : public DiscBuilderBase {
|
class DiscBuilderWii : public DiscBuilderBase {
|
||||||
public:
|
public:
|
||||||
DiscBuilderWii(SystemStringView outPath, bool dualLayer, FProgress progressCB, Codepage_t codepage = CP_US_ASCII);
|
DiscBuilderWii(std::string_view outPath, bool dualLayer, FProgress progressCB);
|
||||||
EBuildResult buildFromDirectory(SystemStringView dirIn);
|
EBuildResult buildFromDirectory(std::string_view dirIn);
|
||||||
static std::optional<uint64_t> CalculateTotalSizeRequired(SystemStringView dirIn, bool& dualLayer, Codepage_t codepage = CP_US_ASCII);
|
static std::optional<uint64_t> CalculateTotalSizeRequired(std::string_view dirIn, bool& dualLayer);
|
||||||
};
|
};
|
||||||
|
|
||||||
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, Codepage_t codepage = CP_US_ASCII);
|
DiscMergerWii(std::string_view outPath, DiscWii& sourceDisc, bool dualLayer, FProgress progressCB);
|
||||||
EBuildResult mergeFromDirectory(SystemStringView dirIn);
|
EBuildResult mergeFromDirectory(std::string_view dirIn);
|
||||||
static std::optional<uint64_t> CalculateTotalSizeRequired(DiscWii& sourceDisc, SystemStringView dirIn, bool& dualLayer, Codepage_t codepage = CP_US_ASCII);
|
static std::optional<uint64_t> CalculateTotalSizeRequired(DiscWii& sourceDisc, std::string_view dirIn, bool& dualLayer);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace nod
|
} // namespace nod
|
||||||
|
|
|
@ -69,6 +69,6 @@ public:
|
||||||
virtual std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const = 0;
|
virtual std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<IFileIO> NewFileIO(SystemStringView path, int64_t maxWriteSize = -1);
|
std::unique_ptr<IFileIO> NewFileIO(std::string_view path, int64_t maxWriteSize = -1);
|
||||||
|
|
||||||
} // namespace nod
|
} // namespace nod
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#define OS_CONSTEXPR constexpr
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define OS_CONSTEXPR
|
||||||
|
typedef uint8_t char8_t;
|
||||||
|
typedef uint16_t char16_t;
|
||||||
|
typedef uint32_t char32_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
OS_CONSTEXPR inline bool IsSjisLeadByte(char8_t c) { return (c > 0x80 && c < 0xa0) || (c > 0xdf && c < 0xfd); }
|
||||||
|
|
||||||
|
OS_CONSTEXPR inline bool IsSjisTrailByte(char8_t c) { return c > 0x3f && c < 0xfd && c != 0x7f; }
|
||||||
|
|
||||||
|
char32_t OSSJISToUTF32(char16_t sjis);
|
||||||
|
|
||||||
|
char16_t OSUTF32ToSJIS(char32_t utf32);
|
||||||
|
|
||||||
|
char8_t OSUTF32ToAnsi(char32_t utf32);
|
||||||
|
|
||||||
|
char16_t* OSUTF32To16(char32_t utf32, char16_t* utf16);
|
||||||
|
|
||||||
|
char8_t* OSUTF32To8(char32_t utf32, char8_t* utf8);
|
||||||
|
|
||||||
|
const char16_t* OSUTF16To32(const char16_t* utf16, char32_t* utf32);
|
||||||
|
|
||||||
|
const char8_t* OSUTF8To32(const char8_t* utf8, char32_t* utf32);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
|
||||||
|
class SJISToUTF8 {
|
||||||
|
private:
|
||||||
|
std::string out;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SJISToUTF8(std::string_view sv) {
|
||||||
|
const auto* in = reinterpret_cast<const char8_t*>(sv.data());
|
||||||
|
const auto* end = in + sv.size();
|
||||||
|
std::array<char8_t, 4> u8arr{};
|
||||||
|
while (in < end) {
|
||||||
|
if (IsSjisLeadByte(*in)) {
|
||||||
|
char16_t sjis = static_cast<char16_t>(*in) << 8 | *(in + 1);
|
||||||
|
in += 2;
|
||||||
|
char32_t utf32 = OSSJISToUTF32(sjis);
|
||||||
|
if (utf32 == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
char8_t* u8out = u8arr.data();
|
||||||
|
char8_t* u8end = OSUTF32To8(utf32, u8out);
|
||||||
|
if (u8end == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto length = static_cast<size_t>(u8end - u8out);
|
||||||
|
out.append(std::string_view{reinterpret_cast<char*>(u8out), length});
|
||||||
|
} else {
|
||||||
|
out.push_back(static_cast<char>(*in++));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const std::string& str() const { return out; }
|
||||||
|
|
||||||
|
[[nodiscard]] std::string& str() { return out; }
|
||||||
|
|
||||||
|
[[nodiscard]] const char* c_str() const { return out.c_str(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class UTF8ToSJIS {
|
||||||
|
private:
|
||||||
|
std::string out;
|
||||||
|
|
||||||
|
public:
|
||||||
|
UTF8ToSJIS(std::string_view sv) {
|
||||||
|
const auto* in = reinterpret_cast<const char8_t*>(sv.data());
|
||||||
|
const auto* end = in + sv.size();
|
||||||
|
while (in < end) {
|
||||||
|
char32_t utf32 = 0;
|
||||||
|
const char8_t* next = OSUTF8To32(in, &utf32);
|
||||||
|
if (next == nullptr) {
|
||||||
|
utf32 = *in;
|
||||||
|
in++;
|
||||||
|
} else {
|
||||||
|
in = next;
|
||||||
|
}
|
||||||
|
char16_t sjis = OSUTF32ToSJIS(utf32);
|
||||||
|
char8_t lead = (sjis >> 8) & 0xFF;
|
||||||
|
if (IsSjisLeadByte(lead)) {
|
||||||
|
out.push_back(static_cast<char>(lead));
|
||||||
|
}
|
||||||
|
out.push_back(static_cast<char>(sjis & 0xFF));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const std::string& str() const { return out; }
|
||||||
|
|
||||||
|
[[nodiscard]] std::string& str() { return out; }
|
||||||
|
|
||||||
|
[[nodiscard]] const char* c_str() const { return out.c_str(); }
|
||||||
|
};
|
||||||
|
#endif
|
|
@ -9,6 +9,7 @@
|
||||||
#ifndef NOMINMAX
|
#ifndef NOMINMAX
|
||||||
#define NOMINMAX
|
#define NOMINMAX
|
||||||
#endif
|
#endif
|
||||||
|
#include <nowide/stackstring.hpp>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#if defined(WINAPI_FAMILY) && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP
|
#if defined(WINAPI_FAMILY) && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP
|
||||||
#define WINDOWS_STORE 1
|
#define WINDOWS_STORE 1
|
||||||
|
@ -18,7 +19,6 @@
|
||||||
#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>
|
||||||
|
@ -66,7 +66,9 @@ constexpr T max(T a, T b) {
|
||||||
/* template-based div for flexible typing and avoiding a library call */
|
/* template-based div for flexible typing and avoiding a library call */
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr auto div(T a, T b) {
|
constexpr auto div(T a, T b) {
|
||||||
struct DivTp { T quot, rem; };
|
struct DivTp {
|
||||||
|
T quot, rem;
|
||||||
|
};
|
||||||
return DivTp{a / b, a % b};
|
return DivTp{a / b, a % b};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,198 +76,27 @@ constexpr auto div(T a, T b) {
|
||||||
extern logvisor::Module LogModule;
|
extern logvisor::Module LogModule;
|
||||||
|
|
||||||
/* filesystem char type */
|
/* filesystem char type */
|
||||||
#if _WIN32 && UNICODE
|
#if _WIN32
|
||||||
#define NOD_UCS2 1
|
static inline int Mkdir(const char* path, int) {
|
||||||
typedef struct _stat64 Sstat;
|
const nowide::wstackstring str(path);
|
||||||
static inline int Mkdir(const wchar_t* path, int) { return _wmkdir(path); }
|
return _wmkdir(str.get());
|
||||||
static inline int Stat(const wchar_t* path, Sstat* statout) { return _wstati64(path, statout); }
|
}
|
||||||
|
|
||||||
|
using Sstat = struct ::_stat64;
|
||||||
|
static inline int Stat(const char* path, Sstat* statout) {
|
||||||
|
const nowide::wstackstring wpath(path);
|
||||||
|
return _wstat64(wpath.get(), statout);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
|
static inline int Mkdir(const char* path, mode_t mode) { return CreateDirectoryA(path, mode); }
|
||||||
|
|
||||||
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 Stat(const char* path, Sstat* statout) { return stat(path, statout); }
|
static inline int Stat(const char* path, Sstat* statout) { return stat(path, statout); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* String-converting views */
|
static inline int StrCaseCmp(const char* str1, const char* str2) {
|
||||||
#if NOD_UCS2
|
#ifdef _MSC_VER
|
||||||
#define CP_US_ASCII 20127
|
return _stricmp(str1, str2);
|
||||||
#define CP_SHIFT_JIS 932
|
|
||||||
#define CP_GB_18030 54936
|
|
||||||
#ifndef _SYS_STR
|
|
||||||
#define _SYS_STR(val) L##val
|
|
||||||
#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
|
|
||||||
#define CP_US_ASCII "US-ASCII"
|
|
||||||
#define CP_UTF8 "UTF-8"
|
|
||||||
#define CP_SHIFT_JIS "SHIFT-JIS"
|
|
||||||
#ifndef _SYS_STR
|
|
||||||
#define _SYS_STR(val) val
|
|
||||||
#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
|
|
||||||
|
|
||||||
static inline void Unlink(const SystemChar* file) {
|
|
||||||
#if NOD_UCS2
|
|
||||||
_wunlink(file);
|
|
||||||
#else
|
|
||||||
unlink(file);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int StrCmp(const SystemChar* str1, const SystemChar* str2) {
|
|
||||||
#if NOD_UCS2
|
|
||||||
return wcscmp(str1, str2);
|
|
||||||
#else
|
|
||||||
return strcmp(str1, str2);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int StrCaseCmp(const SystemChar* str1, const SystemChar* str2) {
|
|
||||||
#if NOD_UCS2
|
|
||||||
return _wcsicmp(str1, str2);
|
|
||||||
#else
|
#else
|
||||||
return strcasecmp(str1, str2);
|
return strcasecmp(str1, str2);
|
||||||
#endif
|
#endif
|
||||||
|
@ -349,9 +180,11 @@ static inline uint64_t SBig(uint64_t val) { return val; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum class FileLockType { None = 0, Read, Write };
|
enum class FileLockType { None = 0, Read, Write };
|
||||||
static inline FILE* Fopen(const SystemChar* path, const SystemChar* mode, FileLockType lock = FileLockType::None) {
|
static inline FILE* Fopen(const char* path, const char* mode, FileLockType lock = FileLockType::None) {
|
||||||
#if NOD_UCS2
|
#if _MSC_VER
|
||||||
FILE* fp = _wfopen(path, mode);
|
const nowide::wstackstring wpath(path);
|
||||||
|
const nowide::wshort_stackstring wmode(mode);
|
||||||
|
FILE* fp = _wfopen(wpath.get(), wmode.get());
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
#else
|
#else
|
||||||
|
@ -394,20 +227,22 @@ static inline int64_t FTell(FILE* fp) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool CheckFreeSpace(const SystemChar* path, size_t reqSz) {
|
static inline bool CheckFreeSpace(const char* path, size_t reqSz) {
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
ULARGE_INTEGER freeBytes;
|
ULARGE_INTEGER freeBytes;
|
||||||
wchar_t buf[1024];
|
const nowide::wstackstring wpath(path);
|
||||||
wchar_t* end;
|
std::array<wchar_t, 1024> buf{};
|
||||||
DWORD ret = GetFullPathNameW(path, 1024, buf, &end);
|
wchar_t* end = nullptr;
|
||||||
if (!ret || ret > 1024) {
|
DWORD ret = GetFullPathNameW(wpath.get(), 1024, buf.data(), &end);
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("GetFullPathNameW {}")), path);
|
if (ret == 0 || ret > 1024) {
|
||||||
|
LogModule.report(logvisor::Error, FMT_STRING("GetFullPathNameA {}"), path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (end)
|
if (end != nullptr) {
|
||||||
end[0] = L'\0';
|
end[0] = L'\0';
|
||||||
if (!GetDiskFreeSpaceExW(buf, &freeBytes, nullptr, nullptr)) {
|
}
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("GetDiskFreeSpaceExW {}: {}")), path, GetLastError());
|
if (!GetDiskFreeSpaceExW(buf.data(), &freeBytes, nullptr, nullptr)) {
|
||||||
|
LogModule.report(logvisor::Error, FMT_STRING("GetDiskFreeSpaceExA {}: {}"), path, GetLastError());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return reqSz < freeBytes.QuadPart;
|
return reqSz < freeBytes.QuadPart;
|
||||||
|
|
|
@ -12,10 +12,10 @@ class DiscBase;
|
||||||
|
|
||||||
struct ExtractionContext final {
|
struct ExtractionContext final {
|
||||||
bool force : 1;
|
bool force : 1;
|
||||||
std::function<void(nod::SystemStringView, float)> progressCB;
|
std::function<void(std::string_view, float)> progressCB;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path);
|
std::unique_ptr<DiscBase> OpenDiscFromImage(std::string_view path);
|
||||||
std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path, bool& isWii, Codepage_t codepage = CP_US_ASCII);
|
std::unique_ptr<DiscBase> OpenDiscFromImage(std::string_view path, bool& isWii);
|
||||||
|
|
||||||
} // namespace nod
|
} // namespace nod
|
||||||
|
|
|
@ -10,6 +10,7 @@ add_library(nod
|
||||||
DiscIOWBFS.cpp
|
DiscIOWBFS.cpp
|
||||||
DiscWii.cpp
|
DiscWii.cpp
|
||||||
nod.cpp
|
nod.cpp
|
||||||
|
OSUTF.c
|
||||||
|
|
||||||
../include/nod/aes.hpp
|
../include/nod/aes.hpp
|
||||||
../include/nod/DirectoryEnumerator.hpp
|
../include/nod/DirectoryEnumerator.hpp
|
||||||
|
@ -21,13 +22,14 @@ add_library(nod
|
||||||
../include/nod/nod.hpp
|
../include/nod/nod.hpp
|
||||||
../include/nod/sha1.h
|
../include/nod/sha1.h
|
||||||
../include/nod/Util.hpp
|
../include/nod/Util.hpp
|
||||||
|
../include/nod/OSUTF.h
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(nod PUBLIC
|
target_include_directories(nod PUBLIC
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(nod PUBLIC logvisor)
|
target_link_libraries(nod PUBLIC $<BUILD_INTERFACE:logvisor>)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_sources(nod PRIVATE FileIOWin32.cpp)
|
target_sources(nod PRIVATE FileIOWin32.cpp)
|
||||||
|
|
|
@ -9,127 +9,157 @@
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
namespace nod {
|
namespace nod {
|
||||||
|
|
||||||
DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode, bool sizeSort, bool reverse, bool noHidden) {
|
DirectoryEnumerator::DirectoryEnumerator(std::string_view path, Mode mode, bool sizeSort, bool reverse, bool noHidden) {
|
||||||
Sstat theStat;
|
Sstat theStat;
|
||||||
if (Stat(path.data(), &theStat) || !S_ISDIR(theStat.st_mode))
|
if (Stat(path.data(), &theStat) || !S_ISDIR(theStat.st_mode)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
SystemString wc(path);
|
std::wstring wc = nowide::widen(path);
|
||||||
wc += _SYS_STR("/*");
|
wc += L"/*";
|
||||||
WIN32_FIND_DATAW d;
|
WIN32_FIND_DATAW d;
|
||||||
HANDLE dir = FindFirstFileW(wc.c_str(), &d);
|
HANDLE dir = FindFirstFileW(wc.c_str(), &d);
|
||||||
if (dir == INVALID_HANDLE_VALUE)
|
if (dir == INVALID_HANDLE_VALUE) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case Mode::Native:
|
case Mode::Native:
|
||||||
do {
|
do {
|
||||||
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
|
if (!wcscmp(d.cFileName, L".") || !wcscmp(d.cFileName, L"..")) {
|
||||||
continue;
|
continue;
|
||||||
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
|
}
|
||||||
|
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)) {
|
||||||
continue;
|
continue;
|
||||||
SystemString fp(path);
|
}
|
||||||
fp += _SYS_STR('/');
|
std::string fileName = nowide::narrow(d.cFileName);
|
||||||
fp += d.cFileName;
|
std::string fp(path);
|
||||||
|
fp += '/';
|
||||||
|
fp += fileName;
|
||||||
Sstat st;
|
Sstat st;
|
||||||
if (Stat(fp.c_str(), &st))
|
if (Stat(fp.c_str(), &st))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
size_t sz = 0;
|
size_t sz = 0;
|
||||||
bool isDir = false;
|
bool isDir = false;
|
||||||
if (S_ISDIR(st.st_mode))
|
if (S_ISDIR(st.st_mode)) {
|
||||||
isDir = true;
|
isDir = true;
|
||||||
else if (S_ISREG(st.st_mode))
|
} else if (S_ISREG(st.st_mode)) {
|
||||||
sz = st.st_size;
|
sz = st.st_size;
|
||||||
else
|
} else {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
m_entries.push_back(Entry(fp, d.cFileName, sz, isDir));
|
m_entries.emplace_back(fp, fileName, sz, isDir);
|
||||||
} while (FindNextFileW(dir, &d));
|
} while (FindNextFileW(dir, &d));
|
||||||
break;
|
break;
|
||||||
case Mode::DirsThenFilesSorted:
|
case Mode::DirsThenFilesSorted:
|
||||||
case Mode::DirsSorted: {
|
case Mode::DirsSorted: {
|
||||||
std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
|
std::map<std::string, Entry, CaseInsensitiveCompare> sort;
|
||||||
do {
|
do {
|
||||||
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
|
if (!wcscmp(d.cFileName, L".") || !wcscmp(d.cFileName, L"..")) {
|
||||||
continue;
|
continue;
|
||||||
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
|
}
|
||||||
|
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)) {
|
||||||
continue;
|
continue;
|
||||||
SystemString fp(path);
|
}
|
||||||
fp += _SYS_STR('/');
|
std::string fileName = nowide::narrow(d.cFileName);
|
||||||
fp += d.cFileName;
|
std::string fp(path);
|
||||||
|
fp += '/';
|
||||||
|
fp += fileName;
|
||||||
Sstat st;
|
Sstat st;
|
||||||
if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode))
|
if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode)) {
|
||||||
continue;
|
continue;
|
||||||
sort.emplace(std::make_pair(d.cFileName, Entry(fp, d.cFileName, 0, true)));
|
}
|
||||||
|
sort.emplace(fileName, Entry{fp, fileName, 0, true});
|
||||||
} while (FindNextFileW(dir, &d));
|
} while (FindNextFileW(dir, &d));
|
||||||
|
|
||||||
m_entries.reserve(sort.size());
|
m_entries.reserve(sort.size());
|
||||||
if (reverse)
|
if (reverse) {
|
||||||
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
|
for (auto& it : std::ranges::reverse_view(sort)) {
|
||||||
m_entries.push_back(std::move(it->second));
|
m_entries.emplace_back(std::move(it.second));
|
||||||
else
|
}
|
||||||
for (auto& e : sort)
|
} else {
|
||||||
m_entries.push_back(std::move(e.second));
|
for (auto& e : sort) {
|
||||||
|
m_entries.emplace_back(std::move(e.second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mode == Mode::DirsSorted)
|
if (mode == Mode::DirsSorted) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
FindClose(dir);
|
FindClose(dir);
|
||||||
dir = FindFirstFileW(wc.c_str(), &d);
|
dir = FindFirstFileW(wc.c_str(), &d);
|
||||||
}
|
}
|
||||||
case Mode::FilesSorted: {
|
case Mode::FilesSorted: {
|
||||||
if (mode == Mode::FilesSorted)
|
if (mode == Mode::FilesSorted) {
|
||||||
m_entries.clear();
|
m_entries.clear();
|
||||||
|
}
|
||||||
|
|
||||||
if (sizeSort) {
|
if (sizeSort) {
|
||||||
std::multimap<size_t, Entry> sort;
|
std::multimap<size_t, Entry> sort;
|
||||||
do {
|
do {
|
||||||
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
|
if (!wcscmp(d.cFileName, L".") || !wcscmp(d.cFileName, L"..")) {
|
||||||
continue;
|
continue;
|
||||||
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
|
}
|
||||||
|
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)) {
|
||||||
continue;
|
continue;
|
||||||
SystemString fp(path);
|
}
|
||||||
fp += _SYS_STR('/');
|
std::string fileName = nowide::narrow(d.cFileName);
|
||||||
fp += d.cFileName;
|
std::string fp(path);
|
||||||
|
fp += '/';
|
||||||
|
fp += fileName;
|
||||||
Sstat st;
|
Sstat st;
|
||||||
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
|
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode)) {
|
||||||
continue;
|
continue;
|
||||||
sort.emplace(std::make_pair(st.st_size, Entry(fp, d.cFileName, st.st_size, false)));
|
}
|
||||||
|
sort.emplace(st.st_size, Entry{fp, fileName, static_cast<size_t>(st.st_size), false});
|
||||||
} while (FindNextFileW(dir, &d));
|
} while (FindNextFileW(dir, &d));
|
||||||
|
|
||||||
m_entries.reserve(sort.size());
|
m_entries.reserve(m_entries.size() + sort.size());
|
||||||
if (reverse)
|
if (reverse) {
|
||||||
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
|
for (auto& it : std::ranges::reverse_view(sort)) {
|
||||||
m_entries.push_back(std::move(it->second));
|
m_entries.emplace_back(std::move(it.second));
|
||||||
else
|
}
|
||||||
for (auto& e : sort)
|
} else {
|
||||||
m_entries.push_back(std::move(e.second));
|
for (auto& e : sort) {
|
||||||
|
m_entries.emplace_back(std::move(e.second));
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
|
std::map<std::string, Entry, CaseInsensitiveCompare> sort;
|
||||||
do {
|
do {
|
||||||
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
|
if (!wcscmp(d.cFileName, L".") || !wcscmp(d.cFileName, L"..")) {
|
||||||
continue;
|
continue;
|
||||||
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
|
}
|
||||||
|
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)) {
|
||||||
continue;
|
continue;
|
||||||
SystemString fp(path);
|
}
|
||||||
fp += _SYS_STR('/');
|
std::string fileName = nowide::narrow(d.cFileName);
|
||||||
fp += d.cFileName;
|
std::string fp(path);
|
||||||
|
fp += '/';
|
||||||
|
fp += fileName;
|
||||||
Sstat st;
|
Sstat st;
|
||||||
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
|
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode)) {
|
||||||
continue;
|
continue;
|
||||||
sort.emplace(std::make_pair(d.cFileName, Entry(fp, d.cFileName, st.st_size, false)));
|
}
|
||||||
|
sort.emplace(fileName, Entry{fp, fileName, static_cast<size_t>(st.st_size), false});
|
||||||
} while (FindNextFileW(dir, &d));
|
} while (FindNextFileW(dir, &d));
|
||||||
|
|
||||||
m_entries.reserve(sort.size());
|
m_entries.reserve(m_entries.size() + sort.size());
|
||||||
if (reverse)
|
if (reverse) {
|
||||||
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
|
for (auto& e : std::ranges::reverse_view(sort)) {
|
||||||
m_entries.push_back(std::move(it->second));
|
m_entries.emplace_back(std::move(e.second));
|
||||||
else
|
}
|
||||||
for (auto& e : sort)
|
} else {
|
||||||
m_entries.push_back(std::move(e.second));
|
for (auto& e : sort) {
|
||||||
|
m_entries.emplace_back(std::move(e.second));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -150,7 +180,7 @@ DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode, bool
|
||||||
continue;
|
continue;
|
||||||
if (noHidden && d->d_name[0] == '.')
|
if (noHidden && d->d_name[0] == '.')
|
||||||
continue;
|
continue;
|
||||||
SystemString fp(path);
|
std::string fp(path);
|
||||||
fp += '/';
|
fp += '/';
|
||||||
fp += d->d_name;
|
fp += d->d_name;
|
||||||
Sstat st;
|
Sstat st;
|
||||||
|
@ -171,13 +201,13 @@ DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode, bool
|
||||||
break;
|
break;
|
||||||
case Mode::DirsThenFilesSorted:
|
case Mode::DirsThenFilesSorted:
|
||||||
case Mode::DirsSorted: {
|
case Mode::DirsSorted: {
|
||||||
std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
|
std::map<std::string, Entry, CaseInsensitiveCompare> sort;
|
||||||
while ((d = readdir(dir))) {
|
while ((d = readdir(dir))) {
|
||||||
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
|
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
|
||||||
continue;
|
continue;
|
||||||
if (noHidden && d->d_name[0] == '.')
|
if (noHidden && d->d_name[0] == '.')
|
||||||
continue;
|
continue;
|
||||||
SystemString fp(path);
|
std::string fp(path);
|
||||||
fp += '/';
|
fp += '/';
|
||||||
fp += d->d_name;
|
fp += d->d_name;
|
||||||
Sstat st;
|
Sstat st;
|
||||||
|
@ -210,7 +240,7 @@ DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode, bool
|
||||||
continue;
|
continue;
|
||||||
if (noHidden && d->d_name[0] == '.')
|
if (noHidden && d->d_name[0] == '.')
|
||||||
continue;
|
continue;
|
||||||
SystemString fp(path);
|
std::string fp(path);
|
||||||
fp += '/';
|
fp += '/';
|
||||||
fp += d->d_name;
|
fp += d->d_name;
|
||||||
Sstat st;
|
Sstat st;
|
||||||
|
@ -227,13 +257,13 @@ DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode, bool
|
||||||
for (auto& e : sort)
|
for (auto& e : sort)
|
||||||
m_entries.push_back(std::move(e.second));
|
m_entries.push_back(std::move(e.second));
|
||||||
} else {
|
} else {
|
||||||
std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
|
std::map<std::string, Entry, CaseInsensitiveCompare> sort;
|
||||||
while ((d = readdir(dir))) {
|
while ((d = readdir(dir))) {
|
||||||
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
|
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
|
||||||
continue;
|
continue;
|
||||||
if (noHidden && d->d_name[0] == '.')
|
if (noHidden && d->d_name[0] == '.')
|
||||||
continue;
|
continue;
|
||||||
SystemString fp(path);
|
std::string fp(path);
|
||||||
fp += '/';
|
fp += '/';
|
||||||
fp += d->d_name;
|
fp += d->d_name;
|
||||||
Sstat st;
|
Sstat st;
|
||||||
|
|
223
lib/DiscBase.cpp
223
lib/DiscBase.cpp
|
@ -43,14 +43,14 @@ static void* memmem(const void* haystack, size_t hlen, const void* needle, size_
|
||||||
|
|
||||||
namespace nod {
|
namespace nod {
|
||||||
|
|
||||||
const SystemChar* getKindString(PartitionKind kind) {
|
const char* getKindString(PartitionKind kind) {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case PartitionKind::Data:
|
case PartitionKind::Data:
|
||||||
return _SYS_STR("DATA");
|
return "DATA";
|
||||||
case PartitionKind::Update:
|
case PartitionKind::Update:
|
||||||
return _SYS_STR("UPDATE");
|
return "UPDATE";
|
||||||
case PartitionKind::Channel:
|
case PartitionKind::Channel:
|
||||||
return _SYS_STR("CHANNEL");
|
return "CHANNEL";
|
||||||
default:
|
default:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -126,25 +126,25 @@ std::unique_ptr<uint8_t[]> Node::getBuf() const {
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Node::extractToDirectory(SystemStringView basePath, const ExtractionContext& ctx, Codepage_t codepage) const {
|
bool Node::extractToDirectory(std::string_view basePath, const ExtractionContext& ctx) const {
|
||||||
DiscLocToSystemConv nameView(getName(), codepage);
|
SJISToUTF8 nameView(getName());
|
||||||
SystemString path = SystemString(basePath) + _SYS_STR('/') + nameView.sys_str().data();
|
std::string path = std::string(basePath) + '/' + nameView.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(nameView.sys_str(), m_parent.m_curNodeIdx / float(m_parent.getNodeCount()));
|
ctx.progressCB(nameView.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("unable to mkdir '{}'"), path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (Node& subnode : *this)
|
for (Node& subnode : *this)
|
||||||
if (!subnode.extractToDirectory(path, ctx, codepage))
|
if (!subnode.extractToDirectory(path, ctx))
|
||||||
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(nameView.sys_str(), m_parent.m_curNodeIdx / float(m_parent.getNodeCount()));
|
ctx.progressCB(nameView.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(nameView.sys_str(), (m_parent.m_curNodeIdx + prog) / float(m_parent.getNodeCount()));
|
ctx.progressCB(nameView.str(), (m_parent.m_curNodeIdx + prog) / float(m_parent.getNodeCount()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
++m_parent.m_curNodeIdx;
|
++m_parent.m_curNodeIdx;
|
||||||
|
@ -161,17 +161,17 @@ bool Node::extractToDirectory(SystemStringView basePath, const ExtractionContext
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IPartition::extractToDirectory(SystemStringView path, const ExtractionContext& ctx) {
|
bool IPartition::extractToDirectory(std::string_view path, const ExtractionContext& ctx) {
|
||||||
m_curNodeIdx = 0;
|
m_curNodeIdx = 0;
|
||||||
if (Mkdir(path.data(), 0755) && errno != EEXIST) {
|
if (Mkdir(path.data(), 0755) && errno != EEXIST) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to mkdir '{}'")), path);
|
LogModule.report(logvisor::Error, FMT_STRING("unable to mkdir '{}'"), path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemString basePath = m_isWii ? SystemString(path) + _SYS_STR("/") + getKindString(m_kind) : SystemString(path);
|
std::string basePath = m_isWii ? std::string(path) + "/" + getKindString(m_kind) : std::string(path);
|
||||||
if (m_isWii) {
|
if (m_isWii) {
|
||||||
if (Mkdir(basePath.c_str(), 0755) && errno != EEXIST) {
|
if (Mkdir(basePath.c_str(), 0755) && errno != EEXIST) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to mkdir '{}'")), basePath);
|
LogModule.report(logvisor::Error, FMT_STRING("unable to mkdir '{}'"), basePath);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,28 +188,28 @@ bool IPartition::extractToDirectory(SystemStringView path, const ExtractionConte
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Extract Filesystem */
|
/* Extract Filesystem */
|
||||||
SystemString fsPath = basePath + _SYS_STR("/files");
|
std::string fsPath = basePath + "/files";
|
||||||
if (Mkdir(fsPath.c_str(), 0755) && errno != EEXIST) {
|
if (Mkdir(fsPath.c_str(), 0755) && errno != EEXIST) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to mkdir '{}'")), fsPath);
|
LogModule.report(logvisor::Error, FMT_STRING("unable to mkdir '{}'"), fsPath);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_nodes[0].extractToDirectory(fsPath, ctx, m_codepage);
|
return m_nodes[0].extractToDirectory(fsPath, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IPartition::extractSysFiles(SystemStringView basePath, const ExtractionContext& ctx) const {
|
bool IPartition::extractSysFiles(std::string_view basePath, const ExtractionContext& ctx) const {
|
||||||
SystemString basePathStr(basePath);
|
std::string basePathStr(basePath);
|
||||||
if (Mkdir((basePathStr + _SYS_STR("/sys")).c_str(), 0755) && errno != EEXIST) {
|
if (Mkdir((basePathStr + "/sys").c_str(), 0755) && errno != EEXIST) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to mkdir '{}/sys'")), basePath);
|
LogModule.report(logvisor::Error, FMT_STRING("unable to mkdir '{}/sys'"), basePath);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sstat theStat;
|
Sstat theStat;
|
||||||
/* Extract Apploader */
|
/* Extract Apploader */
|
||||||
SystemString apploaderPath = basePathStr + _SYS_STR("/sys/apploader.img");
|
std::string apploaderPath = basePathStr + "/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(_SYS_STR("apploader.bin"), 0.f);
|
ctx.progressCB("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)
|
||||||
|
@ -218,10 +218,10 @@ bool IPartition::extractSysFiles(SystemStringView basePath, const ExtractionCont
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Extract Dol */
|
/* Extract Dol */
|
||||||
SystemString dolPath = basePathStr + _SYS_STR("/sys/main.dol");
|
std::string dolPath = basePathStr + "/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(_SYS_STR("main.dol"), 0.f);
|
ctx.progressCB("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)
|
||||||
|
@ -230,10 +230,10 @@ bool IPartition::extractSysFiles(SystemStringView basePath, const ExtractionCont
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Extract Boot info */
|
/* Extract Boot info */
|
||||||
SystemString bootPath = basePathStr + _SYS_STR("/sys/boot.bin");
|
std::string bootPath = basePathStr + "/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(_SYS_STR("boot.bin"), 0.f);
|
ctx.progressCB("boot.bin", 0.f);
|
||||||
auto ws = NewFileIO(bootPath)->beginWriteStream();
|
auto ws = NewFileIO(bootPath)->beginWriteStream();
|
||||||
if (!ws)
|
if (!ws)
|
||||||
return false;
|
return false;
|
||||||
|
@ -241,10 +241,10 @@ bool IPartition::extractSysFiles(SystemStringView basePath, const ExtractionCont
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Extract BI2 info */
|
/* Extract BI2 info */
|
||||||
SystemString bi2Path = basePathStr + _SYS_STR("/sys/bi2.bin");
|
std::string bi2Path = basePathStr + "/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(_SYS_STR("bi2.bin"), 0.f);
|
ctx.progressCB("bi2.bin", 0.f);
|
||||||
|
|
||||||
auto ws = NewFileIO(bi2Path)->beginWriteStream();
|
auto ws = NewFileIO(bi2Path)->beginWriteStream();
|
||||||
if (!ws)
|
if (!ws)
|
||||||
|
@ -255,26 +255,26 @@ bool IPartition::extractSysFiles(SystemStringView basePath, const ExtractionCont
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsSystemFile(SystemStringView name, bool& isDol) {
|
static bool IsSystemFile(std::string_view name, bool& isDol) {
|
||||||
isDol = false;
|
isDol = false;
|
||||||
if (name.size() < 4)
|
if (name.size() < 4)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!StrCaseCmp((&*(name.cend() - 4)), _SYS_STR(".dol"))) {
|
if (!StrCaseCmp((&*(name.cend() - 4)), ".dol")) {
|
||||||
isDol = true;
|
isDol = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!StrCaseCmp((&*(name.cend() - 4)), _SYS_STR(".rel")))
|
if (!StrCaseCmp((&*(name.cend() - 4)), ".rel"))
|
||||||
return true;
|
return true;
|
||||||
if (!StrCaseCmp((&*(name.cend() - 4)), _SYS_STR(".rso")))
|
if (!StrCaseCmp((&*(name.cend() - 4)), ".rso"))
|
||||||
return true;
|
return true;
|
||||||
if (!StrCaseCmp((&*(name.cend() - 4)), _SYS_STR(".sel")))
|
if (!StrCaseCmp((&*(name.cend() - 4)), ".sel"))
|
||||||
return true;
|
return true;
|
||||||
if (!StrCaseCmp((&*(name.cend() - 4)), _SYS_STR(".bnr")))
|
if (!StrCaseCmp((&*(name.cend() - 4)), ".bnr"))
|
||||||
return true;
|
return true;
|
||||||
if (!StrCaseCmp((&*(name.cend() - 4)), _SYS_STR(".elf")))
|
if (!StrCaseCmp((&*(name.cend() - 4)), ".elf"))
|
||||||
return true;
|
return true;
|
||||||
if (!StrCaseCmp((&*(name.cend() - 4)), _SYS_STR(".wad")))
|
if (!StrCaseCmp((&*(name.cend() - 4)), ".wad"))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -301,7 +301,7 @@ static size_t PatchDOL(IFileIO::IReadStream& in, IPartWriteStream& out, size_t s
|
||||||
return out.write(buf.get(), sz);
|
return out.write(buf.get(), sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiscBuilderBase::PartitionBuilderBase::recursiveBuildNodesPre(SystemStringView filesIn) {
|
void DiscBuilderBase::PartitionBuilderBase::recursiveBuildNodesPre(std::string_view filesIn) {
|
||||||
DirectoryEnumerator dEnum(filesIn, DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
|
DirectoryEnumerator dEnum(filesIn, DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
|
||||||
for (const DirectoryEnumerator::Entry& e : dEnum) {
|
for (const DirectoryEnumerator::Entry& e : dEnum) {
|
||||||
if (e.m_isDir)
|
if (e.m_isDir)
|
||||||
|
@ -312,7 +312,7 @@ void DiscBuilderBase::PartitionBuilderBase::recursiveBuildNodesPre(SystemStringV
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DiscBuilderBase::PartitionBuilderBase::recursiveBuildNodes(IPartWriteStream& ws, bool system,
|
bool DiscBuilderBase::PartitionBuilderBase::recursiveBuildNodes(IPartWriteStream& ws, bool system,
|
||||||
SystemStringView filesIn) {
|
std::string_view filesIn) {
|
||||||
DirectoryEnumerator dEnum(filesIn, DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
|
DirectoryEnumerator dEnum(filesIn, DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
|
||||||
for (const DirectoryEnumerator::Entry& e : dEnum) {
|
for (const DirectoryEnumerator::Entry& e : dEnum) {
|
||||||
if (e.m_isDir) {
|
if (e.m_isDir) {
|
||||||
|
@ -337,7 +337,7 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveBuildNodes(IPartWriteStream
|
||||||
bool patched;
|
bool patched;
|
||||||
xferSz = PatchDOL(*rs, ws, e.m_fileSz, patched);
|
xferSz = PatchDOL(*rs, ws, e.m_fileSz, patched);
|
||||||
m_parent.m_progressCB(m_parent.getProgressFactor(),
|
m_parent.m_progressCB(m_parent.getProgressFactor(),
|
||||||
e.m_name + (patched ? _SYS_STR(" [PATCHED]") : _SYS_STR("")), xferSz);
|
e.m_name + (patched ? " [PATCHED]" : ""), xferSz);
|
||||||
++m_parent.m_progressIdx;
|
++m_parent.m_progressIdx;
|
||||||
} else {
|
} else {
|
||||||
char buf[0x8000];
|
char buf[0x8000];
|
||||||
|
@ -359,7 +359,7 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveBuildNodes(IPartWriteStream
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DiscBuilderBase::PartitionBuilderBase::recursiveBuildFST(SystemStringView filesIn,
|
bool DiscBuilderBase::PartitionBuilderBase::recursiveBuildFST(std::string_view filesIn,
|
||||||
std::function<void(void)> incParents,
|
std::function<void(void)> incParents,
|
||||||
size_t parentDirIdx) {
|
size_t parentDirIdx) {
|
||||||
DirectoryEnumerator dEnum(filesIn, DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
|
DirectoryEnumerator dEnum(filesIn, DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
|
||||||
|
@ -387,7 +387,7 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveBuildFST(SystemStringView f
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiscBuilderBase::PartitionBuilderBase::recursiveMergeNodesPre(const Node* nodeIn, SystemStringView dirIn) {
|
void DiscBuilderBase::PartitionBuilderBase::recursiveMergeNodesPre(const Node* nodeIn, std::string_view dirIn) {
|
||||||
/* 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;
|
||||||
|
@ -406,10 +406,9 @@ 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) {
|
||||||
SystemToDiscLocConv nameView(e.m_name, m_codepage);
|
UTF8ToSJIS nameView(e.m_name);
|
||||||
|
|
||||||
if (e.m_isDir) {
|
if (e.m_isDir) {
|
||||||
auto search = dirNodes.find(nameView.disc_str().data());
|
auto search = dirNodes.find(nameView.str());
|
||||||
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 +416,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.disc_str().data());
|
fileNodes.erase(nameView.str());
|
||||||
++m_parent.m_progressTotal;
|
++m_parent.m_progressTotal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -433,7 +432,7 @@ void DiscBuilderBase::PartitionBuilderBase::recursiveMergeNodesPre(const Node* n
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeNodes(IPartWriteStream& ws, bool system, const Node* nodeIn,
|
bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeNodes(IPartWriteStream& ws, bool system, const Node* nodeIn,
|
||||||
SystemStringView dirIn, SystemStringView keyPath) {
|
std::string_view dirIn, std::string_view 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;
|
||||||
|
@ -452,11 +451,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) {
|
||||||
SystemToDiscLocConv nameView(e.m_name, m_codepage);
|
UTF8ToSJIS nameView(e.m_name);
|
||||||
SystemString chKeyPath = SystemString(keyPath) + _SYS_STR('/') + e.m_name;
|
std::string chKeyPath = std::string(keyPath) + '/' + e.m_name;
|
||||||
|
|
||||||
if (e.m_isDir) {
|
if (e.m_isDir) {
|
||||||
auto search = dirNodes.find(nameView.disc_str().data());
|
auto search = dirNodes.find(nameView.str());
|
||||||
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 +470,7 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeNodes(IPartWriteStream
|
||||||
if (system ^ isSys)
|
if (system ^ isSys)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
fileNodes.erase(nameView.disc_str().data());
|
fileNodes.erase(nameView.str());
|
||||||
|
|
||||||
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);
|
||||||
|
@ -486,7 +485,7 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeNodes(IPartWriteStream
|
||||||
bool patched;
|
bool patched;
|
||||||
xferSz = PatchDOL(*rs, ws, e.m_fileSz, patched);
|
xferSz = PatchDOL(*rs, ws, e.m_fileSz, patched);
|
||||||
m_parent.m_progressCB(m_parent.getProgressFactor(),
|
m_parent.m_progressCB(m_parent.getProgressFactor(),
|
||||||
e.m_name + (patched ? _SYS_STR(" [PATCHED]") : _SYS_STR("")), xferSz);
|
e.m_name + (patched ? " [PATCHED]" : ""), xferSz);
|
||||||
++m_parent.m_progressIdx;
|
++m_parent.m_progressIdx;
|
||||||
} else {
|
} else {
|
||||||
char buf[0x8000];
|
char buf[0x8000];
|
||||||
|
@ -508,8 +507,8 @@ 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) {
|
||||||
DiscLocToSystemConv sysName(p.second->getName(), m_codepage);
|
SJISToUTF8 sysName(p.second->getName());
|
||||||
SystemString chKeyPath = SystemString(keyPath) + _SYS_STR('/') + sysName.c_str();
|
std::string chKeyPath = std::string(keyPath) + '/' + sysName.str();
|
||||||
if (!recursiveMergeNodes(ws, system, p.second, {}, chKeyPath))
|
if (!recursiveMergeNodes(ws, system, p.second, {}, chKeyPath))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -517,11 +516,11 @@ 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;
|
||||||
DiscLocToSystemConv sysName(ch.getName(), m_codepage);
|
SJISToUTF8 sysName(ch.getName());
|
||||||
SystemString chKeyPath = SystemString(keyPath) + _SYS_STR('/') + sysName.c_str();
|
std::string chKeyPath = std::string(keyPath) + '/' + sysName.str();
|
||||||
|
|
||||||
bool isDol;
|
bool isDol;
|
||||||
bool isSys = IsSystemFile(sysName.sys_str(), isDol);
|
bool isSys = IsSystemFile(ch.getName(), isDol);
|
||||||
if (system ^ isSys)
|
if (system ^ isSys)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -541,7 +540,7 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeNodes(IPartWriteStream
|
||||||
PatchDOL(dolBuf, xferSz, patched);
|
PatchDOL(dolBuf, xferSz, patched);
|
||||||
ws.write(dolBuf.get(), xferSz);
|
ws.write(dolBuf.get(), xferSz);
|
||||||
m_parent.m_progressCB(m_parent.getProgressFactor(),
|
m_parent.m_progressCB(m_parent.getProgressFactor(),
|
||||||
SystemString(sysName.sys_str()) + (patched ? _SYS_STR(" [PATCHED]") : _SYS_STR("")),
|
std::string(ch.getName()) + (patched ? " [PATCHED]" : ""),
|
||||||
xferSz);
|
xferSz);
|
||||||
++m_parent.m_progressIdx;
|
++m_parent.m_progressIdx;
|
||||||
} else {
|
} else {
|
||||||
|
@ -552,7 +551,7 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeNodes(IPartWriteStream
|
||||||
break;
|
break;
|
||||||
ws.write(buf, rdSz);
|
ws.write(buf, rdSz);
|
||||||
xferSz += rdSz;
|
xferSz += rdSz;
|
||||||
m_parent.m_progressCB(m_parent.getProgressFactorMidFile(xferSz, ch.size()), sysName.sys_str(), xferSz);
|
m_parent.m_progressCB(m_parent.getProgressFactorMidFile(xferSz, ch.size()), ch.getName(), xferSz);
|
||||||
}
|
}
|
||||||
++m_parent.m_progressIdx;
|
++m_parent.m_progressIdx;
|
||||||
}
|
}
|
||||||
|
@ -563,9 +562,9 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeNodes(IPartWriteStream
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeFST(const Node* nodeIn, SystemStringView dirIn,
|
bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeFST(const Node* nodeIn, std::string_view dirIn,
|
||||||
std::function<void(void)> incParents,
|
std::function<void(void)> incParents,
|
||||||
size_t parentDirIdx, SystemStringView keyPath) {
|
size_t parentDirIdx, std::string_view 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,8 +583,8 @@ 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) {
|
||||||
SystemToDiscLocConv nameView(e.m_name, m_codepage);
|
UTF8ToSJIS nameView(e.m_name);
|
||||||
SystemString chKeyPath = SystemString(keyPath) + _SYS_STR('/') + e.m_name;
|
std::string chKeyPath = std::string(keyPath) + '/' + e.m_name;
|
||||||
|
|
||||||
if (e.m_isDir) {
|
if (e.m_isDir) {
|
||||||
size_t dirNodeIdx = m_buildNodes.size();
|
size_t dirNodeIdx = m_buildNodes.size();
|
||||||
|
@ -593,7 +592,7 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeFST(const Node* nodeIn
|
||||||
addBuildName(e.m_name);
|
addBuildName(e.m_name);
|
||||||
incParents();
|
incParents();
|
||||||
|
|
||||||
auto search = dirNodes.find(nameView.disc_str().data());
|
auto search = dirNodes.find(nameView.str());
|
||||||
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(),
|
||||||
[&]() {
|
[&]() {
|
||||||
|
@ -613,7 +612,7 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeFST(const Node* nodeIn
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fileNodes.erase(nameView.disc_str().data());
|
fileNodes.erase(nameView.str());
|
||||||
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,12 +623,12 @@ 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) {
|
||||||
DiscLocToSystemConv sysName(p.second->getName(), m_codepage);
|
SJISToUTF8 sysName(p.second->getName());
|
||||||
SystemString chKeyPath = SystemString(keyPath) + _SYS_STR('/') + sysName.sys_str().data();
|
std::string chKeyPath = std::string(keyPath) + '/' + sysName.str();
|
||||||
|
|
||||||
size_t dirNodeIdx = m_buildNodes.size();
|
size_t dirNodeIdx = m_buildNodes.size();
|
||||||
m_buildNodes.emplace_back(true, m_buildNameOff, parentDirIdx, dirNodeIdx + 1);
|
m_buildNodes.emplace_back(true, m_buildNameOff, parentDirIdx, dirNodeIdx + 1);
|
||||||
addBuildName(sysName.sys_str());
|
addBuildName(sysName.str());
|
||||||
incParents();
|
incParents();
|
||||||
|
|
||||||
if (!recursiveMergeFST(p.second, {},
|
if (!recursiveMergeFST(p.second, {},
|
||||||
|
@ -644,12 +643,12 @@ bool DiscBuilderBase::PartitionBuilderBase::recursiveMergeFST(const Node* nodeIn
|
||||||
/* 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;
|
||||||
DiscLocToSystemConv sysName(ch.getName(), m_codepage);
|
SJISToUTF8 sysName(ch.getName());
|
||||||
SystemString chKeyPath = SystemString(keyPath) + _SYS_STR('/') + sysName.sys_str().data();
|
std::string chKeyPath = std::string(keyPath) + '/' + sysName.str();
|
||||||
|
|
||||||
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(sysName.sys_str());
|
addBuildName(ch.getName());
|
||||||
incParents();
|
incParents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -657,7 +656,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, Codepage_t codepage) {
|
std::string_view dirIn) {
|
||||||
/* 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 +675,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) {
|
||||||
SystemToDiscLocConv nameView(e.m_name, codepage);
|
UTF8ToSJIS nameView(e.m_name);
|
||||||
|
|
||||||
if (e.m_isDir) {
|
if (e.m_isDir) {
|
||||||
auto search = dirNodes.find(nameView.disc_str().data());
|
auto search = dirNodes.find(nameView.str());
|
||||||
if (search != dirNodes.cend()) {
|
if (search != dirNodes.cend()) {
|
||||||
if (!RecursiveCalculateTotalSize(totalSz, search->second, e.m_path.c_str(), codepage))
|
if (!RecursiveCalculateTotalSize(totalSz, search->second, e.m_path))
|
||||||
return false;
|
return false;
|
||||||
dirNodes.erase(search);
|
dirNodes.erase(search);
|
||||||
} else {
|
} else {
|
||||||
if (!RecursiveCalculateTotalSize(totalSz, nullptr, e.m_path.c_str(), codepage))
|
if (!RecursiveCalculateTotalSize(totalSz, nullptr, e.m_path))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fileNodes.erase(nameView.disc_str().data());
|
fileNodes.erase(nameView.str());
|
||||||
totalSz += ROUND_UP_32(e.m_fileSz);
|
totalSz += ROUND_UP_32(e.m_fileSz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -697,7 +696,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, {}, codepage))
|
if (!RecursiveCalculateTotalSize(totalSz, p.second, {}))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -710,34 +709,34 @@ bool DiscBuilderBase::PartitionBuilderBase::RecursiveCalculateTotalSize(uint64_t
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DiscBuilderBase::PartitionBuilderBase::buildFromDirectory(IPartWriteStream& ws, SystemStringView dirIn) {
|
bool DiscBuilderBase::PartitionBuilderBase::buildFromDirectory(IPartWriteStream& ws, std::string_view dirIn) {
|
||||||
if (dirIn.empty()) {
|
if (dirIn.empty()) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("all arguments must be supplied to buildFromDirectory()")));
|
LogModule.report(logvisor::Error, FMT_STRING("all arguments must be supplied to buildFromDirectory()"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemString dirStr(dirIn);
|
std::string dirStr(dirIn);
|
||||||
SystemString basePath = m_isWii ? dirStr + _SYS_STR("/") + getKindString(m_kind) : dirStr;
|
std::string basePath = m_isWii ? dirStr + "/" + getKindString(m_kind) : dirStr;
|
||||||
SystemString dolIn = basePath + _SYS_STR("/sys/main.dol");
|
std::string dolIn = basePath + "/sys/main.dol";
|
||||||
SystemString filesIn = basePath + _SYS_STR("/files");
|
std::string filesIn = basePath + "/files";
|
||||||
|
|
||||||
/* 1st pass - Tally up total progress steps */
|
/* 1st pass - Tally up total progress steps */
|
||||||
m_parent.m_progressTotal += 2; /* Prep and DOL */
|
m_parent.m_progressTotal += 2; /* Prep and DOL */
|
||||||
recursiveBuildNodesPre(filesIn.c_str());
|
recursiveBuildNodesPre(filesIn.c_str());
|
||||||
|
|
||||||
/* Clear file */
|
/* Clear file */
|
||||||
m_parent.m_progressCB(m_parent.getProgressFactor(), _SYS_STR("Preparing output image"), -1);
|
m_parent.m_progressCB(m_parent.getProgressFactor(), "Preparing output image", -1);
|
||||||
++m_parent.m_progressIdx;
|
++m_parent.m_progressIdx;
|
||||||
|
|
||||||
/* Add root node */
|
/* Add root node */
|
||||||
m_buildNodes.emplace_back(true, m_buildNameOff, 0, 1);
|
m_buildNodes.emplace_back(true, m_buildNameOff, 0, 1);
|
||||||
addBuildName(_SYS_STR("<root>"));
|
addBuildName("<root>");
|
||||||
|
|
||||||
/* Write Boot DOL first (first thing seeked to after Apploader) */
|
/* Write Boot DOL first (first thing seeked to after Apploader) */
|
||||||
{
|
{
|
||||||
Sstat dolStat;
|
Sstat dolStat;
|
||||||
if (Stat(dolIn.c_str(), &dolStat)) {
|
if (Stat(dolIn.c_str(), &dolStat)) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {}")), dolIn);
|
LogModule.report(logvisor::Error, FMT_STRING("unable to stat {}"), dolIn);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
size_t fileSz = ROUND_UP_32(dolStat.st_size);
|
size_t fileSz = ROUND_UP_32(dolStat.st_size);
|
||||||
|
@ -751,7 +750,7 @@ bool DiscBuilderBase::PartitionBuilderBase::buildFromDirectory(IPartWriteStream&
|
||||||
return false;
|
return false;
|
||||||
bool patched;
|
bool patched;
|
||||||
size_t xferSz = PatchDOL(*rs, ws, dolStat.st_size, patched);
|
size_t xferSz = PatchDOL(*rs, ws, dolStat.st_size, patched);
|
||||||
m_parent.m_progressCB(m_parent.getProgressFactor(), dolIn + (patched ? _SYS_STR(" [PATCHED]") : _SYS_STR("")),
|
m_parent.m_progressCB(m_parent.getProgressFactor(), dolIn + (patched ? " [PATCHED]" : ""),
|
||||||
xferSz);
|
xferSz);
|
||||||
++m_parent.m_progressIdx;
|
++m_parent.m_progressIdx;
|
||||||
for (size_t i = 0; i < fileSz - xferSz; ++i)
|
for (size_t i = 0; i < fileSz - xferSz; ++i)
|
||||||
|
@ -769,46 +768,46 @@ bool DiscBuilderBase::PartitionBuilderBase::buildFromDirectory(IPartWriteStream&
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<uint64_t> DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeBuild(SystemStringView dirIn,
|
std::optional<uint64_t> DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeBuild(std::string_view dirIn,
|
||||||
PartitionKind kind, bool isWii, Codepage_t codepage) {
|
PartitionKind kind, bool isWii) {
|
||||||
SystemString dirStr(dirIn);
|
std::string dirStr(dirIn);
|
||||||
SystemString basePath = isWii ? dirStr + _SYS_STR("/") + getKindString(kind) : dirStr;
|
std::string basePath = isWii ? dirStr + "/" + getKindString(kind) : dirStr;
|
||||||
SystemString dolIn = basePath + _SYS_STR("/sys/main.dol");
|
std::string dolIn = basePath + "/sys/main.dol";
|
||||||
SystemString filesIn = basePath + _SYS_STR("/files");
|
std::string filesIn = basePath + "/files";
|
||||||
|
|
||||||
Sstat dolStat;
|
Sstat dolStat;
|
||||||
if (Stat(dolIn.c_str(), &dolStat)) {
|
if (Stat(dolIn.c_str(), &dolStat)) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {}")), dolIn);
|
LogModule.report(logvisor::Error, FMT_STRING("unable to stat {}"), dolIn);
|
||||||
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(), codepage))
|
if (!RecursiveCalculateTotalSize(totalSz, nullptr, filesIn))
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
return totalSz;
|
return totalSz;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DiscBuilderBase::PartitionBuilderBase::mergeFromDirectory(IPartWriteStream& ws, const IPartition* partIn,
|
bool DiscBuilderBase::PartitionBuilderBase::mergeFromDirectory(IPartWriteStream& ws, const IPartition* partIn,
|
||||||
SystemStringView dirIn) {
|
std::string_view dirIn) {
|
||||||
if (dirIn.empty()) {
|
if (dirIn.empty()) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("all arguments must be supplied to mergeFromDirectory()")));
|
LogModule.report(logvisor::Error, FMT_STRING("all arguments must be supplied to mergeFromDirectory()"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemString dirStr(dirIn);
|
std::string dirStr(dirIn);
|
||||||
SystemString basePath = m_isWii ? dirStr + _SYS_STR("/") + getKindString(m_kind) : dirStr;
|
std::string basePath = m_isWii ? dirStr + "/" + getKindString(m_kind) : dirStr;
|
||||||
SystemString filesIn = basePath + _SYS_STR("/files");
|
std::string filesIn = basePath + "/files";
|
||||||
|
|
||||||
/* 1st pass - Tally up total progress steps */
|
/* 1st pass - Tally up total progress steps */
|
||||||
m_parent.m_progressTotal += 2; /* Prep and DOL */
|
m_parent.m_progressTotal += 2; /* Prep and DOL */
|
||||||
recursiveMergeNodesPre(&partIn->getFSTRoot(), filesIn.c_str());
|
recursiveMergeNodesPre(&partIn->getFSTRoot(), filesIn.c_str());
|
||||||
|
|
||||||
/* Clear file */
|
/* Clear file */
|
||||||
m_parent.m_progressCB(m_parent.getProgressFactor(), _SYS_STR("Preparing output image"), -1);
|
m_parent.m_progressCB(m_parent.getProgressFactor(), "Preparing output image", -1);
|
||||||
++m_parent.m_progressIdx;
|
++m_parent.m_progressIdx;
|
||||||
|
|
||||||
/* Add root node */
|
/* Add root node */
|
||||||
m_buildNodes.emplace_back(true, m_buildNameOff, 0, 1);
|
m_buildNodes.emplace_back(true, m_buildNameOff, 0, 1);
|
||||||
addBuildName(_SYS_STR("<root>"));
|
addBuildName("<root>");
|
||||||
|
|
||||||
/* Write Boot DOL first (first thing seeked to after Apploader) */
|
/* Write Boot DOL first (first thing seeked to after Apploader) */
|
||||||
{
|
{
|
||||||
|
@ -824,7 +823,7 @@ bool DiscBuilderBase::PartitionBuilderBase::mergeFromDirectory(IPartWriteStream&
|
||||||
PatchDOL(dolBuf, xferSz, patched);
|
PatchDOL(dolBuf, xferSz, patched);
|
||||||
ws.write(dolBuf.get(), xferSz);
|
ws.write(dolBuf.get(), xferSz);
|
||||||
m_parent.m_progressCB(m_parent.getProgressFactor(),
|
m_parent.m_progressCB(m_parent.getProgressFactor(),
|
||||||
SystemString(_SYS_STR("<boot-dol>")) + (patched ? _SYS_STR(" [PATCHED]") : _SYS_STR("")),
|
std::string("<boot-dol>") + (patched ? " [PATCHED]" : ""),
|
||||||
xferSz);
|
xferSz);
|
||||||
++m_parent.m_progressIdx;
|
++m_parent.m_progressIdx;
|
||||||
for (size_t i = 0; i < fileSz - xferSz; ++i)
|
for (size_t i = 0; i < fileSz - xferSz; ++i)
|
||||||
|
@ -832,7 +831,7 @@ bool DiscBuilderBase::PartitionBuilderBase::mergeFromDirectory(IPartWriteStream&
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Gather files in root directory */
|
/* Gather files in root directory */
|
||||||
SystemString keyPath;
|
std::string keyPath;
|
||||||
if (!recursiveMergeNodes(ws, true, &partIn->getFSTRoot(), filesIn.c_str(), keyPath))
|
if (!recursiveMergeNodes(ws, true, &partIn->getFSTRoot(), filesIn.c_str(), keyPath))
|
||||||
return false;
|
return false;
|
||||||
if (!recursiveMergeNodes(ws, false, &partIn->getFSTRoot(), filesIn.c_str(), keyPath))
|
if (!recursiveMergeNodes(ws, false, &partIn->getFSTRoot(), filesIn.c_str(), keyPath))
|
||||||
|
@ -844,13 +843,13 @@ bool DiscBuilderBase::PartitionBuilderBase::mergeFromDirectory(IPartWriteStream&
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<uint64_t> DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeMerge(const IPartition* partIn,
|
std::optional<uint64_t> DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeMerge(const IPartition* partIn,
|
||||||
SystemStringView dirIn, Codepage_t codepage) {
|
std::string_view dirIn) {
|
||||||
SystemString dirStr(dirIn);
|
std::string dirStr(dirIn);
|
||||||
SystemString basePath = partIn->isWii() ? dirStr + _SYS_STR("/") + getKindString(partIn->getKind()) : dirStr;
|
std::string basePath = partIn->isWii() ? dirStr + "/" + getKindString(partIn->getKind()) : dirStr;
|
||||||
SystemString filesIn = basePath + _SYS_STR("/files");
|
std::string filesIn = basePath + "/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(), codepage))
|
if (!RecursiveCalculateTotalSize(totalSz, &partIn->getFSTRoot(), filesIn))
|
||||||
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, Codepage_t codepage)
|
PartitionGCN(const DiscGCN& parent, uint64_t offset, bool& err)
|
||||||
: IPartition(parent, PartitionKind::Data, false, offset, codepage) {
|
: IPartition(parent, PartitionKind::Data, false, offset) {
|
||||||
/* 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,19 +118,19 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
DiscGCN::DiscGCN(std::unique_ptr<IDiscIO>&& dio, bool& err, Codepage_t codepage) : DiscBase(std::move(dio), err) {
|
DiscGCN::DiscGCN(std::unique_ptr<IDiscIO>&& dio, bool& err) : 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, codepage));
|
m_partitions.emplace_back(std::make_unique<PartitionGCN>(*this, 0, err));
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscBuilderGCN DiscGCN::makeMergeBuilder(SystemStringView outPath, FProgress progressCB, Codepage_t codepage) {
|
DiscBuilderGCN DiscGCN::makeMergeBuilder(std::string_view outPath, FProgress progressCB) {
|
||||||
return DiscBuilderGCN(outPath, progressCB, codepage);
|
return DiscBuilderGCN(outPath, progressCB);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DiscGCN::extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const { return true; }
|
bool DiscGCN::extractDiscHeaderFiles(std::string_view path, const ExtractionContext& ctx) const { return true; }
|
||||||
|
|
||||||
class PartitionBuilderGCN : public DiscBuilderBase::PartitionBuilderBase {
|
class PartitionBuilderGCN : public DiscBuilderBase::PartitionBuilderBase {
|
||||||
uint64_t m_curUser = 0x57058000;
|
uint64_t m_curUser = 0x57058000;
|
||||||
|
@ -161,8 +161,8 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PartitionBuilderGCN(DiscBuilderBase& parent, Codepage_t codepage)
|
PartitionBuilderGCN(DiscBuilderBase& parent)
|
||||||
: DiscBuilderBase::PartitionBuilderBase(parent, PartitionKind::Data, false, codepage) {}
|
: DiscBuilderBase::PartitionBuilderBase(parent, PartitionKind::Data, false) {}
|
||||||
|
|
||||||
uint64_t userAllocate(uint64_t reqSz, IPartWriteStream& ws) override {
|
uint64_t userAllocate(uint64_t reqSz, IPartWriteStream& ws) override {
|
||||||
m_curUser -= reqSz;
|
m_curUser -= reqSz;
|
||||||
|
@ -226,7 +226,7 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool buildFromDirectory(SystemStringView dirIn) {
|
bool buildFromDirectory(std::string_view dirIn) {
|
||||||
std::unique_ptr<IPartWriteStream> ws = beginWriteStream(0);
|
std::unique_ptr<IPartWriteStream> ws = beginWriteStream(0);
|
||||||
if (!ws)
|
if (!ws)
|
||||||
return false;
|
return false;
|
||||||
|
@ -234,29 +234,29 @@ public:
|
||||||
if (!result)
|
if (!result)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
SystemString dirStr(dirIn);
|
std::string dirStr(dirIn);
|
||||||
|
|
||||||
/* Check Apploader */
|
/* Check Apploader */
|
||||||
SystemString apploaderIn = dirStr + _SYS_STR("/sys/apploader.img");
|
std::string apploaderIn = dirStr + "/sys/apploader.img";
|
||||||
Sstat apploaderStat;
|
Sstat apploaderStat;
|
||||||
if (Stat(apploaderIn.c_str(), &apploaderStat)) {
|
if (Stat(apploaderIn.c_str(), &apploaderStat)) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {}")), apploaderIn);
|
LogModule.report(logvisor::Error, FMT_STRING("unable to stat {}"), apploaderIn);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check Boot */
|
/* Check Boot */
|
||||||
SystemString bootIn = dirStr + _SYS_STR("/sys/boot.bin");
|
std::string bootIn = dirStr + "/sys/boot.bin";
|
||||||
Sstat bootStat;
|
Sstat bootStat;
|
||||||
if (Stat(bootIn.c_str(), &bootStat)) {
|
if (Stat(bootIn.c_str(), &bootStat)) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {}")), bootIn);
|
LogModule.report(logvisor::Error, FMT_STRING("unable to stat {}"), bootIn);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check BI2 */
|
/* Check BI2 */
|
||||||
SystemString bi2In = dirStr + _SYS_STR("/sys/bi2.bin");
|
std::string bi2In = dirStr + "/sys/bi2.bin";
|
||||||
Sstat bi2Stat;
|
Sstat bi2Stat;
|
||||||
if (Stat(bi2In.c_str(), &bi2Stat)) {
|
if (Stat(bi2In.c_str(), &bi2Stat)) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {}")), bi2In);
|
LogModule.report(logvisor::Error, FMT_STRING("unable to stat {}"), bi2In);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,7 +308,7 @@ public:
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mergeFromDirectory(const PartitionGCN* partIn, SystemStringView dirIn) {
|
bool mergeFromDirectory(const PartitionGCN* partIn, std::string_view dirIn) {
|
||||||
std::unique_ptr<IPartWriteStream> ws = beginWriteStream(0);
|
std::unique_ptr<IPartWriteStream> ws = beginWriteStream(0);
|
||||||
if (!ws)
|
if (!ws)
|
||||||
return false;
|
return false;
|
||||||
|
@ -336,7 +336,7 @@ public:
|
||||||
[this, partIn](IPartWriteStream& ws, size_t& xferSz) -> bool {
|
[this, partIn](IPartWriteStream& ws, size_t& xferSz) -> bool {
|
||||||
std::unique_ptr<uint8_t[]> apploaderBuf = partIn->getApploaderBuf();
|
std::unique_ptr<uint8_t[]> apploaderBuf = partIn->getApploaderBuf();
|
||||||
size_t apploaderSz = partIn->getApploaderSize();
|
size_t apploaderSz = partIn->getApploaderSize();
|
||||||
SystemString apploaderName(_SYS_STR("<apploader>"));
|
std::string apploaderName("<apploader>");
|
||||||
ws.write(apploaderBuf.get(), apploaderSz);
|
ws.write(apploaderBuf.get(), apploaderSz);
|
||||||
xferSz += apploaderSz;
|
xferSz += apploaderSz;
|
||||||
if (0x2440 + xferSz >= m_curUser) {
|
if (0x2440 + xferSz >= m_curUser) {
|
||||||
|
@ -350,14 +350,14 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
EBuildResult DiscBuilderGCN::buildFromDirectory(SystemStringView dirIn) {
|
EBuildResult DiscBuilderGCN::buildFromDirectory(std::string_view dirIn) {
|
||||||
if (!m_fileIO->beginWriteStream())
|
if (!m_fileIO->beginWriteStream())
|
||||||
return EBuildResult::Failed;
|
return EBuildResult::Failed;
|
||||||
if (!CheckFreeSpace(m_outPath.c_str(), 0x57058000)) {
|
if (!CheckFreeSpace(m_outPath.c_str(), 0x57058000)) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("not enough free disk space for {}")), m_outPath);
|
LogModule.report(logvisor::Error, FMT_STRING("not enough free disk space for {}"), m_outPath);
|
||||||
return EBuildResult::DiskFull;
|
return EBuildResult::DiskFull;
|
||||||
}
|
}
|
||||||
m_progressCB(getProgressFactor(), _SYS_STR("Preallocating image"), -1);
|
m_progressCB(getProgressFactor(), "Preallocating image", -1);
|
||||||
++m_progressIdx;
|
++m_progressIdx;
|
||||||
{
|
{
|
||||||
auto ws = m_fileIO->beginWriteStream(0);
|
auto ws = m_fileIO->beginWriteStream(0);
|
||||||
|
@ -372,34 +372,34 @@ 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, Codepage_t codepage) {
|
std::optional<uint64_t> DiscBuilderGCN::CalculateTotalSizeRequired(std::string_view dirIn) {
|
||||||
std::optional<uint64_t> sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeBuild(dirIn, PartitionKind::Data, false, codepage);
|
std::optional<uint64_t> sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeBuild(dirIn, PartitionKind::Data, false);
|
||||||
if (!sz)
|
if (!sz)
|
||||||
return sz;
|
return sz;
|
||||||
*sz += 0x30000;
|
*sz += 0x30000;
|
||||||
if (sz > 0x57058000) {
|
if (sz > 0x57058000) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("disc capacity exceeded [{} / {}]")), *sz, 0x57058000);
|
LogModule.report(logvisor::Error, FMT_STRING("disc capacity exceeded [{} / {}]"), *sz, 0x57058000);
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
return sz;
|
return sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscBuilderGCN::DiscBuilderGCN(SystemStringView outPath, FProgress progressCB, Codepage_t codepage)
|
DiscBuilderGCN::DiscBuilderGCN(std::string_view outPath, FProgress progressCB)
|
||||||
: DiscBuilderBase(outPath, 0x57058000, progressCB) {
|
: DiscBuilderBase(outPath, 0x57058000, progressCB) {
|
||||||
m_partitions.emplace_back(std::make_unique<PartitionBuilderGCN>(*this, codepage));
|
m_partitions.emplace_back(std::make_unique<PartitionBuilderGCN>(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscMergerGCN::DiscMergerGCN(SystemStringView outPath, DiscGCN& sourceDisc, FProgress progressCB, Codepage_t codepage)
|
DiscMergerGCN::DiscMergerGCN(std::string_view outPath, DiscGCN& sourceDisc, FProgress progressCB)
|
||||||
: m_sourceDisc(sourceDisc), m_builder(sourceDisc.makeMergeBuilder(outPath, progressCB, codepage)) {}
|
: m_sourceDisc(sourceDisc), m_builder(sourceDisc.makeMergeBuilder(outPath, progressCB)) {}
|
||||||
|
|
||||||
EBuildResult DiscMergerGCN::mergeFromDirectory(SystemStringView dirIn) {
|
EBuildResult DiscMergerGCN::mergeFromDirectory(std::string_view dirIn) {
|
||||||
if (!m_builder.getFileIO().beginWriteStream())
|
if (!m_builder.getFileIO().beginWriteStream())
|
||||||
return EBuildResult::Failed;
|
return EBuildResult::Failed;
|
||||||
if (!CheckFreeSpace(m_builder.m_outPath.c_str(), 0x57058000)) {
|
if (!CheckFreeSpace(m_builder.m_outPath.c_str(), 0x57058000)) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("not enough free disk space for {}")), m_builder.m_outPath);
|
LogModule.report(logvisor::Error, FMT_STRING("not enough free disk space for {}"), m_builder.m_outPath);
|
||||||
return EBuildResult::DiskFull;
|
return EBuildResult::DiskFull;
|
||||||
}
|
}
|
||||||
m_builder.m_progressCB(m_builder.getProgressFactor(), _SYS_STR("Preallocating image"), -1);
|
m_builder.m_progressCB(m_builder.getProgressFactor(), "Preallocating image", -1);
|
||||||
++m_builder.m_progressIdx;
|
++m_builder.m_progressIdx;
|
||||||
{
|
{
|
||||||
auto ws = m_builder.m_fileIO->beginWriteStream(0);
|
auto ws = m_builder.m_fileIO->beginWriteStream(0);
|
||||||
|
@ -416,13 +416,13 @@ EBuildResult DiscMergerGCN::mergeFromDirectory(SystemStringView dirIn) {
|
||||||
: EBuildResult::Failed;
|
: EBuildResult::Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<uint64_t> DiscMergerGCN::CalculateTotalSizeRequired(DiscGCN& sourceDisc, SystemStringView dirIn, Codepage_t codepage) {
|
std::optional<uint64_t> DiscMergerGCN::CalculateTotalSizeRequired(DiscGCN& sourceDisc, std::string_view dirIn) {
|
||||||
std::optional<uint64_t> sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeMerge(sourceDisc.getDataPartition(), dirIn, codepage);
|
std::optional<uint64_t> sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeMerge(sourceDisc.getDataPartition(), dirIn);
|
||||||
if (!sz)
|
if (!sz)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
*sz += 0x30000;
|
*sz += 0x30000;
|
||||||
if (sz > 0x57058000) {
|
if (sz > 0x57058000) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("disc capacity exceeded [{} / {}]")), *sz, 0x57058000);
|
LogModule.report(logvisor::Error, FMT_STRING("disc capacity exceeded [{} / {}]"), *sz, 0x57058000);
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
return sz;
|
return sz;
|
||||||
|
|
|
@ -8,7 +8,7 @@ class DiscIOISO : public IDiscIO {
|
||||||
std::unique_ptr<IFileIO> m_fio;
|
std::unique_ptr<IFileIO> m_fio;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DiscIOISO(SystemStringView fpin) : m_fio(NewFileIO(fpin)) {}
|
DiscIOISO(std::string_view fpin) : m_fio(NewFileIO(fpin)) {}
|
||||||
|
|
||||||
class ReadStream : public IReadStream {
|
class ReadStream : public IReadStream {
|
||||||
friend class DiscIOISO;
|
friend class DiscIOISO;
|
||||||
|
@ -57,6 +57,6 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<IDiscIO> NewDiscIOISO(SystemStringView path) { return std::make_unique<DiscIOISO>(path); }
|
std::unique_ptr<IDiscIO> NewDiscIOISO(std::string_view path) { return std::make_unique<DiscIOISO>(path); }
|
||||||
|
|
||||||
} // namespace nod
|
} // namespace nod
|
||||||
|
|
|
@ -34,8 +34,8 @@ class DiscIONFS : public IDiscIO {
|
||||||
uint32_t totalBlockCount = 0;
|
uint32_t totalBlockCount = 0;
|
||||||
for (uint32_t i = 0; i < nfsHead.lbaRangeCount; ++i)
|
for (uint32_t i = 0; i < nfsHead.lbaRangeCount; ++i)
|
||||||
totalBlockCount += nfsHead.lbaRanges[i].numBlocks;
|
totalBlockCount += nfsHead.lbaRanges[i].numBlocks;
|
||||||
return (uint64_t(totalBlockCount) * uint64_t(0x8000) +
|
return (uint64_t(totalBlockCount) * uint64_t(0x8000) + (uint64_t(0x200) + uint64_t(0xF9FFFFF))) /
|
||||||
(uint64_t(0x200) + uint64_t(0xF9FFFFF))) / uint64_t(0xFA00000);
|
uint64_t(0xFA00000);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FBO {
|
struct FBO {
|
||||||
|
@ -57,57 +57,57 @@ class DiscIONFS : public IDiscIO {
|
||||||
if (block == UINT32_MAX)
|
if (block == UINT32_MAX)
|
||||||
return {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX};
|
return {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX};
|
||||||
auto fileAndRemBlocks = nod::div(block, uint32_t(8000)); /* 8000 blocks per file */
|
auto fileAndRemBlocks = nod::div(block, uint32_t(8000)); /* 8000 blocks per file */
|
||||||
return {uint32_t(fileAndRemBlocks.quot), uint32_t(fileAndRemBlocks.rem),
|
return {uint32_t(fileAndRemBlocks.quot), uint32_t(fileAndRemBlocks.rem), uint32_t(blockAndRemBytes.quot),
|
||||||
uint32_t(blockAndRemBytes.quot), uint32_t(blockAndRemBytes.rem)};
|
uint32_t(blockAndRemBytes.rem)};
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DiscIONFS(SystemStringView fpin, bool& err) {
|
DiscIONFS(std::string_view fpin, bool& err) {
|
||||||
/* Validate file path format */
|
/* Validate file path format */
|
||||||
using SignedSize = std::make_signed<SystemString::size_type>::type;
|
using SignedSize = std::make_signed<std::string::size_type>::type;
|
||||||
const auto dotPos = SignedSize(fpin.rfind(_SYS_STR('.')));
|
const auto dotPos = SignedSize(fpin.rfind('.'));
|
||||||
const auto slashPos = SignedSize(fpin.find_last_of(_SYS_STR("/\\")));
|
const auto slashPos = SignedSize(fpin.find_last_of("/\\"));
|
||||||
if (fpin.size() <= 4 || dotPos == -1 || dotPos <= slashPos ||
|
if (fpin.size() <= 4 || dotPos == -1 || dotPos <= slashPos || fpin.compare(slashPos + 1, 4, "hif_") ||
|
||||||
fpin.compare(slashPos + 1, 4, _SYS_STR("hif_")) ||
|
fpin.compare(dotPos, fpin.size() - dotPos, ".nfs")) {
|
||||||
fpin.compare(dotPos, fpin.size() - dotPos, _SYS_STR(".nfs"))) {
|
|
||||||
LogModule.report(logvisor::Error,
|
LogModule.report(logvisor::Error,
|
||||||
FMT_STRING(_SYS_STR("'{}' must begin with 'hif_' and end with '.nfs' to be accepted as an NFS image")), fpin);
|
FMT_STRING("'{}' must begin with 'hif_' and end with '.nfs' to be accepted as an NFS image"),
|
||||||
|
fpin);
|
||||||
err = true;
|
err = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load key file */
|
/* Load key file */
|
||||||
const SystemString dir(fpin.begin(), fpin.begin() + slashPos + 1);
|
const std::string dir(fpin.begin(), fpin.begin() + slashPos + 1);
|
||||||
auto keyFile = NewFileIO(dir + _SYS_STR("../code/htk.bin"))->beginReadStream();
|
auto keyFile = NewFileIO(dir + "../code/htk.bin")->beginReadStream();
|
||||||
if (!keyFile)
|
if (!keyFile)
|
||||||
keyFile = NewFileIO(dir + _SYS_STR("htk.bin"))->beginReadStream();
|
keyFile = NewFileIO(dir + "htk.bin")->beginReadStream();
|
||||||
if (!keyFile) {
|
if (!keyFile) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("Unable to open '{}../code/htk.bin' or '{}htk.bin'")), dir, dir);
|
LogModule.report(logvisor::Error, FMT_STRING("Unable to open '{}../code/htk.bin' or '{}htk.bin'"), dir, dir);
|
||||||
err = true;
|
err = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (keyFile->read(key, 16) != 16) {
|
if (keyFile->read(key, 16) != 16) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("Unable to read from '{}../code/htk.bin' or '{}htk.bin'")), dir, dir);
|
LogModule.report(logvisor::Error, FMT_STRING("Unable to read from '{}../code/htk.bin' or '{}htk.bin'"), dir, dir);
|
||||||
err = true;
|
err = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load header from first file */
|
/* Load header from first file */
|
||||||
const SystemString firstPath = fmt::format(FMT_STRING(_SYS_STR("{}hif_{:06}.nfs")), dir, 0);
|
const std::string firstPath = fmt::format(FMT_STRING("{}hif_{:06}.nfs"), dir, 0);
|
||||||
files.push_back(NewFileIO(firstPath));
|
files.push_back(NewFileIO(firstPath));
|
||||||
auto rs = files.back()->beginReadStream();
|
auto rs = files.back()->beginReadStream();
|
||||||
if (!rs) {
|
if (!rs) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("'{}' does not exist")), firstPath);
|
LogModule.report(logvisor::Error, FMT_STRING("'{}' does not exist"), firstPath);
|
||||||
err = true;
|
err = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (rs->read(&nfsHead, 0x200) != 0x200) {
|
if (rs->read(&nfsHead, 0x200) != 0x200) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("Unable to read header from '{}'")), firstPath);
|
LogModule.report(logvisor::Error, FMT_STRING("Unable to read header from '{}'"), firstPath);
|
||||||
err = true;
|
err = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (std::memcmp(&nfsHead.magic, "EGGS", 4)) {
|
if (std::memcmp(&nfsHead.magic, "EGGS", 4)) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("Invalid magic in '{}'")), firstPath);
|
LogModule.report(logvisor::Error, FMT_STRING("Invalid magic in '{}'"), firstPath);
|
||||||
err = true;
|
err = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -122,10 +122,10 @@ public:
|
||||||
const uint32_t numFiles = calculateNumFiles();
|
const uint32_t numFiles = calculateNumFiles();
|
||||||
files.reserve(numFiles);
|
files.reserve(numFiles);
|
||||||
for (uint32_t i = 1; i < numFiles; ++i) {
|
for (uint32_t i = 1; i < numFiles; ++i) {
|
||||||
SystemString path = fmt::format(FMT_STRING(_SYS_STR("{}hif_{:06}.nfs")), dir, i);
|
std::string path = fmt::format(FMT_STRING("{}hif_{:06}.nfs"), dir, i);
|
||||||
files.push_back(NewFileIO(path));
|
files.push_back(NewFileIO(path));
|
||||||
if (!files.back()->exists()) {
|
if (!files.back()->exists()) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("'{}' does not exist")), path);
|
LogModule.report(logvisor::Error, FMT_STRING("'{}' does not exist"), path);
|
||||||
err = true;
|
err = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -150,8 +150,10 @@ public:
|
||||||
uint32_t m_curBlock = UINT32_MAX;
|
uint32_t m_curBlock = UINT32_MAX;
|
||||||
|
|
||||||
ReadStream(const DiscIONFS& parent, uint64_t offset, bool& err)
|
ReadStream(const DiscIONFS& parent, uint64_t offset, bool& err)
|
||||||
: m_parent(parent), m_aes(NewAES()),
|
: m_parent(parent)
|
||||||
m_physAddr({UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX}), m_offset(offset) {
|
, m_aes(NewAES())
|
||||||
|
, m_physAddr({UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX})
|
||||||
|
, m_offset(offset) {
|
||||||
m_aes->setKey(m_parent.key);
|
m_aes->setKey(m_parent.key);
|
||||||
setLogicalAddr(offset);
|
setLogicalAddr(offset);
|
||||||
}
|
}
|
||||||
|
@ -260,7 +262,7 @@ public:
|
||||||
bool hasWiiCrypto() const override { return false; }
|
bool hasWiiCrypto() const override { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<IDiscIO> NewDiscIONFS(SystemStringView path) {
|
std::unique_ptr<IDiscIO> NewDiscIONFS(std::string_view path) {
|
||||||
bool err = false;
|
bool err = false;
|
||||||
auto ret = std::make_unique<DiscIONFS>(path, err);
|
auto ret = std::make_unique<DiscIONFS>(path, err);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -268,4 +270,4 @@ std::unique_ptr<IDiscIO> NewDiscIONFS(SystemStringView path) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace nod
|
|
@ -83,7 +83,7 @@ class DiscIOWBFS : public IDiscIO {
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DiscIOWBFS(SystemStringView fpin) : m_fio(NewFileIO(fpin)) {
|
DiscIOWBFS(std::string_view fpin) : m_fio(NewFileIO(fpin)) {
|
||||||
/* Temporary file handle to read LBA table */
|
/* Temporary file handle to read LBA table */
|
||||||
std::unique_ptr<IFileIO::IReadStream> rs = m_fio->beginReadStream();
|
std::unique_ptr<IFileIO::IReadStream> rs = m_fio->beginReadStream();
|
||||||
if (!rs)
|
if (!rs)
|
||||||
|
@ -275,6 +275,6 @@ public:
|
||||||
std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const override { return {}; }
|
std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const override { return {}; }
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<IDiscIO> NewDiscIOWBFS(SystemStringView path) { return std::make_unique<DiscIOWBFS>(path); }
|
std::unique_ptr<IDiscIO> NewDiscIOWBFS(std::string_view path) { return std::make_unique<DiscIOWBFS>(path); }
|
||||||
|
|
||||||
} // namespace nod
|
} // namespace nod
|
||||||
|
|
134
lib/DiscWii.cpp
134
lib/DiscWii.cpp
|
@ -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, Codepage_t codepage)
|
PartitionWii(const DiscWii& parent, PartitionKind kind, uint64_t offset, bool& err)
|
||||||
: IPartition(parent, kind, true, offset, codepage) {
|
: IPartition(parent, kind, true, offset) {
|
||||||
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;
|
||||||
|
@ -421,7 +421,7 @@ public:
|
||||||
|
|
||||||
uint32_t h3;
|
uint32_t h3;
|
||||||
if (rs->read(&h3, 4) != 4) {
|
if (rs->read(&h3, 4) != 4) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to read H3 offset apploader")));
|
LogModule.report(logvisor::Error, FMT_STRING("unable to read H3 offset apploader"));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
h3 = SBig(h3);
|
h3 = SBig(h3);
|
||||||
|
@ -439,15 +439,15 @@ public:
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool extractCryptoFiles(SystemStringView basePath, const ExtractionContext& ctx) const override {
|
bool extractCryptoFiles(std::string_view basePath, const ExtractionContext& ctx) const override {
|
||||||
Sstat theStat;
|
Sstat theStat;
|
||||||
SystemString basePathStr(basePath);
|
std::string basePathStr(basePath);
|
||||||
|
|
||||||
/* Extract Ticket */
|
/* Extract Ticket */
|
||||||
SystemString ticketPath = basePathStr + _SYS_STR("/ticket.bin");
|
std::string ticketPath = basePathStr + "/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(_SYS_STR("ticket.bin"), 0.f);
|
ctx.progressCB("ticket.bin", 0.f);
|
||||||
auto ws = NewFileIO(ticketPath)->beginWriteStream();
|
auto ws = NewFileIO(ticketPath)->beginWriteStream();
|
||||||
if (!ws)
|
if (!ws)
|
||||||
return false;
|
return false;
|
||||||
|
@ -455,10 +455,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Extract TMD */
|
/* Extract TMD */
|
||||||
SystemString tmdPath = basePathStr + _SYS_STR("/tmd.bin");
|
std::string tmdPath = basePathStr + "/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(_SYS_STR("tmd.bin"), 0.f);
|
ctx.progressCB("tmd.bin", 0.f);
|
||||||
auto ws = NewFileIO(tmdPath)->beginWriteStream();
|
auto ws = NewFileIO(tmdPath)->beginWriteStream();
|
||||||
if (!ws)
|
if (!ws)
|
||||||
return false;
|
return false;
|
||||||
|
@ -466,10 +466,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Extract Certs */
|
/* Extract Certs */
|
||||||
SystemString certPath = basePathStr + _SYS_STR("/cert.bin");
|
std::string certPath = basePathStr + "/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(_SYS_STR("cert.bin"), 0.f);
|
ctx.progressCB("cert.bin", 0.f);
|
||||||
auto ws = NewFileIO(certPath)->beginWriteStream();
|
auto ws = NewFileIO(certPath)->beginWriteStream();
|
||||||
if (!ws)
|
if (!ws)
|
||||||
return false;
|
return false;
|
||||||
|
@ -479,10 +479,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Extract H3 */
|
/* Extract H3 */
|
||||||
SystemString h3Path = basePathStr + _SYS_STR("/h3.bin");
|
std::string h3Path = basePathStr + "/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(_SYS_STR("h3.bin"), 0.f);
|
ctx.progressCB("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, Codepage_t codepage) : DiscBase(std::move(dio), err) {
|
DiscWii::DiscWii(std::unique_ptr<IDiscIO>&& dio, bool& err) : DiscBase(std::move(dio), err) {
|
||||||
if (err)
|
if (err)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -543,31 +543,31 @@ DiscWii::DiscWii(std::unique_ptr<IDiscIO>&& dio, bool& err, Codepage_t codepage)
|
||||||
err = true;
|
err = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_partitions.emplace_back(std::make_unique<PartitionWii>(*this, kind, part.partDataOff << 2, err, codepage));
|
m_partitions.emplace_back(std::make_unique<PartitionWii>(*this, kind, part.partDataOff << 2, err));
|
||||||
if (err)
|
if (err)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscBuilderWii DiscWii::makeMergeBuilder(SystemStringView outPath, bool dualLayer, FProgress progressCB, Codepage_t codepage) {
|
DiscBuilderWii DiscWii::makeMergeBuilder(std::string_view outPath, bool dualLayer, FProgress progressCB) {
|
||||||
return DiscBuilderWii(outPath, dualLayer, progressCB, codepage);
|
return DiscBuilderWii(outPath, dualLayer, progressCB);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DiscWii::extractDiscHeaderFiles(SystemStringView basePath, const ExtractionContext& ctx) const {
|
bool DiscWii::extractDiscHeaderFiles(std::string_view basePath, const ExtractionContext& ctx) const {
|
||||||
SystemString basePathStr(basePath);
|
std::string basePathStr(basePath);
|
||||||
|
|
||||||
if (Mkdir((basePathStr + _SYS_STR("/disc")).c_str(), 0755) && errno != EEXIST) {
|
if (Mkdir((basePathStr + "/disc").c_str(), 0755) && errno != EEXIST) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to mkdir '{}/disc'")), basePathStr);
|
LogModule.report(logvisor::Error, FMT_STRING("unable to mkdir '{}/disc'"), basePathStr);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sstat theStat;
|
Sstat theStat;
|
||||||
|
|
||||||
/* Extract Header */
|
/* Extract Header */
|
||||||
SystemString headerPath = basePathStr + _SYS_STR("/disc/header.bin");
|
std::string headerPath = basePathStr + "/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(_SYS_STR("header.bin"), 0.f);
|
ctx.progressCB("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;
|
||||||
|
@ -580,10 +580,10 @@ bool DiscWii::extractDiscHeaderFiles(SystemStringView basePath, const Extraction
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Extract Region info */
|
/* Extract Region info */
|
||||||
SystemString regionPath = basePathStr + _SYS_STR("/disc/region.bin");
|
std::string regionPath = basePathStr + "/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(_SYS_STR("header.bin"), 0.f);
|
ctx.progressCB("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, Codepage_t codepage)
|
PartitionBuilderWii(DiscBuilderBase& parent, PartitionKind kind, uint64_t baseOffset)
|
||||||
: DiscBuilderBase::PartitionBuilderBase(parent, kind, true, codepage), m_baseOffset(baseOffset), m_aes(NewAES()) {}
|
: DiscBuilderBase::PartitionBuilderBase(parent, kind, true), m_baseOffset(baseOffset), m_aes(NewAES()) {}
|
||||||
|
|
||||||
uint64_t getCurUserEnd() const { return m_curUser; }
|
uint64_t getCurUserEnd() const { return m_curUser; }
|
||||||
|
|
||||||
|
@ -902,7 +902,7 @@ public:
|
||||||
}* bfWindow = (BFWindow*)(tmdData.get() + 0x19A);
|
}* bfWindow = (BFWindow*)(tmdData.get() + 0x19A);
|
||||||
bool good = false;
|
bool good = false;
|
||||||
uint64_t attempts = 0;
|
uint64_t attempts = 0;
|
||||||
SystemString bfName(_SYS_STR("Brute force attempts"));
|
std::string bfName("Brute force attempts");
|
||||||
for (int w = 0; w < 7; ++w) {
|
for (int w = 0; w < 7; ++w) {
|
||||||
for (uint64_t i = 0; i < UINT64_MAX; ++i) {
|
for (uint64_t i = 0; i < UINT64_MAX; ++i) {
|
||||||
bfWindow->word[w] = i;
|
bfWindow->word[w] = i;
|
||||||
|
@ -930,55 +930,55 @@ public:
|
||||||
return m_baseOffset + dataOff + groupCount * 0x200000;
|
return m_baseOffset + dataOff + groupCount * 0x200000;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t buildFromDirectory(SystemStringView dirIn) {
|
uint64_t buildFromDirectory(std::string_view dirIn) {
|
||||||
SystemString dirStr(dirIn);
|
std::string dirStr(dirIn);
|
||||||
SystemString basePath = dirStr + _SYS_STR("/") + getKindString(m_kind);
|
std::string basePath = dirStr + "/" + getKindString(m_kind);
|
||||||
|
|
||||||
/* Check Ticket */
|
/* Check Ticket */
|
||||||
SystemString ticketIn = basePath + _SYS_STR("/ticket.bin");
|
std::string ticketIn = basePath + "/ticket.bin";
|
||||||
Sstat theStat;
|
Sstat theStat;
|
||||||
if (Stat(ticketIn.c_str(), &theStat)) {
|
if (Stat(ticketIn.c_str(), &theStat)) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {}")), ticketIn);
|
LogModule.report(logvisor::Error, FMT_STRING("unable to stat {}"), ticketIn);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check TMD */
|
/* Check TMD */
|
||||||
SystemString tmdIn = basePath + _SYS_STR("/tmd.bin");
|
std::string tmdIn = basePath + "/tmd.bin";
|
||||||
Sstat tmdStat;
|
Sstat tmdStat;
|
||||||
if (Stat(tmdIn.c_str(), &tmdStat)) {
|
if (Stat(tmdIn.c_str(), &tmdStat)) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {}")), tmdIn);
|
LogModule.report(logvisor::Error, FMT_STRING("unable to stat {}"), tmdIn);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check Cert */
|
/* Check Cert */
|
||||||
SystemString certIn = basePath + _SYS_STR("/cert.bin");
|
std::string certIn = basePath + "/cert.bin";
|
||||||
Sstat certStat;
|
Sstat certStat;
|
||||||
if (Stat(certIn.c_str(), &certStat)) {
|
if (Stat(certIn.c_str(), &certStat)) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {}")), certIn);
|
LogModule.report(logvisor::Error, FMT_STRING("unable to stat {}"), certIn);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check Apploader */
|
/* Check Apploader */
|
||||||
SystemString apploaderIn = basePath + _SYS_STR("/sys/apploader.img");
|
std::string apploaderIn = basePath + "/sys/apploader.img";
|
||||||
Sstat apploaderStat;
|
Sstat apploaderStat;
|
||||||
if (Stat(apploaderIn.c_str(), &apploaderStat)) {
|
if (Stat(apploaderIn.c_str(), &apploaderStat)) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {}")), apploaderIn);
|
LogModule.report(logvisor::Error, FMT_STRING("unable to stat {}"), apploaderIn);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check Boot */
|
/* Check Boot */
|
||||||
SystemString bootIn = basePath + _SYS_STR("/sys/boot.bin");
|
std::string bootIn = basePath + "/sys/boot.bin";
|
||||||
Sstat bootStat;
|
Sstat bootStat;
|
||||||
if (Stat(bootIn.c_str(), &bootStat)) {
|
if (Stat(bootIn.c_str(), &bootStat)) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {}")), bootIn);
|
LogModule.report(logvisor::Error, FMT_STRING("unable to stat {}"), bootIn);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check BI2 */
|
/* Check BI2 */
|
||||||
SystemString bi2In = basePath + _SYS_STR("/sys/bi2.bin");
|
std::string bi2In = basePath + "/sys/bi2.bin";
|
||||||
Sstat bi2Stat;
|
Sstat bi2Stat;
|
||||||
if (Stat(bi2In.c_str(), &bi2Stat)) {
|
if (Stat(bi2In.c_str(), &bi2Stat)) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {}")), bi2In);
|
LogModule.report(logvisor::Error, FMT_STRING("unable to stat {}"), bi2In);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1085,7 +1085,7 @@ public:
|
||||||
apploaderStat.st_size);
|
apploaderStat.st_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t mergeFromDirectory(const PartitionWii* partIn, SystemStringView dirIn) {
|
uint64_t mergeFromDirectory(const PartitionWii* partIn, std::string_view dirIn) {
|
||||||
size_t phSz;
|
size_t phSz;
|
||||||
std::unique_ptr<uint8_t[]> phBuf = partIn->readPartitionHeaderBuf(phSz);
|
std::unique_ptr<uint8_t[]> phBuf = partIn->readPartitionHeaderBuf(phSz);
|
||||||
|
|
||||||
|
@ -1125,7 +1125,7 @@ public:
|
||||||
[this, partIn](IPartWriteStream& cws, size_t& xferSz) -> bool {
|
[this, partIn](IPartWriteStream& cws, size_t& xferSz) -> bool {
|
||||||
std::unique_ptr<uint8_t[]> apploaderBuf = partIn->getApploaderBuf();
|
std::unique_ptr<uint8_t[]> apploaderBuf = partIn->getApploaderBuf();
|
||||||
size_t apploaderSz = partIn->getApploaderSize();
|
size_t apploaderSz = partIn->getApploaderSize();
|
||||||
SystemString apploaderName(_SYS_STR("<apploader>"));
|
std::string apploaderName("<apploader>");
|
||||||
cws.write(apploaderBuf.get(), apploaderSz);
|
cws.write(apploaderBuf.get(), apploaderSz);
|
||||||
xferSz += apploaderSz;
|
xferSz += apploaderSz;
|
||||||
if (0x2440 + xferSz >= 0x1F0000) {
|
if (0x2440 + xferSz >= 0x1F0000) {
|
||||||
|
@ -1143,9 +1143,9 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
EBuildResult DiscBuilderWii::buildFromDirectory(SystemStringView dirIn) {
|
EBuildResult DiscBuilderWii::buildFromDirectory(std::string_view dirIn) {
|
||||||
SystemString dirStr(dirIn);
|
std::string dirStr(dirIn);
|
||||||
SystemString basePath = SystemString(dirStr) + _SYS_STR("/") + getKindString(PartitionKind::Data);
|
std::string basePath = std::string(dirStr) + "/" + getKindString(PartitionKind::Data);
|
||||||
|
|
||||||
PartitionBuilderWii& pb = static_cast<PartitionBuilderWii&>(*m_partitions[0]);
|
PartitionBuilderWii& pb = static_cast<PartitionBuilderWii&>(*m_partitions[0]);
|
||||||
uint64_t filledSz = pb.m_baseOffset;
|
uint64_t filledSz = pb.m_baseOffset;
|
||||||
|
@ -1153,10 +1153,10 @@ EBuildResult DiscBuilderWii::buildFromDirectory(SystemStringView dirIn) {
|
||||||
return EBuildResult::Failed;
|
return EBuildResult::Failed;
|
||||||
|
|
||||||
if (!CheckFreeSpace(m_outPath.c_str(), m_discCapacity)) {
|
if (!CheckFreeSpace(m_outPath.c_str(), m_discCapacity)) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("not enough free disk space for {}")), m_outPath);
|
LogModule.report(logvisor::Error, FMT_STRING("not enough free disk space for {}"), m_outPath);
|
||||||
return EBuildResult::DiskFull;
|
return EBuildResult::DiskFull;
|
||||||
}
|
}
|
||||||
m_progressCB(getProgressFactor(), _SYS_STR("Preallocating image"), -1);
|
m_progressCB(getProgressFactor(), "Preallocating image", -1);
|
||||||
++m_progressIdx;
|
++m_progressIdx;
|
||||||
{
|
{
|
||||||
std::unique_ptr<IFileIO::IWriteStream> ws = m_fileIO->beginWriteStream(0);
|
std::unique_ptr<IFileIO::IWriteStream> ws = m_fileIO->beginWriteStream(0);
|
||||||
|
@ -1176,14 +1176,14 @@ EBuildResult DiscBuilderWii::buildFromDirectory(SystemStringView dirIn) {
|
||||||
return EBuildResult::Failed;
|
return EBuildResult::Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_progressCB(getProgressFactor(), _SYS_STR("Finishing Disc"), -1);
|
m_progressCB(getProgressFactor(), "Finishing Disc", -1);
|
||||||
++m_progressIdx;
|
++m_progressIdx;
|
||||||
|
|
||||||
/* Populate disc header */
|
/* Populate disc header */
|
||||||
std::unique_ptr<IFileIO::IWriteStream> ws = m_fileIO->beginWriteStream(0);
|
std::unique_ptr<IFileIO::IWriteStream> ws = m_fileIO->beginWriteStream(0);
|
||||||
if (!ws)
|
if (!ws)
|
||||||
return EBuildResult::Failed;
|
return EBuildResult::Failed;
|
||||||
SystemString headerPath = basePath + _SYS_STR("/disc/header.bin");
|
std::string headerPath = basePath + "/disc/header.bin";
|
||||||
std::unique_ptr<IFileIO::IReadStream> rs = NewFileIO(headerPath.c_str())->beginReadStream();
|
std::unique_ptr<IFileIO::IReadStream> rs = NewFileIO(headerPath.c_str())->beginReadStream();
|
||||||
if (!rs)
|
if (!rs)
|
||||||
return EBuildResult::Failed;
|
return EBuildResult::Failed;
|
||||||
|
@ -1205,7 +1205,7 @@ EBuildResult DiscBuilderWii::buildFromDirectory(SystemStringView dirIn) {
|
||||||
ws->write(vals, 4);
|
ws->write(vals, 4);
|
||||||
|
|
||||||
/* Populate region info */
|
/* Populate region info */
|
||||||
SystemString regionPath = basePath + _SYS_STR("/disc/region.bin");
|
std::string regionPath = basePath + "/disc/region.bin";
|
||||||
rs = NewFileIO(regionPath.c_str())->beginReadStream();
|
rs = NewFileIO(regionPath.c_str())->beginReadStream();
|
||||||
if (!rs)
|
if (!rs)
|
||||||
return EBuildResult::Failed;
|
return EBuildResult::Failed;
|
||||||
|
@ -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, Codepage_t codepage) {
|
std::optional<uint64_t> DiscBuilderWii::CalculateTotalSizeRequired(std::string_view dirIn, bool& dualLayer) {
|
||||||
std::optional<uint64_t> sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeBuild(dirIn, PartitionKind::Data, true, codepage);
|
std::optional<uint64_t> sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeBuild(dirIn, PartitionKind::Data, true);
|
||||||
if (!sz)
|
if (!sz)
|
||||||
return sz;
|
return sz;
|
||||||
auto szDiv = nod::div(*sz, uint64_t(0x1F0000));
|
auto szDiv = nod::div(*sz, uint64_t(0x1F0000));
|
||||||
|
@ -1246,31 +1246,31 @@ std::optional<uint64_t> DiscBuilderWii::CalculateTotalSizeRequired(SystemStringV
|
||||||
*sz += 0x200000;
|
*sz += 0x200000;
|
||||||
dualLayer = (sz > 0x118240000);
|
dualLayer = (sz > 0x118240000);
|
||||||
if (sz > 0x1FB4E0000) {
|
if (sz > 0x1FB4E0000) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("disc capacity exceeded [{} / {}]")), *sz, 0x1FB4E0000);
|
LogModule.report(logvisor::Error, FMT_STRING("disc capacity exceeded [{} / {}]"), *sz, 0x1FB4E0000);
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
return sz;
|
return sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscBuilderWii::DiscBuilderWii(SystemStringView outPath, bool dualLayer, FProgress progressCB, Codepage_t codepage)
|
DiscBuilderWii::DiscBuilderWii(std::string_view outPath, bool dualLayer, FProgress progressCB)
|
||||||
: DiscBuilderBase(outPath, dualLayer ? 0x1FB4E0000 : 0x118240000, progressCB) {
|
: DiscBuilderBase(outPath, dualLayer ? 0x1FB4E0000 : 0x118240000, progressCB) {
|
||||||
m_partitions.emplace_back(std::make_unique<PartitionBuilderWii>(*this, PartitionKind::Data, 0x200000, codepage));
|
m_partitions.emplace_back(std::make_unique<PartitionBuilderWii>(*this, PartitionKind::Data, 0x200000));
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscMergerWii::DiscMergerWii(SystemStringView outPath, DiscWii& sourceDisc, bool dualLayer, FProgress progressCB, Codepage_t codepage)
|
DiscMergerWii::DiscMergerWii(std::string_view outPath, DiscWii& sourceDisc, bool dualLayer, FProgress progressCB)
|
||||||
: m_sourceDisc(sourceDisc), m_builder(sourceDisc.makeMergeBuilder(outPath, dualLayer, progressCB, codepage)) {}
|
: m_sourceDisc(sourceDisc), m_builder(sourceDisc.makeMergeBuilder(outPath, dualLayer, progressCB)) {}
|
||||||
|
|
||||||
EBuildResult DiscMergerWii::mergeFromDirectory(SystemStringView dirIn) {
|
EBuildResult DiscMergerWii::mergeFromDirectory(std::string_view dirIn) {
|
||||||
PartitionBuilderWii& pb = static_cast<PartitionBuilderWii&>(*m_builder.m_partitions[0]);
|
PartitionBuilderWii& pb = static_cast<PartitionBuilderWii&>(*m_builder.m_partitions[0]);
|
||||||
uint64_t filledSz = pb.m_baseOffset;
|
uint64_t filledSz = pb.m_baseOffset;
|
||||||
if (!m_builder.m_fileIO->beginWriteStream())
|
if (!m_builder.m_fileIO->beginWriteStream())
|
||||||
return EBuildResult::Failed;
|
return EBuildResult::Failed;
|
||||||
|
|
||||||
if (!CheckFreeSpace(m_builder.m_outPath.c_str(), m_builder.m_discCapacity)) {
|
if (!CheckFreeSpace(m_builder.m_outPath.c_str(), m_builder.m_discCapacity)) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("not enough free disk space for {}")), m_builder.m_outPath);
|
LogModule.report(logvisor::Error, FMT_STRING("not enough free disk space for {}"), m_builder.m_outPath);
|
||||||
return EBuildResult::DiskFull;
|
return EBuildResult::DiskFull;
|
||||||
}
|
}
|
||||||
m_builder.m_progressCB(m_builder.getProgressFactor(), _SYS_STR("Preallocating image"), -1);
|
m_builder.m_progressCB(m_builder.getProgressFactor(), "Preallocating image", -1);
|
||||||
++m_builder.m_progressIdx;
|
++m_builder.m_progressIdx;
|
||||||
{
|
{
|
||||||
std::unique_ptr<IFileIO::IWriteStream> ws = m_builder.m_fileIO->beginWriteStream(0);
|
std::unique_ptr<IFileIO::IWriteStream> ws = m_builder.m_fileIO->beginWriteStream(0);
|
||||||
|
@ -1290,7 +1290,7 @@ EBuildResult DiscMergerWii::mergeFromDirectory(SystemStringView dirIn) {
|
||||||
return EBuildResult::Failed;
|
return EBuildResult::Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_builder.m_progressCB(m_builder.getProgressFactor(), _SYS_STR("Finishing Disc"), -1);
|
m_builder.m_progressCB(m_builder.getProgressFactor(), "Finishing Disc", -1);
|
||||||
++m_builder.m_progressIdx;
|
++m_builder.m_progressIdx;
|
||||||
|
|
||||||
/* Populate disc header */
|
/* Populate disc header */
|
||||||
|
@ -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, Codepage_t codepage) {
|
std::optional<uint64_t> DiscMergerWii::CalculateTotalSizeRequired(DiscWii& sourceDisc, std::string_view dirIn, bool& dualLayer) {
|
||||||
std::optional<uint64_t> sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeMerge(sourceDisc.getDataPartition(), dirIn, codepage);
|
std::optional<uint64_t> sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeMerge(sourceDisc.getDataPartition(), dirIn);
|
||||||
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));
|
||||||
|
@ -1353,7 +1353,7 @@ std::optional<uint64_t> DiscMergerWii::CalculateTotalSizeRequired(DiscWii& sourc
|
||||||
*sz += 0x200000;
|
*sz += 0x200000;
|
||||||
dualLayer = (sz > 0x118240000);
|
dualLayer = (sz > 0x118240000);
|
||||||
if (sz > 0x1FB4E0000) {
|
if (sz > 0x1FB4E0000) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("disc capacity exceeded [{} / {}]")), *sz, 0x1FB4E0000);
|
LogModule.report(logvisor::Error, FMT_STRING("disc capacity exceeded [{} / {}]"), *sz, 0x1FB4E0000);
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
return sz;
|
return sz;
|
||||||
|
|
|
@ -11,14 +11,14 @@
|
||||||
namespace nod {
|
namespace nod {
|
||||||
|
|
||||||
class FileIOFILE : public IFileIO {
|
class FileIOFILE : public IFileIO {
|
||||||
SystemString m_path;
|
std::string m_path;
|
||||||
int64_t m_maxWriteSize;
|
int64_t m_maxWriteSize;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FileIOFILE(SystemStringView path, int64_t maxWriteSize) : m_path(path), m_maxWriteSize(maxWriteSize) {}
|
FileIOFILE(std::string_view path, int64_t maxWriteSize) : m_path(path), m_maxWriteSize(maxWriteSize) {}
|
||||||
|
|
||||||
bool exists() override {
|
bool exists() override {
|
||||||
FILE* fp = Fopen(m_path.c_str(), _SYS_STR("rb"));
|
FILE* fp = Fopen(m_path.c_str(), "rb");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return false;
|
return false;
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
@ -26,7 +26,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t size() override {
|
uint64_t size() override {
|
||||||
FILE* fp = Fopen(m_path.c_str(), _SYS_STR("rb"));
|
FILE* fp = Fopen(m_path.c_str(), "rb");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return 0;
|
return 0;
|
||||||
FSeek(fp, 0, SEEK_END);
|
FSeek(fp, 0, SEEK_END);
|
||||||
|
@ -38,33 +38,33 @@ public:
|
||||||
struct WriteStream : public IFileIO::IWriteStream {
|
struct WriteStream : public IFileIO::IWriteStream {
|
||||||
FILE* fp;
|
FILE* fp;
|
||||||
int64_t m_maxWriteSize;
|
int64_t m_maxWriteSize;
|
||||||
WriteStream(SystemStringView path, int64_t maxWriteSize, bool& err) : m_maxWriteSize(maxWriteSize) {
|
WriteStream(std::string_view path, int64_t maxWriteSize, bool& err) : m_maxWriteSize(maxWriteSize) {
|
||||||
fp = Fopen(path.data(), _SYS_STR("wb"));
|
fp = Fopen(path.data(), "wb");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to open '{}' for writing")), path);
|
LogModule.report(logvisor::Error, FMT_STRING("unable to open '{}' for writing"), path);
|
||||||
err = true;
|
err = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WriteStream(SystemStringView path, uint64_t offset, int64_t maxWriteSize, bool& err)
|
WriteStream(std::string_view path, uint64_t offset, int64_t maxWriteSize, bool& err)
|
||||||
: m_maxWriteSize(maxWriteSize) {
|
: m_maxWriteSize(maxWriteSize) {
|
||||||
fp = Fopen(path.data(), _SYS_STR("ab"));
|
fp = Fopen(path.data(), "ab");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
goto FailLoc;
|
goto FailLoc;
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
fp = Fopen(path.data(), _SYS_STR("r+b"));
|
fp = Fopen(path.data(), "r+b");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
goto FailLoc;
|
goto FailLoc;
|
||||||
FSeek(fp, offset, SEEK_SET);
|
FSeek(fp, offset, SEEK_SET);
|
||||||
return;
|
return;
|
||||||
FailLoc:
|
FailLoc:
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to open '{}' for writing")), path);
|
LogModule.report(logvisor::Error, FMT_STRING("unable to open '{}' for writing"), path);
|
||||||
err = true;
|
err = true;
|
||||||
}
|
}
|
||||||
~WriteStream() override { fclose(fp); }
|
~WriteStream() override { fclose(fp); }
|
||||||
uint64_t write(const void* buf, uint64_t length) override {
|
uint64_t write(const void* buf, uint64_t length) override {
|
||||||
if (m_maxWriteSize >= 0) {
|
if (m_maxWriteSize >= 0) {
|
||||||
if (FTell(fp) + length > m_maxWriteSize) {
|
if (FTell(fp) + length > m_maxWriteSize) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("write operation exceeds file's {}-byte limit")),
|
LogModule.report(logvisor::Error, FMT_STRING("write operation exceeds file's {}-byte limit"),
|
||||||
m_maxWriteSize);
|
m_maxWriteSize);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -95,14 +95,14 @@ public:
|
||||||
|
|
||||||
struct ReadStream : public IFileIO::IReadStream {
|
struct ReadStream : public IFileIO::IReadStream {
|
||||||
FILE* fp;
|
FILE* fp;
|
||||||
ReadStream(SystemStringView path, bool& err) {
|
ReadStream(std::string_view path, bool& err) {
|
||||||
fp = Fopen(path.data(), _SYS_STR("rb"));
|
fp = Fopen(path.data(), "rb");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
err = true;
|
err = true;
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to open '{}' for reading")), path);
|
LogModule.report(logvisor::Error, FMT_STRING("unable to open '{}' for reading"), path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ReadStream(SystemStringView path, uint64_t offset, bool& err) : ReadStream(path, err) {
|
ReadStream(std::string_view path, uint64_t offset, bool& err) : ReadStream(path, err) {
|
||||||
if (err)
|
if (err)
|
||||||
return;
|
return;
|
||||||
FSeek(fp, offset, SEEK_SET);
|
FSeek(fp, offset, SEEK_SET);
|
||||||
|
@ -152,7 +152,7 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<IFileIO> NewFileIO(SystemStringView path, int64_t maxWriteSize) {
|
std::unique_ptr<IFileIO> NewFileIO(std::string_view path, int64_t maxWriteSize) {
|
||||||
return std::make_unique<FileIOFILE>(path, maxWriteSize);
|
return std::make_unique<FileIOFILE>(path, maxWriteSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,21 +8,26 @@
|
||||||
|
|
||||||
#include <logvisor/logvisor.hpp>
|
#include <logvisor/logvisor.hpp>
|
||||||
|
|
||||||
|
#include <nowide/convert.hpp>
|
||||||
|
#include <nowide/stackstring.hpp>
|
||||||
|
|
||||||
namespace nod {
|
namespace nod {
|
||||||
|
|
||||||
class FileIOWin32 : public IFileIO {
|
class FileIOWin32 : public IFileIO {
|
||||||
SystemString m_path;
|
std::wstring m_wpath;
|
||||||
int64_t m_maxWriteSize;
|
int64_t m_maxWriteSize;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FileIOWin32(SystemStringView path, int64_t maxWriteSize) : m_path(path), m_maxWriteSize(maxWriteSize) {}
|
FileIOWin32(std::string_view path, int64_t maxWriteSize)
|
||||||
|
: m_wpath(nowide::widen(path))
|
||||||
|
, m_maxWriteSize(maxWriteSize) {}
|
||||||
|
|
||||||
bool exists() override {
|
bool exists() override {
|
||||||
#if !WINDOWS_STORE
|
#if !WINDOWS_STORE
|
||||||
HANDLE fp = CreateFileW(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
|
HANDLE fp = CreateFileW(m_wpath.data(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
|
||||||
FILE_ATTRIBUTE_NORMAL, nullptr);
|
FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
#else
|
#else
|
||||||
HANDLE fp = CreateFile2(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr);
|
HANDLE fp = CreateFile2(m_path.get(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr);
|
||||||
#endif
|
#endif
|
||||||
if (fp == INVALID_HANDLE_VALUE)
|
if (fp == INVALID_HANDLE_VALUE)
|
||||||
return false;
|
return false;
|
||||||
|
@ -32,10 +37,10 @@ public:
|
||||||
|
|
||||||
uint64_t size() override {
|
uint64_t size() override {
|
||||||
#if !WINDOWS_STORE
|
#if !WINDOWS_STORE
|
||||||
HANDLE fp = CreateFileW(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
|
HANDLE fp = CreateFileW(m_wpath.data(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
|
||||||
FILE_ATTRIBUTE_NORMAL, nullptr);
|
FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
#else
|
#else
|
||||||
HANDLE fp = CreateFile2(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr);
|
HANDLE fp = CreateFile2(m_path.get(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr);
|
||||||
#endif
|
#endif
|
||||||
if (fp == INVALID_HANDLE_VALUE)
|
if (fp == INVALID_HANDLE_VALUE)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -51,28 +56,30 @@ public:
|
||||||
struct WriteStream : public IFileIO::IWriteStream {
|
struct WriteStream : public IFileIO::IWriteStream {
|
||||||
HANDLE fp;
|
HANDLE fp;
|
||||||
int64_t m_maxWriteSize;
|
int64_t m_maxWriteSize;
|
||||||
WriteStream(SystemStringView path, int64_t maxWriteSize, bool& err) : m_maxWriteSize(maxWriteSize) {
|
WriteStream(std::wstring_view wpath, int64_t maxWriteSize, bool& err) : m_maxWriteSize(maxWriteSize) {
|
||||||
#if !WINDOWS_STORE
|
#if !WINDOWS_STORE
|
||||||
fp = CreateFileW(path.data(), GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
|
fp = CreateFileW(wpath.data(), GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
|
||||||
nullptr);
|
nullptr);
|
||||||
#else
|
#else
|
||||||
fp = CreateFile2(path.data(), GENERIC_WRITE, FILE_SHARE_WRITE, CREATE_ALWAYS, nullptr);
|
fp = CreateFile2(wpath.data(), GENERIC_WRITE, FILE_SHARE_WRITE, CREATE_ALWAYS, nullptr);
|
||||||
#endif
|
#endif
|
||||||
if (fp == INVALID_HANDLE_VALUE) {
|
if (fp == INVALID_HANDLE_VALUE) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to open '{}' for writing")), path);
|
const nowide::stackstring path(wpath.data(), wpath.data() + wpath.size());
|
||||||
|
LogModule.report(logvisor::Error, FMT_STRING("unable to open '{}' for writing"), path.get());
|
||||||
err = true;
|
err = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WriteStream(SystemStringView path, uint64_t offset, int64_t maxWriteSize, bool& err)
|
WriteStream(std::wstring_view wpath, uint64_t offset, int64_t maxWriteSize, bool& err)
|
||||||
: m_maxWriteSize(maxWriteSize) {
|
: m_maxWriteSize(maxWriteSize) {
|
||||||
#if !WINDOWS_STORE
|
#if !WINDOWS_STORE
|
||||||
fp = CreateFileW(path.data(), GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
|
fp = CreateFileW(wpath.data(), GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
|
||||||
nullptr);
|
nullptr);
|
||||||
#else
|
#else
|
||||||
fp = CreateFile2(path.data(), GENERIC_WRITE, FILE_SHARE_WRITE, OPEN_ALWAYS, nullptr);
|
fp = CreateFile2(wpath.data(), GENERIC_WRITE, FILE_SHARE_WRITE, OPEN_ALWAYS, nullptr);
|
||||||
#endif
|
#endif
|
||||||
if (fp == INVALID_HANDLE_VALUE) {
|
if (fp == INVALID_HANDLE_VALUE) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to open '{}' for writing")), path);
|
const nowide::stackstring path(wpath.data(), wpath.data() + wpath.size());
|
||||||
|
LogModule.report(logvisor::Error, FMT_STRING("unable to open '{}' for writing"), path.get());
|
||||||
err = true;
|
err = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -87,7 +94,7 @@ public:
|
||||||
LARGE_INTEGER res;
|
LARGE_INTEGER res;
|
||||||
SetFilePointerEx(fp, li, &res, FILE_CURRENT);
|
SetFilePointerEx(fp, li, &res, FILE_CURRENT);
|
||||||
if (res.QuadPart + int64_t(length) > m_maxWriteSize) {
|
if (res.QuadPart + int64_t(length) > m_maxWriteSize) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("write operation exceeds file's {}-byte limit")),
|
LogModule.report(logvisor::Error, FMT_STRING("write operation exceeds file's {}-byte limit"),
|
||||||
m_maxWriteSize);
|
m_maxWriteSize);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -100,7 +107,7 @@ public:
|
||||||
};
|
};
|
||||||
std::unique_ptr<IWriteStream> beginWriteStream() const override {
|
std::unique_ptr<IWriteStream> beginWriteStream() const override {
|
||||||
bool err = false;
|
bool err = false;
|
||||||
auto ret = std::make_unique<WriteStream>(m_path, m_maxWriteSize, err);
|
auto ret = std::make_unique<WriteStream>(m_wpath, m_maxWriteSize, err);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -110,7 +117,7 @@ public:
|
||||||
}
|
}
|
||||||
std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const override {
|
std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const override {
|
||||||
bool err = false;
|
bool err = false;
|
||||||
auto ret = std::make_unique<WriteStream>(m_path, offset, m_maxWriteSize, err);
|
auto ret = std::make_unique<WriteStream>(m_wpath, offset, m_maxWriteSize, err);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -121,19 +128,20 @@ public:
|
||||||
|
|
||||||
struct ReadStream : public IFileIO::IReadStream {
|
struct ReadStream : public IFileIO::IReadStream {
|
||||||
HANDLE fp;
|
HANDLE fp;
|
||||||
ReadStream(SystemStringView path, bool& err) {
|
ReadStream(std::wstring_view wpath, bool& err) {
|
||||||
#if !WINDOWS_STORE
|
#if !WINDOWS_STORE
|
||||||
fp = CreateFileW(path.data(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
|
fp = CreateFileW(wpath.data(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
|
||||||
nullptr);
|
nullptr);
|
||||||
#else
|
#else
|
||||||
fp = CreateFile2(path.data(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr);
|
fp = CreateFile2(wpath.data(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr);
|
||||||
#endif
|
#endif
|
||||||
if (fp == INVALID_HANDLE_VALUE) {
|
if (fp == INVALID_HANDLE_VALUE) {
|
||||||
err = true;
|
err = true;
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to open '{}' for reading")), path);
|
const nowide::stackstring path(wpath.data(), wpath.data() + wpath.size());
|
||||||
|
LogModule.report(logvisor::Error, FMT_STRING("unable to open '{}' for reading"), path.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ReadStream(SystemStringView path, uint64_t offset, bool& err) : ReadStream(path, err) {
|
ReadStream(std::wstring_view wpath, uint64_t offset, bool& err) : ReadStream(wpath, err) {
|
||||||
if (err)
|
if (err)
|
||||||
return;
|
return;
|
||||||
LARGE_INTEGER lioffset;
|
LARGE_INTEGER lioffset;
|
||||||
|
@ -179,7 +187,7 @@ public:
|
||||||
|
|
||||||
std::unique_ptr<IReadStream> beginReadStream() const override {
|
std::unique_ptr<IReadStream> beginReadStream() const override {
|
||||||
bool err = false;
|
bool err = false;
|
||||||
auto ret = std::make_unique<ReadStream>(m_path, err);
|
auto ret = std::make_unique<ReadStream>(m_wpath, err);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -190,7 +198,7 @@ public:
|
||||||
|
|
||||||
std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const override {
|
std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const override {
|
||||||
bool err = false;
|
bool err = false;
|
||||||
auto ret = std::make_unique<ReadStream>(m_path, offset, err);
|
auto ret = std::make_unique<ReadStream>(m_wpath, offset, err);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -200,7 +208,7 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<IFileIO> NewFileIO(SystemStringView path, int64_t maxWriteSize) {
|
std::unique_ptr<IFileIO> NewFileIO(std::string_view path, int64_t maxWriteSize) {
|
||||||
return std::make_unique<FileIOWin32>(path, maxWriteSize);
|
return std::make_unique<FileIOWin32>(path, maxWriteSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
32
lib/nod.cpp
32
lib/nod.cpp
|
@ -10,15 +10,15 @@ namespace nod {
|
||||||
|
|
||||||
logvisor::Module LogModule("nod");
|
logvisor::Module LogModule("nod");
|
||||||
|
|
||||||
std::unique_ptr<IDiscIO> NewDiscIOISO(SystemStringView path);
|
std::unique_ptr<IDiscIO> NewDiscIOISO(std::string_view path);
|
||||||
std::unique_ptr<IDiscIO> NewDiscIOWBFS(SystemStringView path);
|
std::unique_ptr<IDiscIO> NewDiscIOWBFS(std::string_view path);
|
||||||
std::unique_ptr<IDiscIO> NewDiscIONFS(SystemStringView path);
|
std::unique_ptr<IDiscIO> NewDiscIONFS(std::string_view path);
|
||||||
|
|
||||||
std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path, bool& isWii, Codepage_t codepage) {
|
std::unique_ptr<DiscBase> OpenDiscFromImage(std::string_view path, bool& isWii) {
|
||||||
/* 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()) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("Unable to open '{}'")), path);
|
LogModule.report(logvisor::Error, FMT_STRING("Unable to open '{}'"), path);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
std::unique_ptr<IFileIO::IReadStream> rs = fio->beginReadStream();
|
std::unique_ptr<IFileIO::IReadStream> rs = fio->beginReadStream();
|
||||||
|
@ -29,19 +29,19 @@ std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path, bool& isWii,
|
||||||
std::unique_ptr<IDiscIO> discIO;
|
std::unique_ptr<IDiscIO> discIO;
|
||||||
uint32_t magic = 0;
|
uint32_t magic = 0;
|
||||||
if (rs->read(&magic, 4) != 4) {
|
if (rs->read(&magic, 4) != 4) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("Unable to read magic from '{}'")), path);
|
LogModule.report(logvisor::Error, FMT_STRING("Unable to read magic from '{}'"), path);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
using SignedSize = std::make_signed<SystemString::size_type>::type;
|
using SignedSize = std::make_signed<std::string::size_type>::type;
|
||||||
const auto dotPos = SignedSize(path.rfind(_SYS_STR('.')));
|
const auto dotPos = SignedSize(path.rfind('.'));
|
||||||
const auto slashPos = SignedSize(path.find_last_of(_SYS_STR("/\\")));
|
const auto slashPos = SignedSize(path.find_last_of("/\\"));
|
||||||
if (magic == nod::SBig((uint32_t)'WBFS')) {
|
if (magic == nod::SBig((uint32_t)'WBFS')) {
|
||||||
discIO = NewDiscIOWBFS(path);
|
discIO = NewDiscIOWBFS(path);
|
||||||
isWii = true;
|
isWii = true;
|
||||||
} else if (path.size() > 4 && dotPos != -1 && dotPos > slashPos &&
|
} else if (path.size() > 4 && dotPos != -1 && dotPos > slashPos &&
|
||||||
!path.compare(slashPos + 1, 4, _SYS_STR("hif_")) &&
|
!path.compare(slashPos + 1, 4, "hif_") &&
|
||||||
!path.compare(dotPos, path.size() - dotPos, _SYS_STR(".nfs"))) {
|
!path.compare(dotPos, path.size() - dotPos, ".nfs")) {
|
||||||
discIO = NewDiscIONFS(path);
|
discIO = NewDiscIONFS(path);
|
||||||
isWii = true;
|
isWii = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -60,28 +60,28 @@ std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path, bool& isWii,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!discIO) {
|
if (!discIO) {
|
||||||
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("'{}' is not a valid image")), path);
|
LogModule.report(logvisor::Error, FMT_STRING("'{}' is not a valid image"), path);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
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, codepage);
|
ret = std::make_unique<DiscWii>(std::move(discIO), err);
|
||||||
if (err)
|
if (err)
|
||||||
return {};
|
return {};
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = std::make_unique<DiscGCN>(std::move(discIO), err, codepage);
|
ret = std::make_unique<DiscGCN>(std::move(discIO), err);
|
||||||
if (err)
|
if (err)
|
||||||
return {};
|
return {};
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path) {
|
std::unique_ptr<DiscBase> OpenDiscFromImage(std::string_view path) {
|
||||||
bool isWii;
|
bool isWii;
|
||||||
return OpenDiscFromImage(path, isWii, CP_US_ASCII);
|
return OpenDiscFromImage(path, isWii);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace nod
|
} // namespace nod
|
||||||
|
|
2
logvisor
2
logvisor
|
@ -1 +1 @@
|
||||||
Subproject commit 274ad5ef07e0d658ee5281f11cc19bf168f7d4c6
|
Subproject commit df3c283186a677d178b61240003ec4114e9a925b
|
Loading…
Reference in New Issue