92 Commits
v1.0 ... hsh

Author SHA1 Message Date
bad0f06254 devkitA64 compilation fixes 2020-10-21 00:39:16 -04:00
9a10e58f8d Update logvisor 2020-10-21 00:38:29 -04:00
Jack Andersen
1d61a211f2 Update logvisor 2020-09-28 10:53:07 -10:00
Jack Andersen
2783337c36 Update fmtlib 2020-04-11 12:45:06 -10:00
Jack Andersen
dffcac50c5 Exclude CMake CXX standard from MSVC 2020-04-10 19:00:19 -10:00
Jack Andersen
f147e12356 Windows build fixes 2019-11-24 15:17:57 -10:00
Jack Andersen
48a2981a93 Shared NFS data class not necessary 2019-11-24 13:47:48 -10:00
Jack Andersen
19604b2a3b Use correct slash finding function 2019-11-23 20:25:29 -10:00
Jack Andersen
c1a1d1abc8 Use logical block for iv 2019-11-23 20:00:48 -10:00
Jack Andersen
6bf4f07129 Consistent variable names for blocks 2019-11-23 17:29:57 -10:00
Jack Andersen
75fc574f81 Support for Wii U VC NFS images 2019-11-23 17:24:33 -10:00
Jack Andersen
11a0351d1c Merge branch 'master' of ssh://git.axiodl.com:6431/AxioDL/nod 2019-09-30 21:30:57 -10:00
Jack Andersen
4ec6c6697b Update logvisor 2019-09-30 21:30:42 -10:00
ba0c2b7843 Merge pull request #14 from lioncash/athena
General: Be explicit about athena's SeekOrigin type
2019-09-08 17:51:25 -07:00
Lioncash
221bc7c7f2 General: Be explicit about athena's SeekOrigin type
Allows this code to function if the enum is turned into an enum class.
2019-09-08 17:29:38 -04:00
acdadaf963 Merge pull request #5 from henriquegemignani/optional
Use std::optional for CalculateTotalSizeBuild
2019-09-07 01:18:43 -07:00
d658909948 Update athena 2019-09-06 23:31:44 -07:00
Henrique Gemignani Passos Lima
091262ace1 Use std::optional for CalculateTotalSizeBuild 2019-09-06 22:17:06 +02:00
97cfcea14e Merge pull request #13 from lioncash/overrun
DiscBase: Prevent potential off-by-one case within getPartitonNodeCount()
2019-09-05 19:35:01 -07:00
Lioncash
f5c3cbdcd7 DiscBase: Amend typo within getPartitonNodeCount() name
Adds an extra 'i' to correct a typo.
2019-09-05 21:57:44 -04:00
Lioncash
7ddff919c1 DiscBase: Prevent potential off-by-one case within getPartitonNodeCount()
We should be comparing with >= instead of >.
2019-09-05 21:56:49 -04:00
Lioncash
4bba7af2c2 DiscBase: std::move std::function instance
std::function isn't a trivial type (it's allowed to heap allocate to
store any necessary captures), so we can move it in the constructor to
avoid any unnecessary allocations
2019-09-05 21:52:43 -04:00
Lioncash
f443b60bde DiscBase: Mark member functions as const where applicable
These don't modify instance state, so they can be marked as const.
2019-09-05 21:51:20 -04:00
Lioncash
998d6a77c3 General: Remove redundant inline keyword
Functions defined within the class declaration are already inline by
default, so we don't need to specify the keyword here.
2019-09-05 21:48:07 -04:00
55301dd505 Merge pull request #11 from lioncash/make
General: Use std::make_unique where applicable
2019-08-30 16:28:53 -07:00
793413540d Merge pull request #12 from lioncash/fmt
FileIOWin32: Amend fmt format strings
2019-08-30 16:28:45 -07:00
Lioncash
f11eb728bf FileIOWin32: Amend fmt format strings
Amends a few stragglers from the transition to fmtlib.
2019-08-30 05:40:00 -04:00
Lioncash
a8753e273f General: Use std::make_unique where applicable
Makes for a little less reading in certain cases.
2019-08-30 05:35:12 -04:00
63264695b0 Merge pull request #9 from lioncash/include
General: Include headers directly where necessary
2019-08-30 02:13:24 -07:00
edc31b2107 Merge pull request #10 from lioncash/cmake
CMakeLists: Minor cleanup
2019-08-30 02:13:13 -07:00
Lioncash
1b3bb7815d CMakeLists: Move lib-specific CMake commands into the lib folder
Keeps a clear division between the lib and the driver CMake code.
2019-08-30 04:53:05 -04:00
Lioncash
89df98ee96 CMakeLists: Eliminate glob statement
Avoids a top-level variable from being defined and adds the source files
explicitly to the target like our other targets.
2019-08-30 04:43:56 -04:00
Lioncash
5935e84dab General: Include headers directly where necessary
Ensures includes are explicitly included where necessary to avoid
indirect inclusions.
2019-08-30 04:34:49 -04:00
df1e450728 Update logvisor 2019-08-26 15:56:48 -07:00
c9bf821285 Update logvisor 2019-08-17 23:00:24 -07:00
Jack Andersen
18b297e312 Merge pull request #8 from lioncash/cmake
CMakeLists: Migrate off directly modifying CMAKE_CXX_FLAGS
2019-08-10 09:30:26 -07:00
255a37216f Merge branch 'override' of git://github.com/lioncash/nod into lioncash-override 2019-08-09 23:14:32 -07:00
7da7761afb Merge branch 'lioncash-null-term' 2019-08-09 23:14:09 -07:00
Lioncash
876a2ccf81 CMakeLists: Migrate off directly modifying CMAKE_CXX_FLAGS
We can simply apply the compilation options directly to the target. We
can perform equivalent behavior for conditionally adding sources to the
target instead of assigning to a variable as well.
2019-08-10 01:52:27 -04:00
Lioncash
2171388b9d General: Make use of override where applicable
Makes it explicit where functions are being overridden in derived
classes/structs.
2019-08-10 01:41:44 -04:00
Lioncash
a572439967 DirectoryEnumerator: Handle non-null-terminated strings in CaseInsensitiveCompare
std::string_view instances aren't required to be null terminated. Given
this, we can make the functions a little safer by performing an explicit
bounded comparison on the range of characters, making the code more
generic with regards to handling the underlying string data.
2019-08-10 01:16:21 -04:00
Jack Andersen
ac6f2a1ed2 update logvisor 2019-07-27 15:20:43 -10:00
Jack Andersen
37792ba116 Massive libfmt refactor 2019-07-19 18:21:57 -10:00
d9b6be8446 Compile fixes 2019-06-20 15:45:35 -07:00
Jack Andersen
47322b9496 Refactor of CMake for cleaner dependency handling 2019-06-11 15:54:20 -10:00
Jack Andersen
77013bbd9f Merge branch 'master' of https://github.com/AxioDL/nod 2019-06-09 16:51:00 -10:00
Jack Andersen
34b943c40f Solve various signing warnings reported by GCC 2019-06-09 16:49:17 -10:00
Jack Andersen
a1284ae065 Update logvisor 2019-05-25 00:15:37 -10:00
Jack Andersen
4dd0375cae Adjusted install commands for better CMake compatibility 2019-05-23 14:17:45 -10:00
Jack Andersen
01237372e1 Update logvisor 2019-05-22 18:09:21 -10:00
Jack Andersen
d9638cc60d Update logvisor 2019-05-22 17:59:34 -10:00
Jack Andersen
0ac7140542 Minor .gitmodules change 2019-05-22 16:04:33 -10:00
Jack Andersen
a5e9166194 Merge branch 'cmake' 2019-05-22 16:03:03 -10:00
Jack Andersen
ca2aeecc64 Ensure exported include dir is correct 2019-05-12 13:16:34 -10:00
Jack Andersen
cd782047c8 Update .gitmodules 2019-05-12 12:48:02 -10:00
Jack Andersen
2b7ea07cae Remove redundant include path 2019-05-12 12:41:14 -10:00
Jack Andersen
ed28576b99 Update logvisor 2019-05-09 18:06:48 -10:00
Jack Andersen
95ed2ae7dc Implicit switch fallthrough refactor 2019-02-17 19:46:42 -10:00
Sam Fuller
f1c76a475d Cmake config support 2019-01-27 21:35:03 -08:00
Jack Andersen
be8409681f New code style refactor 2018-12-07 19:21:47 -10:00
Jack Andersen
3d380fdc3b macOS build fixes 2018-10-15 17:16:08 -10:00
Jack Andersen
f87b286ff3 Windows build fixes 2018-10-14 10:11:28 -10:00
Jack Andersen
e964a013fe Convert to pragma once 2018-10-06 17:39:24 -10:00
Jack Andersen
eb6aa30563 NX build fixes 2018-10-06 16:56:47 -10:00
1ad101897c Merge branch 'arukibree-master' closes #4 2018-07-06 16:03:00 -07:00
Aruki
6f777ebb48 Fixes for a couple warnings/errors whene compiling on windows 2018-07-06 01:02:23 -06:00
Jack Andersen
42589c3604 Update logvisor 2018-06-01 14:02:48 -10:00
Jack Andersen
4d9071bad7 Update logvisor 2018-05-26 18:22:14 -10:00
Jack Andersen
d5f5db440c Windows build fixes and warning avoidance 2018-05-24 20:38:06 -10:00
Jack Andersen
51a15e474e Update logvisor 2018-05-05 15:31:24 -10:00
Jack Andersen
274a63bb30 Update logvisor 2018-03-23 12:05:04 -10:00
Jack Andersen
bab7aab6fa Update logvisor 2018-01-22 19:00:12 -10:00
Jack Andersen
5197abc131 Update logvisor 2018-01-13 20:41:28 -10:00
Jack Andersen
648c015383 Update logvisor 2018-01-09 20:17:41 -10:00
Jack Andersen
bf00fcd10f Driver fix 2017-12-28 22:38:55 -10:00
Jack Andersen
a557f86974 Huge compile performance refactor 2017-12-28 21:57:54 -10:00
Jack Andersen
34de6276b0 UWP fix 2017-12-06 18:11:03 -10:00
Jack Andersen
3d70a568dc UWP support 2017-12-05 17:23:58 -10:00
63ae60a967 Update .gitmodules 2017-12-02 13:23:44 -08:00
Jack Andersen
e20fce1e6f Update logvisor 2017-11-18 21:10:10 -10:00
Jack Andersen
b5916af702 Require CMake 3.10 2017-11-13 18:51:39 -10:00
Jack Andersen
58ceb47b25 Windows fixes 2017-11-13 17:35:34 -10:00
Jack Andersen
69e96e3b3c Linux build fixes 2017-11-12 21:21:29 -10:00
Jack Andersen
27a2cb5998 string_view refactor 2017-11-12 20:18:53 -10:00
Jack Andersen
c374038103 Minor indent fix 2017-10-30 17:51:49 -10:00
Jack Andersen
db1a6f13a2 Fix missing variable initialization 2017-07-30 17:43:51 -10:00
Jack Andersen
fb2a5c91d2 Explicitly zero-initialize new image files 2017-07-30 16:03:20 -10:00
42ef3a7958 Fix return type derp 2017-07-25 05:06:35 -07:00
Jack Andersen
d597400f4a Fix FST parent directory index 2017-07-11 19:13:44 -10:00
e99290e3c3 Remove unreferenced local 2017-07-09 02:11:19 -07:00
72169e8e77 Added writeSysFiles for convience of integration 2017-07-09 01:25:43 -07:00
a7c19799e1 Add MSVC definitions 2017-07-08 22:25:19 -07:00
28 changed files with 5194 additions and 5429 deletions

2
.gitmodules vendored
View File

@@ -1,3 +1,3 @@
[submodule "logvisor"] [submodule "logvisor"]
path = logvisor path = logvisor
url = https://github.com/AxioDL/logvisor.git url = ../logvisor.git

View File

@@ -1,18 +1,53 @@
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) # because of CMAKE_CXX_STANDARD cmake_minimum_required(VERSION 3.10 FATAL_ERROR) # because of c++17
project(nod) project(nod VERSION 0.1)
set(CMAKE_CXX_STANDARD 14) if (NOT MSVC)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif() endif()
endif()
include (CMakePackageConfigHelpers)
if (MSVC)
# Shaddup MSVC
add_definitions(-DUNICODE=1 -D_UNICODE=1 -D__SSE__=1 -D_CRT_SECURE_NO_WARNINGS=1 -DD_SCL_SECURE_NO_WARNINGS=1
/IGNORE:4221 /wd4018 /wd4800 /wd4005 /wd4311 /wd4267 /wd4244 /wd4200 /wd4305 /wd4067 /wd4146 ${VS_DEFINES})
endif()
if (NOT TARGET logvisor) if (NOT TARGET logvisor)
add_subdirectory(logvisor) add_subdirectory(logvisor)
set(LOGVISOR_INCLUDE_DIR logvisor/include)
endif() endif()
include_directories(include ${LOGVISOR_INCLUDE_DIR})
file(GLOB NOD_HEADERS include/nod/*.h*)
add_subdirectory(lib) add_subdirectory(lib)
add_subdirectory(driver) add_subdirectory(driver)
install(DIRECTORY include/nod DESTINATION include/nod)
set(version_config_file "${PROJECT_BINARY_DIR}/nodConfigVersion.cmake")
set(config_file "${PROJECT_BINARY_DIR}/nodConfig.cmake")
set(config_install_dir "lib/cmake/nod")
# Install the target config files
install(
EXPORT nodTargets
NAMESPACE "nod::"
DESTINATION "${config_install_dir}"
)
# Generate version config file
write_basic_package_version_file(
"${version_config_file}"
COMPATIBILITY SameMajorVersion
)
# Generate config file
configure_package_config_file(
"Config.cmake.in"
"${config_file}"
INSTALL_DESTINATION "lib/cmake/nod"
)
# Install the config files
install(
FILES "${config_file}" "${version_config_file}"
DESTINATION ${config_install_dir}
)

4
Config.cmake.in Normal file
View File

@@ -0,0 +1,4 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/nodTargets.cmake")
check_required_components(nod)

View File

@@ -41,12 +41,12 @@ auto progFunc = [&](size_t idx, const nod::SystemString& name, size_t bytes)
lastIdx = idx; lastIdx = idx;
/* NOD provides I/O wrappers using wchar_t on Windows; /* NOD provides I/O wrappers using wchar_t on Windows;
* _S() conditionally makes string-literals wide */ * _S() conditionally makes string-literals wide */
nod::Printf(_S("\n")); fmt::print(_S("\n"));
} }
if (bytes != -1) if (bytes != -1)
nod::Printf(_S("\r%s %" PRISize " B"), name.c_str(), bytes); fmt::print(_S("\r{} {} B"), name, bytes);
else else
nod::Printf(_S("\r%s"), name.c_str()); fmt::print(_S("\r{}"), name);
fflush(stdout); fflush(stdout);
}; };

View File

@@ -1,16 +1,23 @@
#include <stdio.h> #include <cstddef>
#include <string.h> #include <cstdint>
#include "logvisor/logvisor.hpp" #include <cstdio>
#include "nod/nod.hpp" #include <cstring>
static void printHelp() #include <logvisor/logvisor.hpp>
{
fprintf(stderr, "Usage:\n" #include <nod/DiscBase.hpp>
#include <nod/DiscGCN.hpp>
#include <nod/DiscWii.hpp>
#include <nod/nod.hpp>
static void printHelp() {
fmt::print(stderr, FMT_STRING(
"Usage:\n"
" nodtool extract [-f] <image-in> [<dir-out>]\n" " nodtool extract [-f] <image-in> [<dir-out>]\n"
" nodtool makegcn <fsroot-in> [<image-out>]\n" " nodtool makegcn <fsroot-in> [<image-out>]\n"
" nodtool makewii <fsroot-in> [<image-out>]\n" " nodtool makewii <fsroot-in> [<image-out>]\n"
" nodtool mergegcn <fsroot-in> <image-in> [<image-out>]\n" " nodtool mergegcn <fsroot-in> <image-in> [<image-out>]\n"
" nodtool mergewii <fsroot-in> <image-in> [<image-out>]\n"); " nodtool mergewii <fsroot-in> <image-in> [<image-out>]\n"));
} }
#if NOD_UCS2 #if NOD_UCS2
@@ -25,12 +32,10 @@ int wmain(int argc, wchar_t* argv[])
int main(int argc, char* argv[]) int main(int argc, char* argv[])
#endif #endif
{ {
if (argc < 3 || if (argc < 3 || (!strcasecmp(argv[1], _SYS_STR("makegcn")) && argc < 3) ||
(!strcasecmp(argv[1], _S("makegcn")) && argc < 3) || (!strcasecmp(argv[1], _SYS_STR("makewii")) && argc < 3) ||
(!strcasecmp(argv[1], _S("makewii")) && argc < 3) || (!strcasecmp(argv[1], _SYS_STR("mergegcn")) && argc < 4) ||
(!strcasecmp(argv[1], _S("mergegcn")) && argc < 4) || (!strcasecmp(argv[1], _SYS_STR("mergewii")) && argc < 4)) {
(!strcasecmp(argv[1], _S("mergewii")) && argc < 4))
{
printHelp(); printHelp();
return 1; return 1;
} }
@@ -40,16 +45,15 @@ int main(int argc, char* argv[])
logvisor::RegisterConsoleLogger(); logvisor::RegisterConsoleLogger();
bool verbose = false; bool verbose = false;
nod::ExtractionContext ctx = {true, nod::ExtractionContext ctx = {true, [&](std::string_view str, float c) {
[&](const std::string& str, float c) {
if (verbose) if (verbose)
fprintf(stderr, "Current node: %s, Extraction %g%% Complete\n", str.c_str(), c * 100.f); fmt::print(stderr, FMT_STRING("Current node: {}, Extraction {:g}% Complete\n"), str,
c * 100.f);
}}; }};
const nod::SystemChar* inDir = nullptr; const nod::SystemChar* inDir = nullptr;
const nod::SystemChar* outDir = _S("."); const nod::SystemChar* outDir = _SYS_STR(".");
for (int a=2 ; a<argc ; ++a) for (int a = 2; a < argc; ++a) {
{
if (argv[a][0] == '-' && argv[a][1] == 'f') if (argv[a][0] == '-' && argv[a][1] == 'f')
ctx.force = true; ctx.force = true;
else if (argv[a][0] == '-' && argv[a][1] == 'v') else if (argv[a][0] == '-' && argv[a][1] == 'v')
@@ -61,18 +65,16 @@ int main(int argc, char* argv[])
outDir = argv[a]; outDir = argv[a];
} }
auto progFunc = [&](float prog, const nod::SystemString& name, size_t bytes) auto progFunc = [&](float prog, nod::SystemStringView name, size_t bytes) {
{ fmt::print(FMT_STRING(_SYS_STR("\r ")));
nod::Printf(_S("\r ")); if (bytes != SIZE_MAX)
if (bytes != -1) fmt::print(FMT_STRING(_SYS_STR("\r{:g}% {} {} B")), prog * 100.f, name, bytes);
nod::Printf(_S("\r%g%% %s %" PRISize " B"), prog * 100.f, name.c_str(), bytes);
else else
nod::Printf(_S("\r%g%% %s"), prog * 100.f, name.c_str()); fmt::print(FMT_STRING(_SYS_STR("\r{:g}% {}")), prog * 100.f, name);
fflush(stdout); fflush(stdout);
}; };
if (!strcasecmp(argv[1], _S("extract"))) if (!strcasecmp(argv[1], _SYS_STR("extract"))) {
{
bool isWii; bool isWii;
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(inDir, isWii); std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(inDir, isWii);
if (!disc) if (!disc)
@@ -80,186 +82,153 @@ int main(int argc, char* argv[])
nod::Mkdir(outDir, 0755); nod::Mkdir(outDir, 0755);
nod::Partition* dataPart = disc->getDataPartition(); nod::IPartition* dataPart = disc->getDataPartition();
if (!dataPart) if (!dataPart)
return 1; return 1;
if (!dataPart->extractToDirectory(outDir, ctx)) if (!dataPart->extractToDirectory(outDir, ctx))
return 1; return 1;
} } else if (!strcasecmp(argv[1], _SYS_STR("makegcn"))) {
else if (!strcasecmp(argv[1], _S("makegcn")))
{
/* Pre-validate path */ /* Pre-validate path */
nod::Sstat theStat; nod::Sstat theStat;
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode)) if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode)) {
{ nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {} as directory")), argv[2]);
nod::LogModule.report(logvisor::Error, _S("unable to stat %s as directory"), argv[2]);
return 1; return 1;
} }
if (nod::DiscBuilderGCN::CalculateTotalSizeRequired(argv[2]) == -1) if (!nod::DiscBuilderGCN::CalculateTotalSizeRequired(argv[2]))
return 1; return 1;
nod::EBuildResult ret; nod::EBuildResult ret;
if (argc < 4) if (argc < 4) {
{
nod::SystemString outPath(argv[2]); nod::SystemString outPath(argv[2]);
outPath.append(_S(".iso")); outPath.append(_SYS_STR(".iso"));
nod::DiscBuilderGCN b(outPath.c_str(), progFunc); nod::DiscBuilderGCN b(outPath, progFunc);
ret = b.buildFromDirectory(argv[2]); ret = b.buildFromDirectory(argv[2]);
} } else {
else
{
nod::DiscBuilderGCN b(argv[3], progFunc); nod::DiscBuilderGCN b(argv[3], progFunc);
ret = b.buildFromDirectory(argv[2]); ret = b.buildFromDirectory(argv[2]);
} }
printf("\n"); fmt::print(FMT_STRING("\n"));
if (ret != nod::EBuildResult::Success) if (ret != nod::EBuildResult::Success)
return 1; return 1;
} } else if (!strcasecmp(argv[1], _SYS_STR("makewii"))) {
else if (!strcasecmp(argv[1], _S("makewii")))
{
/* Pre-validate path */ /* Pre-validate path */
nod::Sstat theStat; nod::Sstat theStat;
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode)) if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode)) {
{ nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {} as directory")), argv[4]);
nod::LogModule.report(logvisor::Error, _S("unable to stat %s as directory"), argv[4]);
return 1; return 1;
} }
bool dual = false; bool dual = false;
if (nod::DiscBuilderWii::CalculateTotalSizeRequired(argv[2], dual) == -1) if (!nod::DiscBuilderWii::CalculateTotalSizeRequired(argv[2], dual))
return 1; return 1;
nod::EBuildResult ret; nod::EBuildResult ret;
if (argc < 4) if (argc < 4) {
{
nod::SystemString outPath(argv[2]); nod::SystemString outPath(argv[2]);
outPath.append(_S(".iso")); outPath.append(_SYS_STR(".iso"));
nod::DiscBuilderWii b(outPath.c_str(), dual, progFunc); nod::DiscBuilderWii b(outPath.c_str(), dual, progFunc);
ret = b.buildFromDirectory(argv[2]); ret = b.buildFromDirectory(argv[2]);
} } else {
else
{
nod::DiscBuilderWii b(argv[3], dual, progFunc); nod::DiscBuilderWii b(argv[3], dual, progFunc);
ret = b.buildFromDirectory(argv[2]); ret = b.buildFromDirectory(argv[2]);
} }
printf("\n"); fmt::print(FMT_STRING("\n"));
if (ret != nod::EBuildResult::Success) if (ret != nod::EBuildResult::Success)
return 1; return 1;
} } else if (!strcasecmp(argv[1], _SYS_STR("mergegcn"))) {
else if (!strcasecmp(argv[1], _S("mergegcn")))
{
/* Pre-validate paths */ /* Pre-validate paths */
nod::Sstat theStat; nod::Sstat theStat;
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode)) if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode)) {
{ nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {} as directory")), argv[2]);
nod::LogModule.report(logvisor::Error, _S("unable to stat %s as directory"), argv[2]);
return 1; return 1;
} }
if (nod::Stat(argv[3], &theStat) || !S_ISREG(theStat.st_mode)) if (nod::Stat(argv[3], &theStat) || !S_ISREG(theStat.st_mode)) {
{ nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {} as file")), argv[3]);
nod::LogModule.report(logvisor::Error, _S("unable to stat %s as file"), argv[3]);
return 1; return 1;
} }
bool isWii; bool isWii;
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(argv[3], isWii); std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(argv[3], 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, _S("unable to open image %s"), argv[3]);
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, _S("Wii images should be merged with 'mergewii'"));
return 1; return 1;
} }
if (nod::DiscMergerGCN::CalculateTotalSizeRequired(static_cast<nod::DiscGCN&>(*disc), argv[2]) == -1) if (!nod::DiscMergerGCN::CalculateTotalSizeRequired(static_cast<nod::DiscGCN&>(*disc), argv[2]))
return 1; return 1;
nod::EBuildResult ret; nod::EBuildResult ret;
if (argc < 5) if (argc < 5) {
{
nod::SystemString outPath(argv[2]); nod::SystemString outPath(argv[2]);
outPath.append(_S(".iso")); outPath.append(_SYS_STR(".iso"));
nod::DiscMergerGCN b(outPath.c_str(), static_cast<nod::DiscGCN&>(*disc), progFunc); nod::DiscMergerGCN b(outPath.c_str(), static_cast<nod::DiscGCN&>(*disc), progFunc);
ret = b.mergeFromDirectory(argv[2]); ret = b.mergeFromDirectory(argv[2]);
} } else {
else
{
nod::DiscMergerGCN b(argv[4], static_cast<nod::DiscGCN&>(*disc), progFunc); nod::DiscMergerGCN b(argv[4], static_cast<nod::DiscGCN&>(*disc), progFunc);
ret = b.mergeFromDirectory(argv[2]); ret = b.mergeFromDirectory(argv[2]);
} }
printf("\n"); fmt::print(FMT_STRING("\n"));
if (ret != nod::EBuildResult::Success) if (ret != nod::EBuildResult::Success)
return 1; return 1;
} } else if (!strcasecmp(argv[1], _SYS_STR("mergewii"))) {
else if (!strcasecmp(argv[1], _S("mergewii")))
{
/* Pre-validate paths */ /* Pre-validate paths */
nod::Sstat theStat; nod::Sstat theStat;
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode)) if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode)) {
{ nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {} as directory")), argv[2]);
nod::LogModule.report(logvisor::Error, _S("unable to stat %s as directory"), argv[2]);
return 1; return 1;
} }
if (nod::Stat(argv[3], &theStat) || !S_ISREG(theStat.st_mode)) if (nod::Stat(argv[3], &theStat) || !S_ISREG(theStat.st_mode)) {
{ nod::LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {} as file")), argv[3]);
nod::LogModule.report(logvisor::Error, _S("unable to stat %s as file"), argv[3]);
return 1; return 1;
} }
bool isWii; bool isWii;
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(argv[3], isWii); std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(argv[3], 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, _S("unable to open image %s"), 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, _S("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), argv[2], dual) == -1) if (!nod::DiscMergerWii::CalculateTotalSizeRequired(static_cast<nod::DiscWii&>(*disc), argv[2], dual))
return 1; return 1;
nod::EBuildResult ret; nod::EBuildResult ret;
if (argc < 5) if (argc < 5) {
{
nod::SystemString outPath(argv[2]); nod::SystemString outPath(argv[2]);
outPath.append(_S(".iso")); outPath.append(_SYS_STR(".iso"));
nod::DiscMergerWii b(outPath.c_str(), static_cast<nod::DiscWii&>(*disc), dual, progFunc); nod::DiscMergerWii b(outPath.c_str(), static_cast<nod::DiscWii&>(*disc), dual, progFunc);
ret = b.mergeFromDirectory(argv[2]); ret = b.mergeFromDirectory(argv[2]);
} } else {
else
{
nod::DiscMergerWii b(argv[4], static_cast<nod::DiscWii&>(*disc), dual, progFunc); nod::DiscMergerWii b(argv[4], static_cast<nod::DiscWii&>(*disc), dual, progFunc);
ret = b.mergeFromDirectory(argv[2]); ret = b.mergeFromDirectory(argv[2]);
} }
printf("\n"); fmt::print(FMT_STRING("\n"));
if (ret != nod::EBuildResult::Success) if (ret != nod::EBuildResult::Success)
return 1; return 1;
} } else {
else
{
printHelp(); printHelp();
return 1; return 1;
} }
nod::LogModule.report(logvisor::Info, _S("Success!")); nod::LogModule.report(logvisor::Info, FMT_STRING(_SYS_STR("Success!")));
return 0; return 0;
} }

View File

@@ -1,66 +1,49 @@
#ifndef __NOD_DIRECTORY_ENUMERATOR__ #pragma once
#define __NOD_DIRECTORY_ENUMERATOR__
#include "Util.hpp" #include <algorithm>
#include <cctype>
#include <cstddef>
#include <vector>
namespace nod #include "nod/Util.hpp"
{
struct CaseInsensitiveCompare namespace nod {
{
bool operator()(const std::string& lhs, const std::string& rhs) const struct CaseInsensitiveCompare {
{ bool operator()(std::string_view lhs, std::string_view rhs) const {
#if _WIN32 return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](char lhs, char rhs) {
if (_stricmp(lhs.c_str(), rhs.c_str()) < 0) return std::tolower(static_cast<unsigned char>(lhs)) < std::tolower(static_cast<unsigned char>(rhs));
#else });
if (strcasecmp(lhs.c_str(), rhs.c_str()) < 0)
#endif
return true;
return false;
} }
#if _WIN32 #if _WIN32
bool operator()(const std::wstring& lhs, const std::wstring& rhs) const 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) {
if (_wcsicmp(lhs.c_str(), rhs.c_str()) < 0) return std::towlower(lhs) < std::towlower(rhs);
return true; });
return false;
} }
#endif #endif
}; };
class DirectoryEnumerator class DirectoryEnumerator {
{
public: public:
enum class Mode enum class Mode { Native, DirsSorted, FilesSorted, DirsThenFilesSorted };
{ struct Entry {
Native,
DirsSorted,
FilesSorted,
DirsThenFilesSorted
};
struct Entry
{
SystemString m_path; SystemString m_path;
SystemString m_name; SystemString m_name;
size_t m_fileSz; size_t m_fileSz;
bool m_isDir; bool m_isDir;
private: Entry(const SystemString& path, const SystemChar* name, size_t sz, bool isDir)
friend class DirectoryEnumerator; : m_path(path), m_name(name), m_fileSz(sz), m_isDir(isDir) {}
Entry(SystemString&& path, const SystemChar* name, size_t sz, bool isDir)
: m_path(std::move(path)), m_name(name), m_fileSz(sz), m_isDir(isDir) {}
}; };
private: private:
std::vector<Entry> m_entries; std::vector<Entry> m_entries;
public: public:
DirectoryEnumerator(const SystemString& path, Mode mode=Mode::DirsThenFilesSorted, DirectoryEnumerator(SystemStringView path, Mode mode = Mode::DirsThenFilesSorted, bool sizeSort = false,
bool sizeSort=false, bool reverse=false, bool noHidden=false) bool reverse = false, bool noHidden = false);
: DirectoryEnumerator(path.c_str(), mode, sizeSort, reverse, noHidden) {}
DirectoryEnumerator(const SystemChar* path, Mode mode=Mode::DirsThenFilesSorted,
bool sizeSort=false, bool reverse=false, bool noHidden=false);
operator bool() const { return m_entries.size() != 0; } operator bool() const { return m_entries.size() != 0; }
size_t size() const { return m_entries.size(); } size_t size() const { return m_entries.size(); }
@@ -68,6 +51,4 @@ public:
std::vector<Entry>::const_iterator end() const { return m_entries.cend(); } std::vector<Entry>::const_iterator end() const { return m_entries.cend(); }
}; };
} } // namespace nod
#endif // __NOD_DIRECTORY_ENUMERATOR__

View File

@@ -1,65 +1,53 @@
#ifndef __NOD_DISC_BASE__ #pragma once
#define __NOD_DISC_BASE__
#include <vector> #include <cstddef>
#include <cstdint>
#include <cstring>
#include <functional>
#include <memory> #include <memory>
#include <optional>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <stdio.h> #include <vector>
#include <stdint.h>
#include <functional>
#include "Util.hpp"
#include "IDiscIO.hpp"
#include "IFileIO.hpp"
namespace nod #include "nod/IDiscIO.hpp"
{ #include "nod/IFileIO.hpp"
#include "nod/Util.hpp"
using FProgress = std::function<void(float totalProg, const SystemString& fileName, size_t fileBytesXfered)>; namespace nod {
enum class EBuildResult using FProgress = std::function<void(float totalProg, SystemStringView fileName, size_t fileBytesXfered)>;
{
Success,
Failed,
DiskFull
};
enum class PartitionKind : uint32_t enum class EBuildResult { Success, Failed, DiskFull };
{
Data, enum class PartitionKind : uint32_t { Data, Update, Channel };
Update,
Channel
};
const SystemChar* getKindString(PartitionKind kind); const SystemChar* getKindString(PartitionKind kind);
class FSTNode class FSTNode {
{
uint32_t typeAndNameOffset; uint32_t typeAndNameOffset;
uint32_t offset; uint32_t offset;
uint32_t length; uint32_t length;
public: public:
FSTNode(bool isDir, uint32_t nameOff, uint32_t off, uint32_t len) FSTNode(bool isDir, uint32_t nameOff, uint32_t off, uint32_t len) {
{
typeAndNameOffset = nameOff & 0xffffff; typeAndNameOffset = nameOff & 0xffffff;
typeAndNameOffset |= isDir << 24; typeAndNameOffset |= isDir << 24;
typeAndNameOffset = SBig(typeAndNameOffset); typeAndNameOffset = SBig(typeAndNameOffset);
offset = SBig(off); offset = SBig(off);
length = SBig(len); length = SBig(len);
} }
inline bool isDir() const {return ((SBig(typeAndNameOffset) >> 24) != 0);} bool isDir() const { return ((SBig(typeAndNameOffset) >> 24) != 0); }
inline uint32_t getNameOffset() const {return SBig(typeAndNameOffset) & 0xffffff;} uint32_t getNameOffset() const { return SBig(typeAndNameOffset) & 0xffffff; }
inline uint32_t getOffset() const {return SBig(offset);} uint32_t getOffset() const { return SBig(offset); }
inline uint32_t getLength() const {return SBig(length);} uint32_t getLength() const { return SBig(length); }
void incrementLength() void incrementLength() {
{
uint32_t orig = SBig(length); uint32_t orig = SBig(length);
++orig; ++orig;
length = SBig(orig); length = SBig(orig);
} }
}; };
struct Header struct Header {
{
char m_gameID[6]; char m_gameID[6];
char m_discNum; char m_discNum;
char m_discVersion; char m_discVersion;
@@ -85,19 +73,16 @@ struct Header
uint8_t padding1[4]; uint8_t padding1[4];
Header() = default; Header() = default;
Header(IDiscIO& dio, bool& err) Header(IDiscIO& dio, bool& err) {
{
auto rs = dio.beginReadStream(); auto rs = dio.beginReadStream();
if (!rs) if (!rs) {
{
err = true; err = true;
return; return;
} }
read(*rs); read(*rs);
} }
void read(IReadStream& s) void read(IReadStream& s) {
{
memset(this, 0, sizeof(*this)); memset(this, 0, sizeof(*this));
s.read(this, sizeof(*this)); s.read(this, sizeof(*this));
m_wiiMagic = SBig(m_wiiMagic); m_wiiMagic = SBig(m_wiiMagic);
@@ -113,8 +98,7 @@ struct Header
m_userSz = SBig(m_userSz); m_userSz = SBig(m_userSz);
} }
void write(IWriteStream& ws) const void write(IWriteStream& ws) const {
{
Header hs(*this); Header hs(*this);
hs.m_wiiMagic = SBig(hs.m_wiiMagic); hs.m_wiiMagic = SBig(hs.m_wiiMagic);
hs.m_gcnMagic = SBig(hs.m_gcnMagic); hs.m_gcnMagic = SBig(hs.m_gcnMagic);
@@ -132,8 +116,7 @@ struct Header
}; };
/* Currently only kept for dolphin compatibility */ /* Currently only kept for dolphin compatibility */
struct BI2Header struct BI2Header {
{
int32_t m_debugMonitorSize; int32_t m_debugMonitorSize;
int32_t m_simMemSize; int32_t m_simMemSize;
uint32_t m_argOffset; uint32_t m_argOffset;
@@ -148,8 +131,7 @@ struct BI2Header
uint32_t m_unk4; uint32_t m_unk4;
uint8_t padding2[0x1FD0]; uint8_t padding2[0x1FD0];
void read(IReadStream& rs) void read(IReadStream& rs) {
{
memset(this, 0, sizeof(*this)); memset(this, 0, sizeof(*this));
rs.read(this, sizeof(*this)); rs.read(this, sizeof(*this));
m_debugMonitorSize = SBig(m_debugMonitorSize); m_debugMonitorSize = SBig(m_debugMonitorSize);
@@ -166,8 +148,7 @@ struct BI2Header
m_unk4 = SBig(m_unk4); m_unk4 = SBig(m_unk4);
} }
void write(IWriteStream& ws) const void write(IWriteStream& ws) const {
{
BI2Header h = *this; BI2Header h = *this;
h.m_debugMonitorSize = SBig(h.m_debugMonitorSize); h.m_debugMonitorSize = SBig(h.m_debugMonitorSize);
h.m_simMemSize = SBig(h.m_simMemSize); h.m_simMemSize = SBig(h.m_simMemSize);
@@ -186,36 +167,13 @@ struct BI2Header
}; };
struct ExtractionContext; struct ExtractionContext;
class DiscBase class IPartition;
{ class DiscBase;
public:
virtual ~DiscBase() = default;
class IPartition class Node {
{
public: public:
virtual ~IPartition() = default; enum class Kind { File, Directory };
struct DOLHeader
{
uint32_t textOff[7];
uint32_t dataOff[11];
uint32_t textStarts[7];
uint32_t dataStarts[11];
uint32_t textSizes[7];
uint32_t dataSizes[11];
uint32_t bssStart;
uint32_t bssSize;
uint32_t entryPoint;
};
class Node
{
public:
enum class Kind
{
File,
Directory
};
private: private:
friend class IPartition; friend class IPartition;
const IPartition& m_parent; const IPartition& m_parent;
@@ -229,68 +187,48 @@ public:
std::vector<Node>::iterator m_childrenEnd; std::vector<Node>::iterator m_childrenEnd;
public: public:
Node(const IPartition& parent, const FSTNode& node, const char* name) Node(const IPartition& parent, const FSTNode& node, std::string_view name);
: m_parent(parent), Kind getKind() const { return m_kind; }
m_kind(node.isDir() ? Kind::Directory : Kind::File), std::string_view getName() const { return m_name; }
m_discOffset(parent.normalizeOffset(node.getOffset())), uint64_t size() const { return m_discLength; }
m_discLength(node.getLength()), std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset = 0) const;
m_name(name) {} std::unique_ptr<uint8_t[]> getBuf() const;
inline Kind getKind() const {return m_kind;} std::vector<Node>::iterator rawBegin() const { return m_childrenBegin; }
inline const std::string& getName() const {return m_name;} std::vector<Node>::iterator rawEnd() const { return m_childrenEnd; }
inline uint64_t size() const {return m_discLength;}
std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset=0) const
{
if (m_kind != Kind::File)
{
LogModule.report(logvisor::Error, "unable to stream a non-file %s", m_name.c_str());
return std::unique_ptr<IPartReadStream>();
}
return m_parent.beginReadStream(m_discOffset + offset);
}
std::unique_ptr<uint8_t[]> getBuf() const
{
if (m_kind != Kind::File)
{
LogModule.report(logvisor::Error, "unable to buffer a non-file %s", m_name.c_str());
return std::unique_ptr<uint8_t[]>();
}
uint8_t* buf = new uint8_t[m_discLength];
beginReadStream()->read(buf, m_discLength);
return std::unique_ptr<uint8_t[]>(buf);
}
inline std::vector<Node>::iterator rawBegin() const {return m_childrenBegin;}
inline std::vector<Node>::iterator rawEnd() const {return m_childrenEnd;}
class DirectoryIterator : std::iterator<std::forward_iterator_tag, Node> class DirectoryIterator {
{
friend class Node; friend class Node;
std::vector<Node>::iterator m_it; std::vector<Node>::iterator m_it;
DirectoryIterator(const std::vector<Node>::iterator& it) DirectoryIterator(const std::vector<Node>::iterator& it) : m_it(it) {}
: m_it(it) {}
public: public:
inline bool operator!=(const DirectoryIterator& other) {return m_it != other.m_it;} using iterator_category = std::forward_iterator_tag;
inline bool operator==(const DirectoryIterator& other) {return m_it == other.m_it;} using value_type = Node;
inline DirectoryIterator& operator++() using difference_type = std::ptrdiff_t;
{ using pointer = Node*;
using reference = Node&;
bool operator==(const DirectoryIterator& other) const { return m_it == other.m_it; }
bool operator!=(const DirectoryIterator& other) const { return !operator==(other); }
DirectoryIterator& operator++() {
if (m_it->m_kind == Kind::Directory) if (m_it->m_kind == Kind::Directory)
m_it = m_it->rawEnd(); m_it = m_it->rawEnd();
else else
++m_it; ++m_it;
return *this; return *this;
} }
inline Node& operator*() {return *m_it;} Node& operator*() { return *m_it; }
inline Node* operator->() {return &*m_it;} const Node& operator*() const { return *m_it; }
Node* operator->() { return &*m_it; }
const Node* operator->() const { return &*m_it; }
}; };
inline DirectoryIterator begin() const {return DirectoryIterator(m_childrenBegin);} DirectoryIterator begin() const { return DirectoryIterator(m_childrenBegin); }
inline DirectoryIterator end() const {return DirectoryIterator(m_childrenEnd);} DirectoryIterator end() const { return DirectoryIterator(m_childrenEnd); }
inline DirectoryIterator find(const std::string& name) const DirectoryIterator find(std::string_view name) const {
{ if (m_kind == Kind::Directory) {
if (m_kind == Kind::Directory)
{
DirectoryIterator it = begin(); DirectoryIterator it = begin();
for (; it != end() ; ++it) for (; it != end(); ++it) {
{ if (it->getName() == name)
if (!it->getName().compare(name))
return it; return it;
} }
return it; return it;
@@ -298,8 +236,24 @@ public:
return end(); return end();
} }
bool extractToDirectory(const SystemString& basePath, const ExtractionContext& ctx) const; bool extractToDirectory(SystemStringView basePath, const ExtractionContext& ctx) const;
}; };
class IPartition {
public:
virtual ~IPartition() = default;
struct DOLHeader {
uint32_t textOff[7];
uint32_t dataOff[11];
uint32_t textStarts[7];
uint32_t dataStarts[11];
uint32_t textSizes[7];
uint32_t dataSizes[11];
uint32_t bssStart;
uint32_t bssSize;
uint32_t entryPoint;
};
protected: protected:
Header m_header; Header m_header;
BI2Header m_bi2Header; BI2Header m_bi2Header;
@@ -313,7 +267,6 @@ public:
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;
void recursiveBuildNodes(const SystemChar* dirIn, std::function<void(void)> incParents);
uint64_t m_dolSz; uint64_t m_dolSz;
void parseDOL(IPartReadStream& s); void parseDOL(IPartReadStream& s);
@@ -322,11 +275,11 @@ public:
PartitionKind m_kind; PartitionKind m_kind;
uint64_t m_offset; uint64_t m_offset;
bool m_isWii; bool m_isWii;
public: public:
mutable size_t m_curNodeIdx = 0; mutable size_t m_curNodeIdx = 0;
float getProgressFactor() const { return getNodeCount() ? m_curNodeIdx / float(getNodeCount()) : 0.f; } float getProgressFactor() const { return getNodeCount() ? m_curNodeIdx / float(getNodeCount()) : 0.f; }
float getProgressFactorMidFile(size_t curByte, size_t totalBytes) const float getProgressFactorMidFile(size_t curByte, size_t totalBytes) const {
{
if (!getNodeCount()) if (!getNodeCount())
return 0.f; return 0.f;
@@ -339,100 +292,102 @@ public:
IPartition(const DiscBase& parent, PartitionKind kind, bool isWii, uint64_t offset) IPartition(const DiscBase& parent, PartitionKind kind, bool isWii, uint64_t offset)
: m_parent(parent), m_kind(kind), m_offset(offset), m_isWii(isWii) {} : 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; }
inline PartitionKind getKind() const {return m_kind;} PartitionKind getKind() const { return m_kind; }
inline bool isWii() const {return m_isWii;} bool isWii() const { return m_isWii; }
inline uint64_t getDiscOffset() const {return m_offset;} uint64_t getDiscOffset() const { return m_offset; }
virtual std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset = 0) const = 0; virtual std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset = 0) const = 0;
inline std::unique_ptr<IPartReadStream> beginDOLReadStream(uint64_t offset=0) const std::unique_ptr<IPartReadStream> beginDOLReadStream(uint64_t offset = 0) const {
{return beginReadStream(m_dolOff + offset);} return beginReadStream(m_dolOff + offset);
inline std::unique_ptr<IPartReadStream> beginFSTReadStream(uint64_t offset=0) const }
{return beginReadStream(m_fstOff + offset);} std::unique_ptr<IPartReadStream> beginFSTReadStream(uint64_t offset = 0) const {
inline std::unique_ptr<IPartReadStream> beginApploaderReadStream(uint64_t offset=0) const return beginReadStream(m_fstOff + offset);
{return beginReadStream(0x2440 + offset);} }
inline const Node& getFSTRoot() const {return m_nodes[0];} std::unique_ptr<IPartReadStream> beginApploaderReadStream(uint64_t offset = 0) const {
inline Node& getFSTRoot() {return m_nodes[0];} return beginReadStream(0x2440 + offset);
bool extractToDirectory(const SystemString& path, const ExtractionContext& ctx); }
const Node& getFSTRoot() const { return m_nodes[0]; }
Node& getFSTRoot() { return m_nodes[0]; }
bool extractToDirectory(SystemStringView path, const ExtractionContext& ctx);
inline uint64_t getDOLSize() const {return m_dolSz;} uint64_t getDOLSize() const { return m_dolSz; }
inline std::unique_ptr<uint8_t[]> getDOLBuf() const std::unique_ptr<uint8_t[]> getDOLBuf() const {
{
std::unique_ptr<uint8_t[]> buf(new uint8_t[m_dolSz]); std::unique_ptr<uint8_t[]> buf(new uint8_t[m_dolSz]);
beginDOLReadStream()->read(buf.get(), m_dolSz); beginDOLReadStream()->read(buf.get(), m_dolSz);
return buf; return buf;
} }
inline uint64_t getFSTSize() const {return m_fstSz;} uint64_t getFSTSize() const { return m_fstSz; }
inline std::unique_ptr<uint8_t[]> getFSTBuf() const std::unique_ptr<uint8_t[]> getFSTBuf() const {
{
std::unique_ptr<uint8_t[]> buf(new uint8_t[m_fstSz]); std::unique_ptr<uint8_t[]> buf(new uint8_t[m_fstSz]);
beginFSTReadStream()->read(buf.get(), m_fstSz); beginFSTReadStream()->read(buf.get(), m_fstSz);
return buf; return buf;
} }
inline uint64_t getApploaderSize() const {return m_apploaderSz;} uint64_t getApploaderSize() const { return m_apploaderSz; }
inline std::unique_ptr<uint8_t[]> getApploaderBuf() const std::unique_ptr<uint8_t[]> getApploaderBuf() const {
{
std::unique_ptr<uint8_t[]> buf(new uint8_t[m_apploaderSz]); std::unique_ptr<uint8_t[]> buf(new uint8_t[m_apploaderSz]);
beginApploaderReadStream()->read(buf.get(), m_apploaderSz); beginApploaderReadStream()->read(buf.get(), m_apploaderSz);
return buf; return buf;
} }
inline size_t getNodeCount() const { return m_nodes.size(); } size_t getNodeCount() const { return m_nodes.size(); }
inline const Header& getHeader() const { return m_header; } const Header& getHeader() const { return m_header; }
inline const BI2Header& getBI2() const { return m_bi2Header; } const BI2Header& getBI2() const { return m_bi2Header; }
virtual bool extractCryptoFiles(const SystemString& path, const ExtractionContext& ctx) const { return true; } virtual bool extractCryptoFiles(SystemStringView path, const ExtractionContext& ctx) const { return true; }
bool extractSysFiles(SystemStringView path, const ExtractionContext& ctx) const;
}; };
class DiscBase {
public:
virtual ~DiscBase() = default;
protected: protected:
std::unique_ptr<IDiscIO> m_discIO; std::unique_ptr<IDiscIO> m_discIO;
Header m_header; Header m_header;
std::vector<std::unique_ptr<IPartition>> m_partitions; std::vector<std::unique_ptr<IPartition>> m_partitions;
public:
DiscBase(std::unique_ptr<IDiscIO>&& dio, bool& err)
: m_discIO(std::move(dio)), m_header(*m_discIO, err) {}
inline const Header& getHeader() const {return m_header;} public:
inline const IDiscIO& getDiscIO() const {return *m_discIO;} DiscBase(std::unique_ptr<IDiscIO>&& dio, bool& err) : m_discIO(std::move(dio)), m_header(*m_discIO, err) {}
inline size_t getPartitonNodeCount(size_t partition = 0) const
{ const Header& getHeader() const { return m_header; }
if (partition > m_partitions.size()) const IDiscIO& getDiscIO() const { return *m_discIO; }
size_t getPartitionNodeCount(size_t partition = 0) const {
if (partition >= m_partitions.size()) {
return -1; return -1;
}
return m_partitions[partition]->getNodeCount(); return m_partitions[partition]->getNodeCount();
} }
inline IPartition* getDataPartition() IPartition* getDataPartition() {
{
for (const std::unique_ptr<IPartition>& part : m_partitions) for (const std::unique_ptr<IPartition>& part : m_partitions)
if (part->getKind() == PartitionKind::Data) if (part->getKind() == PartitionKind::Data)
return part.get(); return part.get();
return nullptr; return nullptr;
} }
inline IPartition* getUpdatePartition() IPartition* getUpdatePartition() {
{
for (const std::unique_ptr<IPartition>& part : m_partitions) for (const std::unique_ptr<IPartition>& part : m_partitions)
if (part->getKind() == PartitionKind::Update) if (part->getKind() == PartitionKind::Update)
return part.get(); return part.get();
return nullptr; return nullptr;
} }
inline void extractToDirectory(const SystemString& path, const ExtractionContext& ctx) void extractToDirectory(SystemStringView 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(const SystemString& path, const ExtractionContext& ctx) const=0; virtual bool extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const = 0;
}; };
class DiscBuilderBase class DiscBuilderBase {
{
friend class DiscMergerWii; friend class DiscMergerWii;
public: public:
class PartitionBuilderBase class PartitionBuilderBase {
{
public: public:
virtual ~PartitionBuilderBase() = default; virtual ~PartitionBuilderBase() = default;
protected: protected:
std::unordered_map<SystemString, std::pair<uint64_t, uint64_t>> m_fileOffsetsSizes; std::unordered_map<SystemString, std::pair<uint64_t, uint64_t>> m_fileOffsetsSizes;
std::vector<FSTNode> m_buildNodes; std::vector<FSTNode> m_buildNodes;
@@ -441,28 +396,22 @@ public:
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(const SystemChar* dirIn); void recursiveBuildNodesPre(SystemStringView dirIn);
bool recursiveBuildNodes(IPartWriteStream& ws, bool system, const SystemChar* dirIn); bool recursiveBuildNodes(IPartWriteStream& ws, bool system, SystemStringView dirIn);
bool recursiveBuildFST(const SystemChar* dirIn, bool recursiveBuildFST(SystemStringView dirIn, std::function<void(void)> incParents, size_t parentDirIdx);
std::function<void(void)> incParents);
void recursiveMergeNodesPre(const DiscBase::IPartition::Node* nodeIn, const SystemChar* dirIn); void recursiveMergeNodesPre(const Node* nodeIn, SystemStringView dirIn);
bool recursiveMergeNodes(IPartWriteStream& ws, bool system, bool recursiveMergeNodes(IPartWriteStream& ws, bool system, const Node* nodeIn, SystemStringView dirIn,
const DiscBase::IPartition::Node* nodeIn, const SystemChar* dirIn, SystemStringView keyPath);
const SystemString& keyPath); bool recursiveMergeFST(const Node* nodeIn, SystemStringView dirIn, std::function<void(void)> incParents,
bool recursiveMergeFST(const DiscBase::IPartition::Node* nodeIn, SystemStringView keyPath);
const SystemChar* dirIn, std::function<void(void)> incParents,
const SystemString& keyPath);
static bool RecursiveCalculateTotalSize(uint64_t& totalSz, static bool RecursiveCalculateTotalSize(uint64_t& totalSz, const Node* nodeIn, SystemStringView dirIn);
const DiscBase::IPartition::Node* nodeIn,
const SystemChar* dirIn);
void addBuildName(const SystemString& str) void addBuildName(SystemStringView str) {
{ SystemUTF8Conv utf8View(str);
SystemUTF8View utf8View(str); m_buildNames.emplace_back(utf8View.utf8_str());
m_buildNames.push_back(utf8View.utf8_str());
m_buildNameOff += str.size() + 1; m_buildNameOff += str.size() + 1;
} }
@@ -471,36 +420,31 @@ 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;
public: public:
PartitionBuilderBase(DiscBuilderBase& parent, PartitionKind kind, bool isWii) PartitionBuilderBase(DiscBuilderBase& parent, PartitionKind kind, bool isWii)
: m_parent(parent), m_kind(kind), m_isWii(isWii) : 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, bool buildFromDirectory(IPartWriteStream& ws, SystemStringView dirIn);
const SystemChar* dirIn); static std::optional<uint64_t> CalculateTotalSizeBuild(SystemStringView dirIn, PartitionKind kind, bool isWii);
static uint64_t CalculateTotalSizeBuild(const SystemChar* dirIn, bool mergeFromDirectory(IPartWriteStream& ws, const IPartition* partIn, SystemStringView dirIn);
PartitionKind kind, bool isWii); static std::optional<uint64_t> CalculateTotalSizeMerge(const IPartition* partIn, SystemStringView dirIn);
bool mergeFromDirectory(IPartWriteStream& ws,
const DiscBase::IPartition* partIn,
const SystemChar* dirIn);
static uint64_t CalculateTotalSizeMerge(const DiscBase::IPartition* partIn,
const SystemChar* dirIn);
}; };
protected: protected:
SystemString m_outPath; SystemString 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;
public: public:
FProgress m_progressCB; FProgress m_progressCB;
size_t m_progressIdx = 0; size_t m_progressIdx = 0;
size_t m_progressTotal = 0; size_t m_progressTotal = 0;
float getProgressFactor() const float getProgressFactor() const {
{
return m_progressTotal ? std::min(1.f, m_progressIdx / float(m_progressTotal)) : 0.f; return m_progressTotal ? std::min(1.f, m_progressIdx / float(m_progressTotal)) : 0.f;
} }
float getProgressFactorMidFile(size_t curByte, size_t totalBytes) const float getProgressFactorMidFile(size_t curByte, size_t totalBytes) const {
{
if (!m_progressTotal) if (!m_progressTotal)
return 0.f; return 0.f;
@@ -511,19 +455,15 @@ public:
} }
virtual ~DiscBuilderBase() = default; virtual ~DiscBuilderBase() = default;
DiscBuilderBase(const SystemChar* outPath, DiscBuilderBase(SystemStringView outPath, int64_t discCapacity, FProgress progressCB)
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_progressCB(progressCB) {} , m_discCapacity(discCapacity)
, m_progressCB(std::move(progressCB)) {}
DiscBuilderBase(DiscBuilderBase&&) = default; DiscBuilderBase(DiscBuilderBase&&) = default;
DiscBuilderBase& operator=(DiscBuilderBase&&) = default; DiscBuilderBase& operator=(DiscBuilderBase&&) = default;
IFileIO& getFileIO() { return *m_fileIO; } IFileIO& getFileIO() { return *m_fileIO; }
}; };
using Partition = DiscBase::IPartition; } // namespace nod
using Node = Partition::Node;
}
#endif // __NOD_DISC_BASE__

View File

@@ -1,41 +1,36 @@
#ifndef __NOD_DISC_GCN__ #pragma once
#define __NOD_DISC_GCN__
#include "DiscBase.hpp" #include "nod/DiscBase.hpp"
namespace nod namespace nod {
{
class DiscBuilderGCN; class DiscBuilderGCN;
class DiscGCN : public DiscBase class DiscGCN : public DiscBase {
{
friend class DiscMergerGCN; friend class DiscMergerGCN;
DiscBuilderGCN makeMergeBuilder(const SystemChar* outPath, FProgress progressCB); DiscBuilderGCN makeMergeBuilder(SystemStringView outPath, FProgress progressCB);
public: public:
DiscGCN(std::unique_ptr<IDiscIO>&& dio, bool& err); DiscGCN(std::unique_ptr<IDiscIO>&& dio, bool& err);
bool extractDiscHeaderFiles(const SystemString& path, const ExtractionContext& ctx) const; bool extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const override;
}; };
class DiscBuilderGCN : public DiscBuilderBase class DiscBuilderGCN : public DiscBuilderBase {
{
friend class DiscMergerGCN; friend class DiscMergerGCN;
public: public:
DiscBuilderGCN(const SystemChar* outPath, FProgress progressCB); DiscBuilderGCN(SystemStringView outPath, FProgress progressCB);
EBuildResult buildFromDirectory(const SystemChar* dirIn); EBuildResult buildFromDirectory(SystemStringView dirIn);
static uint64_t CalculateTotalSizeRequired(const SystemChar* dirIn); static std::optional<uint64_t> CalculateTotalSizeRequired(SystemStringView dirIn);
}; };
class DiscMergerGCN class DiscMergerGCN {
{
DiscGCN& m_sourceDisc; DiscGCN& m_sourceDisc;
DiscBuilderGCN m_builder; DiscBuilderGCN m_builder;
public: public:
DiscMergerGCN(const SystemChar* outPath, DiscGCN& sourceDisc, FProgress progressCB); DiscMergerGCN(SystemStringView outPath, DiscGCN& sourceDisc, FProgress progressCB);
EBuildResult mergeFromDirectory(const SystemChar* dirIn); EBuildResult mergeFromDirectory(SystemStringView dirIn);
static uint64_t CalculateTotalSizeRequired(DiscGCN& sourceDisc, const SystemChar* dirIn); static std::optional<uint64_t> CalculateTotalSizeRequired(DiscGCN& sourceDisc, SystemStringView dirIn);
}; };
} } // namespace nod
#endif // __NOD_DISC_GCN__

View File

@@ -1,41 +1,32 @@
#ifndef __NOD_DISC_WII__ #pragma once
#define __NOD_DISC_WII__
#include "DiscBase.hpp" #include "nod/DiscBase.hpp"
namespace nod namespace nod {
{
class DiscBuilderWii; class DiscBuilderWii;
class DiscWii : public DiscBase class DiscWii : public DiscBase {
{
public: public:
DiscWii(std::unique_ptr<IDiscIO>&& dio, bool& err); DiscWii(std::unique_ptr<IDiscIO>&& dio, bool& err);
DiscBuilderWii makeMergeBuilder(const SystemChar* outPath, bool dualLayer, FProgress progressCB); DiscBuilderWii makeMergeBuilder(SystemStringView outPath, bool dualLayer, FProgress progressCB);
bool extractDiscHeaderFiles(const SystemString& path, const ExtractionContext& ctx) const; bool extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const override;
}; };
class DiscBuilderWii : public DiscBuilderBase class DiscBuilderWii : public DiscBuilderBase {
{
bool m_dualLayer;
public: public:
DiscBuilderWii(const SystemChar* outPath, bool dualLayer, FProgress progressCB); DiscBuilderWii(SystemStringView outPath, bool dualLayer, FProgress progressCB);
EBuildResult buildFromDirectory(const SystemChar* dirIn); EBuildResult buildFromDirectory(SystemStringView dirIn);
static uint64_t CalculateTotalSizeRequired(const SystemChar* dirIn, bool& dualLayer); static std::optional<uint64_t> CalculateTotalSizeRequired(SystemStringView dirIn, bool& dualLayer);
}; };
class DiscMergerWii class DiscMergerWii {
{
DiscWii& m_sourceDisc; DiscWii& m_sourceDisc;
DiscBuilderWii m_builder; DiscBuilderWii m_builder;
public: public:
DiscMergerWii(const SystemChar* outPath, DiscWii& sourceDisc, DiscMergerWii(SystemStringView outPath, DiscWii& sourceDisc, bool dualLayer, FProgress progressCB);
bool dualLayer, FProgress progressCB); EBuildResult mergeFromDirectory(SystemStringView dirIn);
EBuildResult mergeFromDirectory(const SystemChar* dirIn); static std::optional<uint64_t> CalculateTotalSizeRequired(DiscWii& sourceDisc, SystemStringView dirIn, bool& dualLayer);
static uint64_t CalculateTotalSizeRequired(DiscWii& sourceDisc, const SystemChar* dirIn,
bool& dualLayer);
}; };
} } // namespace nod
#endif // __NOD_DISC_WII__

View File

@@ -1,75 +1,69 @@
#ifndef __NOD_IDISC_IO__ #pragma once
#define __NOD_IDISC_IO__
#include <cstdint>
#include <cstdio>
#include <memory> #include <memory>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#if NOD_ATHENA #if NOD_ATHENA
#include <athena/IStreamReader.hpp> #include <athena/IStreamReader.hpp>
#include <athena/IStreamWriter.hpp> #include <athena/IStreamWriter.hpp>
#endif #endif
namespace nod namespace nod {
{
struct IReadStream struct IReadStream {
{
virtual ~IReadStream() = default; virtual ~IReadStream() = default;
virtual uint64_t read(void* buf, uint64_t length) = 0; virtual uint64_t read(void* buf, uint64_t length) = 0;
virtual void seek(int64_t offset, int whence = SEEK_SET) = 0; virtual void seek(int64_t offset, int whence = SEEK_SET) = 0;
virtual uint64_t position() const = 0; virtual uint64_t position() const = 0;
}; };
struct IWriteStream struct IWriteStream {
{
virtual ~IWriteStream() = default; virtual ~IWriteStream() = default;
virtual uint64_t write(const void* buf, uint64_t length) = 0; virtual uint64_t write(const void* buf, uint64_t length) = 0;
}; };
class IDiscIO class IDiscIO {
{
public: public:
virtual ~IDiscIO() = default; virtual ~IDiscIO() = default;
virtual std::unique_ptr<IReadStream> beginReadStream(uint64_t offset = 0) const = 0; virtual std::unique_ptr<IReadStream> beginReadStream(uint64_t offset = 0) const = 0;
virtual std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset = 0) const = 0; virtual std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset = 0) const = 0;
virtual bool hasWiiCrypto() const { return true; } /* NFS overrides this to false */
}; };
struct IPartReadStream : IReadStream struct IPartReadStream : IReadStream {
{ ~IPartReadStream() override = default;
virtual ~IPartReadStream() = default;
}; };
struct IPartWriteStream : IWriteStream struct IPartWriteStream : IWriteStream {
{ ~IPartWriteStream() override = default;
virtual ~IPartWriteStream() = default;
virtual void close() = 0; virtual void close() = 0;
virtual uint64_t position() const = 0; virtual uint64_t position() const = 0;
}; };
#if NOD_ATHENA #if NOD_ATHENA
class AthenaPartReadStream : public athena::io::IStreamReader class AthenaPartReadStream : public athena::io::IStreamReader {
{
std::unique_ptr<IPartReadStream> m_rs; std::unique_ptr<IPartReadStream> m_rs;
public: public:
AthenaPartReadStream(std::unique_ptr<IPartReadStream>&& rs) : m_rs(std::move(rs)) {} AthenaPartReadStream(std::unique_ptr<IPartReadStream>&& rs) : m_rs(std::move(rs)) {}
inline void seek(atInt64 off, athena::SeekOrigin origin) void seek(atInt64 off, athena::SeekOrigin origin) override {
{ if (origin == athena::SeekOrigin::Begin) {
if (origin == athena::Begin)
m_rs->seek(off, SEEK_SET); m_rs->seek(off, SEEK_SET);
else if (origin == athena::Current) } else if (origin == athena::SeekOrigin::Current) {
m_rs->seek(off, SEEK_CUR); m_rs->seek(off, SEEK_CUR);
} }
inline atUint64 position() const {return m_rs->position();} }
inline atUint64 length() const {return 0;} atUint64 position() const override { return m_rs->position(); }
inline atUint64 readUBytesToBuf(void* buf, atUint64 sz) {m_rs->read(buf, sz); return sz;} atUint64 length() const override { return 0; }
atUint64 readUBytesToBuf(void* buf, atUint64 sz) override {
m_rs->read(buf, sz);
return sz;
}
}; };
#endif #endif
} } // namespace nod
#endif // __NOD_IDISC_IO__

View File

@@ -1,40 +1,35 @@
#ifndef __NOD_IFILE_IO__ #pragma once
#define __NOD_IFILE_IO__
#include <memory> #include <cstdint>
#include <functional> #include <functional>
#include <stdlib.h> #include <memory>
#include "IDiscIO.hpp"
#include "Util.hpp"
namespace nod #include "nod/IDiscIO.hpp"
{ #include "nod/Util.hpp"
class IFileIO #include <logvisor/logvisor.hpp>
{
namespace nod {
class IFileIO {
public: public:
virtual ~IFileIO() = default; virtual ~IFileIO() = default;
virtual bool exists() = 0; virtual bool exists() = 0;
virtual uint64_t size() = 0; virtual uint64_t size() = 0;
struct IWriteStream : nod::IWriteStream struct IWriteStream : nod::IWriteStream {
{ uint64_t copyFromDisc(IPartReadStream& discio, uint64_t length) {
uint64_t copyFromDisc(IPartReadStream& discio, uint64_t length)
{
uint64_t read = 0; uint64_t read = 0;
uint8_t buf[0x7c00]; uint8_t buf[0x7c00];
while (length) while (length) {
{
uint64_t thisSz = nod::min(uint64_t(0x7c00), length); uint64_t thisSz = nod::min(uint64_t(0x7c00), length);
uint64_t readSz = discio.read(buf, thisSz); uint64_t readSz = discio.read(buf, thisSz);
if (thisSz != readSz) if (thisSz != readSz) {
{ LogModule.report(logvisor::Error, FMT_STRING("unable to read enough from disc"));
LogModule.report(logvisor::Error, "unable to read enough from disc");
return read; return read;
} }
if (write(buf, readSz) != readSz) if (write(buf, readSz) != readSz) {
{ LogModule.report(logvisor::Error, FMT_STRING("unable to write in file"));
LogModule.report(logvisor::Error, "unable to write in file");
return read; return read;
} }
length -= thisSz; length -= thisSz;
@@ -42,23 +37,19 @@ public:
} }
return read; return read;
} }
uint64_t copyFromDisc(IPartReadStream& discio, uint64_t length, const std::function<void(float)>& prog) uint64_t copyFromDisc(IPartReadStream& discio, uint64_t length, const std::function<void(float)>& prog) {
{
uint64_t read = 0; uint64_t read = 0;
uint8_t buf[0x7c00]; uint8_t buf[0x7c00];
uint64_t total = length; uint64_t total = length;
while (length) while (length) {
{
uint64_t thisSz = nod::min(uint64_t(0x7c00), length); uint64_t thisSz = nod::min(uint64_t(0x7c00), length);
uint64_t readSz = discio.read(buf, thisSz); uint64_t readSz = discio.read(buf, thisSz);
if (thisSz != readSz) if (thisSz != readSz) {
{ LogModule.report(logvisor::Error, FMT_STRING("unable to read enough from disc"));
LogModule.report(logvisor::Error, "unable to read enough from disc");
return read; return read;
} }
if (write(buf, readSz) != readSz) if (write(buf, readSz) != readSz) {
{ LogModule.report(logvisor::Error, FMT_STRING("unable to write in file"));
LogModule.report(logvisor::Error, "unable to write in file");
return read; return read;
} }
length -= thisSz; length -= thisSz;
@@ -71,17 +62,13 @@ public:
virtual std::unique_ptr<IWriteStream> beginWriteStream() const = 0; virtual std::unique_ptr<IWriteStream> beginWriteStream() const = 0;
virtual std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const = 0; virtual std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const = 0;
struct IReadStream : nod::IReadStream struct IReadStream : nod::IReadStream {
{
virtual uint64_t copyToDisc(struct IPartWriteStream& discio, uint64_t length) = 0; virtual uint64_t copyToDisc(struct IPartWriteStream& discio, uint64_t length) = 0;
}; };
virtual std::unique_ptr<IReadStream> beginReadStream() const = 0; virtual std::unique_ptr<IReadStream> beginReadStream() const = 0;
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(const SystemString& path, int64_t maxWriteSize=-1); std::unique_ptr<IFileIO> NewFileIO(SystemStringView path, int64_t maxWriteSize = -1);
std::unique_ptr<IFileIO> NewFileIO(const SystemChar* path, int64_t maxWriteSize=-1);
} } // namespace nod
#endif // __NOD_IFILE_IO__

View File

@@ -1,8 +1,7 @@
#ifndef __NOD_UTIL_HPP__ #pragma once
#define __NOD_UTIL_HPP__
#if _WIN32 && UNICODE #if _WIN32 && UNICODE
#include <wctype.h> #include <cwctype>
#include <direct.h> #include <direct.h>
#ifndef WIN32_LEAN_AND_MEAN #ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1 #define WIN32_LEAN_AND_MEAN 1
@@ -11,21 +10,26 @@
#define NOMINMAX #define NOMINMAX
#endif #endif
#include <windows.h> #include <windows.h>
#if defined(WINAPI_FAMILY) && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP
#define WINDOWS_STORE 1
#else #else
#include <ctype.h> #define WINDOWS_STORE 0
#endif
#else
#include <cctype>
#include <cerrno>
#include <sys/file.h> #include <sys/file.h>
#include <unistd.h>
#include <errno.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/statvfs.h> #include <sys/statvfs.h>
#include <unistd.h>
#endif #endif
#include <sys/stat.h> #include <sys/stat.h>
#include <string>
#include <cstring>
#include <algorithm> #include <algorithm>
#include "logvisor/logvisor.hpp" #include <cstring>
#include <string>
#include <string_view>
#include <logvisor/logvisor.hpp>
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(disable : 4996) #pragma warning(disable : 4996)
@@ -47,13 +51,23 @@
#undef min #undef min
#undef max #undef max
namespace nod namespace nod {
{
/* define our own min/max to avoid MSVC BS */ /* define our own min/max to avoid MSVC BS */
template <typename T> template <typename T>
inline T min(T a, T b) { return a < b ? a : b; } constexpr T min(T a, T b) {
return a < b ? a : b;
}
template <typename T> template <typename T>
inline T max(T a, T b) { return a > b ? a : b; } constexpr T max(T a, T b) {
return a > b ? a : b;
}
/* template-based div for flexible typing and avoiding a library call */
template <typename T>
constexpr auto div(T a, T b) {
struct DivTp { T quot, rem; };
return DivTp{a / b, a % b};
}
/* Log Module */ /* Log Module */
extern logvisor::Module LogModule; extern logvisor::Module LogModule;
@@ -74,69 +88,66 @@ static inline int Stat(const char* path, Sstat* statout) {return stat(path, stat
#if NOD_UCS2 #if NOD_UCS2
typedef wchar_t SystemChar; typedef wchar_t SystemChar;
typedef std::wstring SystemString; typedef std::wstring SystemString;
static inline void ToLower(SystemString& str) typedef std::wstring_view SystemStringView;
{std::transform(str.begin(), str.end(), str.begin(), towlower);} static inline void ToLower(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), towlower); }
static inline void ToUpper(SystemString& str) static inline void ToUpper(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), towupper); }
{std::transform(str.begin(), str.end(), str.begin(), towupper);}
static inline size_t StrLen(const SystemChar* str) { return wcslen(str); } static inline size_t StrLen(const SystemChar* str) { return wcslen(str); }
class SystemUTF8View class SystemUTF8Conv {
{
std::string m_utf8; std::string m_utf8;
public: public:
explicit SystemUTF8View(const SystemString& str) explicit SystemUTF8Conv(SystemStringView str) {
{ int len = WideCharToMultiByte(CP_UTF8, 0, str.data(), str.size(), nullptr, 0, nullptr, nullptr);
int len = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), str.size(), nullptr, 0, nullptr, nullptr);
m_utf8.assign(len, '\0'); m_utf8.assign(len, '\0');
WideCharToMultiByte(CP_UTF8, 0, str.c_str(), str.size(), &m_utf8[0], len, nullptr, nullptr); WideCharToMultiByte(CP_UTF8, 0, str.data(), str.size(), &m_utf8[0], len, nullptr, nullptr);
} }
inline const std::string& utf8_str() {return m_utf8;} std::string_view utf8_str() const { return m_utf8; }
const char* c_str() const { return m_utf8.c_str(); }
}; };
class SystemStringView class SystemStringConv {
{
std::wstring m_sys; std::wstring m_sys;
public: public:
explicit SystemStringView(const std::string& str) explicit SystemStringConv(std::string_view str) {
{ int len = MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), nullptr, 0);
int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.size(), nullptr, 0);
m_sys.assign(len, L'\0'); m_sys.assign(len, L'\0');
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.size(), &m_sys[0], len); MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), &m_sys[0], len);
} }
inline const std::wstring& sys_str() {return m_sys;} SystemStringView sys_str() const { return m_sys; }
const SystemChar* c_str() const { return m_sys.c_str(); }
}; };
#ifndef _S #ifndef _SYS_STR
#define _S(val) L ## val #define _SYS_STR(val) L##val
#endif #endif
#else #else
typedef char SystemChar; typedef char SystemChar;
typedef std::string SystemString; typedef std::string SystemString;
static inline void ToLower(SystemString& str) typedef std::string_view SystemStringView;
{std::transform(str.begin(), str.end(), str.begin(), tolower);} static inline void ToLower(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), tolower); }
static inline void ToUpper(SystemString& str) static inline void ToUpper(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), toupper); }
{std::transform(str.begin(), str.end(), str.begin(), toupper);}
static inline size_t StrLen(const SystemChar* str) { return strlen(str); } static inline size_t StrLen(const SystemChar* str) { return strlen(str); }
class SystemUTF8View class SystemUTF8Conv {
{ std::string_view m_utf8;
const std::string& m_utf8;
public: public:
explicit SystemUTF8View(const SystemString& str) explicit SystemUTF8Conv(SystemStringView str) : m_utf8(str) {}
: m_utf8(str) {} std::string_view utf8_str() const { return m_utf8; }
inline const std::string& utf8_str() {return m_utf8;} const char* c_str() const { return m_utf8.data(); }
}; };
class SystemStringView class SystemStringConv {
{ SystemStringView m_sys;
const std::string& m_sys;
public: public:
explicit SystemStringView(const std::string& str) explicit SystemStringConv(std::string_view str) : m_sys(str) {}
: m_sys(str) {} SystemStringView sys_str() const { return m_sys; }
inline const std::string& sys_str() {return m_sys;} const SystemChar* c_str() const { return m_sys.data(); }
}; };
#ifndef _S #ifndef _SYS_STR
#define _S(val) val #define _SYS_STR(val) val
#endif #endif
#endif #endif
static inline void Unlink(const SystemChar* file) static inline void Unlink(const SystemChar* file) {
{
#if NOD_UCS2 #if NOD_UCS2
_wunlink(file); _wunlink(file);
#else #else
@@ -144,8 +155,7 @@ static inline void Unlink(const SystemChar* file)
#endif #endif
} }
static inline int StrCmp(const SystemChar* str1, const SystemChar* str2) static inline int StrCmp(const SystemChar* str1, const SystemChar* str2) {
{
#if NOD_UCS2 #if NOD_UCS2
return wcscmp(str1, str2); return wcscmp(str1, str2);
#else #else
@@ -153,8 +163,7 @@ static inline int StrCmp(const SystemChar* str1, const SystemChar* str2)
#endif #endif
} }
static inline int StrCaseCmp(const SystemChar* str1, const SystemChar* str2) static inline int StrCaseCmp(const SystemChar* str1, const SystemChar* str2) {
{
#if NOD_UCS2 #if NOD_UCS2
return _wcsicmp(str1, str2); return _wcsicmp(str1, str2);
#else #else
@@ -167,8 +176,7 @@ static inline int StrCaseCmp(const SystemChar* str1, const SystemChar* str2)
#undef bswap64 #undef bswap64
/* Type-sensitive byte swappers */ /* Type-sensitive byte swappers */
template <typename T> template <typename T>
static inline T bswap16(T val) static inline T bswap16(T val) {
{
#if __GNUC__ #if __GNUC__
return __builtin_bswap16(val); return __builtin_bswap16(val);
#elif _WIN32 #elif _WIN32
@@ -179,8 +187,7 @@ static inline T bswap16(T val)
} }
template <typename T> template <typename T>
static inline T bswap32(T val) static inline T bswap32(T val) {
{
#if __GNUC__ #if __GNUC__
return __builtin_bswap32(val); return __builtin_bswap32(val);
#elif _WIN32 #elif _WIN32
@@ -193,25 +200,19 @@ static inline T bswap32(T val)
} }
template <typename T> template <typename T>
static inline T bswap64(T val) static inline T bswap64(T val) {
{
#if __GNUC__ #if __GNUC__
return __builtin_bswap64(val); return __builtin_bswap64(val);
#elif _WIN32 #elif _WIN32
return _byteswap_uint64(val); return _byteswap_uint64(val);
#else #else
return ((val & 0xFF00000000000000ULL) >> 56) | return ((val & 0xFF00000000000000ULL) >> 56) | ((val & 0x00FF000000000000ULL) >> 40) |
((val & 0x00FF000000000000ULL) >> 40) | ((val & 0x0000FF0000000000ULL) >> 24) | ((val & 0x000000FF00000000ULL) >> 8) |
((val & 0x0000FF0000000000ULL) >> 24) | ((val & 0x00000000FF000000ULL) << 8) | ((val & 0x0000000000FF0000ULL) << 24) |
((val & 0x000000FF00000000ULL) >> 8) | ((val & 0x000000000000FF00ULL) << 40) | ((val & 0x00000000000000FFULL) << 56);
((val & 0x00000000FF000000ULL) << 8) |
((val & 0x0000000000FF0000ULL) << 24) |
((val & 0x000000000000FF00ULL) << 40) |
((val & 0x00000000000000FFULL) << 56);
#endif #endif
} }
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
static inline int16_t SBig(int16_t val) { return bswap16(val); } static inline int16_t SBig(int16_t val) { return bswap16(val); }
static inline uint16_t SBig(uint16_t val) { return bswap16(val); } static inline uint16_t SBig(uint16_t val) { return bswap16(val); }
@@ -247,14 +248,8 @@ static inline uint64_t SBig(uint64_t val) {return val;}
#define ROUND_UP_16(val) (((val) + 15) & ~15) #define ROUND_UP_16(val) (((val) + 15) & ~15)
#endif #endif
enum class FileLockType enum class FileLockType { None = 0, Read, Write };
{ static inline FILE* Fopen(const SystemChar* path, const SystemChar* mode, FileLockType lock = FileLockType::None) {
None = 0,
Read,
Write
};
static inline FILE* Fopen(const SystemChar* path, const SystemChar* mode, FileLockType lock=FileLockType::None)
{
#if NOD_UCS2 #if NOD_UCS2
FILE* fp = _wfopen(path, mode); FILE* fp = _wfopen(path, mode);
if (!fp) if (!fp)
@@ -265,88 +260,65 @@ static inline FILE* Fopen(const SystemChar* path, const SystemChar* mode, FileLo
return nullptr; return nullptr;
#endif #endif
if (lock != FileLockType::None) if (lock != FileLockType::None) {
{
#if _WIN32 #if _WIN32
OVERLAPPED ov = {}; OVERLAPPED ov = {};
LockFileEx((HANDLE)(uintptr_t)_fileno(fp), (lock == FileLockType::Write) ? LOCKFILE_EXCLUSIVE_LOCK : 0, 0, 0, 1, &ov); LockFileEx((HANDLE)(uintptr_t)_fileno(fp), (lock == FileLockType::Write) ? LOCKFILE_EXCLUSIVE_LOCK : 0, 0, 0, 1,
#else &ov);
#elif !defined(__SWITCH__)
if (flock(fileno(fp), ((lock == FileLockType::Write) ? LOCK_EX : LOCK_SH) | LOCK_NB)) if (flock(fileno(fp), ((lock == FileLockType::Write) ? LOCK_EX : LOCK_SH) | LOCK_NB))
LogModule.report(logvisor::Error, "flock %s: %s", path, strerror(errno)); LogModule.report(logvisor::Error, FMT_STRING("flock {}: {}"), path, strerror(errno));
#endif #endif
} }
return fp; return fp;
} }
static inline int FSeek(FILE* fp, int64_t offset, int whence) static inline int FSeek(FILE* fp, int64_t offset, int whence) {
{
#if _WIN32 #if _WIN32
return _fseeki64(fp, offset, whence); return _fseeki64(fp, offset, whence);
#elif __APPLE__ || __FreeBSD__ #elif __APPLE__ || __FreeBSD__ || __SWITCH__
return fseeko(fp, offset, whence); return fseeko(fp, offset, whence);
#else #else
return fseeko64(fp, offset, whence); return fseeko64(fp, offset, whence);
#endif #endif
} }
static inline int64_t FTell(FILE* fp) static inline int64_t FTell(FILE* fp) {
{
#if _WIN32 #if _WIN32
return _ftelli64(fp); return _ftelli64(fp);
#elif __APPLE__ || __FreeBSD__ #elif __APPLE__ || __FreeBSD__ || __SWITCH__
return ftello(fp); return ftello(fp);
#else #else
return ftello64(fp); return ftello64(fp);
#endif #endif
} }
static inline bool CheckFreeSpace(const SystemChar* path, size_t reqSz) static inline bool CheckFreeSpace(const SystemChar* path, size_t reqSz) {
{
#if _WIN32 #if _WIN32
ULARGE_INTEGER freeBytes; ULARGE_INTEGER freeBytes;
wchar_t buf[1024]; wchar_t buf[1024];
wchar_t* end; wchar_t* end;
DWORD ret = GetFullPathNameW(path, 1024, buf, &end); DWORD ret = GetFullPathNameW(path, 1024, buf, &end);
if (!ret || ret > 1024) if (!ret || ret > 1024) {
{ LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("GetFullPathNameW {}")), path);
LogModule.report(logvisor::Error, _S("GetFullPathNameW %s"), path);
return false; return false;
} }
if (end) if (end)
end[0] = L'\0'; end[0] = L'\0';
if (!GetDiskFreeSpaceExW(buf, &freeBytes, nullptr, nullptr)) if (!GetDiskFreeSpaceExW(buf, &freeBytes, nullptr, nullptr)) {
{ LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("GetDiskFreeSpaceExW {}: {}")), path, GetLastError());
LogModule.report(logvisor::Error, _S("GetDiskFreeSpaceExW %s: %d"), path, GetLastError());
return false; return false;
} }
return reqSz < freeBytes.QuadPart; return reqSz < freeBytes.QuadPart;
#else #else
struct statvfs svfs; struct statvfs svfs;
if (statvfs(path, &svfs)) if (statvfs(path, &svfs)) {
{ LogModule.report(logvisor::Error, FMT_STRING("statvfs {}: {}"), path, strerror(errno));
LogModule.report(logvisor::Error, "statvfs %s: %s", path, strerror(errno));
return false; return false;
} }
return reqSz < svfs.f_frsize * svfs.f_bavail; return reqSz < svfs.f_frsize * svfs.f_bavail;
#endif #endif
} }
#if __GNUC__ } // namespace nod
__attribute__((__format__ (__printf__, 1, 2)))
#endif
static inline void Printf(const SystemChar* fmt, ...)
{
va_list args;
va_start(args, fmt);
#if NOD_UCS2
vwprintf(fmt, args);
#else
vprintf(fmt, args);
#endif
va_end(args);
}
}
#endif // __NOD_UTIL_HPP__

View File

@@ -1,15 +1,12 @@
#ifndef __AES_HPP__ #pragma once
#define __AES_HPP__
#include <stdint.h> #include <cstdint>
#include <stdlib.h> #include <cstdlib>
#include <memory> #include <memory>
namespace nod namespace nod {
{
class IAES class IAES {
{
public: public:
virtual ~IAES() = default; virtual ~IAES() = default;
virtual void encrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len) = 0; virtual void encrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len) = 0;
@@ -19,6 +16,4 @@ public:
std::unique_ptr<IAES> NewAES(); std::unique_ptr<IAES> NewAES();
} } // namespace nod
#endif //__AES_HPP__

View File

@@ -1,29 +1,21 @@
#ifndef __NOD_LIB__ #pragma once
#define __NOD_LIB__
#include <memory>
#include <functional> #include <functional>
#include "logvisor/logvisor.hpp" #include <memory>
#include "Util.hpp" #include <string>
namespace nod #include "nod/Util.hpp"
{
namespace nod {
class DiscBase; class DiscBase;
struct ExtractionContext final struct ExtractionContext final {
{
bool force : 1; bool force : 1;
std::function<void(const std::string&, float)> progressCB; std::function<void(std::string_view, float)> progressCB;
}; };
std::unique_ptr<DiscBase> OpenDiscFromImage(const SystemChar* path); std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path);
std::unique_ptr<DiscBase> OpenDiscFromImage(const SystemChar* path, bool& isWii); std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path, bool& isWii);
} } // namespace nod
#include "DiscGCN.hpp"
#include "DiscWii.hpp"
#include "IDiscIO.hpp"
#endif // __NOD_LIB__

View File

@@ -1,21 +1,51 @@
if(NOT WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-multichar")
set(PLAT_SRCS FileIOFILE.cpp)
else()
set(PLAT_SRCS FileIOWin32.cpp)
endif()
add_library(nod add_library(nod
aes.cpp aes.cpp
sha1.c sha1.c
DirectoryEnumerator.cpp
DiscBase.cpp DiscBase.cpp
DiscGCN.cpp DiscGCN.cpp
DiscIOISO.cpp DiscIOISO.cpp
DiscIONFS.cpp
DiscIOWBFS.cpp DiscIOWBFS.cpp
DiscWii.cpp DiscWii.cpp
DirectoryEnumerator.cpp
nod.cpp nod.cpp
${PLAT_SRCS}
${NOD_HEADERS}) ../include/nod/aes.hpp
if(NOT MSVC) ../include/nod/DirectoryEnumerator.hpp
../include/nod/DiscBase.hpp
../include/nod/DiscGCN.hpp
../include/nod/DiscWii.hpp
../include/nod/IDiscIO.hpp
../include/nod/IFileIO.hpp
../include/nod/nod.hpp
../include/nod/sha1.h
../include/nod/Util.hpp
)
target_include_directories(nod PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
)
target_link_libraries(nod PUBLIC logvisor)
if(WIN32)
target_sources(nod PRIVATE FileIOWin32.cpp)
else()
target_compile_options(nod PRIVATE -Wno-multichar)
target_sources(nod PRIVATE FileIOFILE.cpp)
endif()
if(NOT MSVC AND NOT NX)
set_source_files_properties(aes.cpp PROPERTIES COMPILE_FLAGS -maes) set_source_files_properties(aes.cpp PROPERTIES COMPILE_FLAGS -maes)
endif() endif()
# Associate target with export
install(
TARGETS nod
EXPORT nodTargets
ARCHIVE DESTINATION "lib"
INCLUDES DESTINATION include # This sets the INTERFACE_INCLUDE_DIRECTORIES property of the target.
)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../include/nod DESTINATION include)

View File

@@ -1,3 +1,5 @@
#include "nod/DirectoryEnumerator.hpp"
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
#else #else
@@ -5,38 +7,32 @@
#include <dirent.h> #include <dirent.h>
#endif #endif
#include <cstring>
#include <map> #include <map>
#include "nod/DirectoryEnumerator.hpp" namespace nod {
namespace nod DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode, bool sizeSort, bool reverse, bool noHidden) {
{
DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
bool sizeSort, bool reverse, bool noHidden)
{
Sstat theStat; Sstat theStat;
if (Stat(path, &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); SystemString wc(path);
wc += _S("/*"); wc += _SYS_STR("/*");
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, _S(".")) || !wcscmp(d.cFileName, _S("..")))
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); SystemString fp(path);
fp += _S('/'); fp += _SYS_STR('/');
fp += d.cFileName; fp += d.cFileName;
Sstat st; Sstat st;
if (Stat(fp.c_str(), &st)) if (Stat(fp.c_str(), &st))
@@ -51,26 +47,24 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
else else
continue; continue;
m_entries.push_back(std::move(Entry(std::move(fp), d.cFileName, sz, isDir))); m_entries.push_back(Entry(fp, d.cFileName, 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<SystemString, Entry, CaseInsensitiveCompare> sort;
do do {
{ if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
if (!wcscmp(d.cFileName, _S(".")) || !wcscmp(d.cFileName, _S("..")))
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); SystemString fp(path);
fp +=_S('/'); fp += _SYS_STR('/');
fp += d.cFileName; fp += d.cFileName;
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(std::move(fp), d.cFileName, 0, true))); sort.emplace(std::make_pair(d.cFileName, Entry(fp, d.cFileName, 0, true)));
} while (FindNextFileW(dir, &d)); } while (FindNextFileW(dir, &d));
m_entries.reserve(sort.size()); m_entries.reserve(sort.size());
@@ -86,27 +80,24 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
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, _S(".")) || !wcscmp(d.cFileName, _S("..")))
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); SystemString fp(path);
fp += _S('/'); fp += _SYS_STR('/');
fp += d.cFileName; fp += d.cFileName;
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(std::move(fp), d.cFileName, st.st_size, false))); sort.emplace(std::make_pair(st.st_size, Entry(fp, d.cFileName, st.st_size, false)));
} while (FindNextFileW(dir, &d)); } while (FindNextFileW(dir, &d));
m_entries.reserve(sort.size()); m_entries.reserve(sort.size());
@@ -116,23 +107,20 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
else else
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<SystemString, Entry, CaseInsensitiveCompare> sort;
do do {
{ if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
if (!wcscmp(d.cFileName, _S(".")) || !wcscmp(d.cFileName, _S("..")))
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); SystemString fp(path);
fp += _S('/'); fp += _SYS_STR('/');
fp += d.cFileName; fp += d.cFileName;
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(std::move(fp), d.cFileName, st.st_size, false))); sort.emplace(std::make_pair(d.cFileName, Entry(fp, d.cFileName, st.st_size, false)));
} while (FindNextFileW(dir, &d)); } while (FindNextFileW(dir, &d));
m_entries.reserve(sort.size()); m_entries.reserve(sort.size());
@@ -151,15 +139,13 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
#else #else
DIR* dir = opendir(path); DIR* dir = opendir(path.data());
if (!dir) if (!dir)
return; return;
const dirent* d; const dirent* d;
switch (mode) switch (mode) {
{
case Mode::Native: case Mode::Native:
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] == '.')
@@ -180,15 +166,13 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
else else
continue; continue;
m_entries.push_back(Entry(std::move(fp), d->d_name, sz, isDir)); m_entries.push_back(Entry(fp, d->d_name, sz, isDir));
} }
break; break;
case Mode::DirsThenFilesSorted: case Mode::DirsThenFilesSorted:
case Mode::DirsSorted: case Mode::DirsSorted: {
{
std::map<SystemString, Entry, CaseInsensitiveCompare> sort; std::map<SystemString, 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] == '.')
@@ -199,7 +183,7 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
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->d_name, Entry(std::move(fp), d->d_name, 0, true))); sort.emplace(std::make_pair(d->d_name, Entry(fp, d->d_name, 0, true)));
} }
m_entries.reserve(sort.size()); m_entries.reserve(sort.size());
@@ -213,17 +197,15 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
if (mode == Mode::DirsSorted) if (mode == Mode::DirsSorted)
break; break;
rewinddir(dir); rewinddir(dir);
[[fallthrough]];
} }
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;
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] == '.')
@@ -234,7 +216,7 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
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(std::move(fp), d->d_name, st.st_size, false))); sort.emplace(std::make_pair(st.st_size, Entry(fp, d->d_name, st.st_size, false)));
} }
m_entries.reserve(sort.size()); m_entries.reserve(sort.size());
@@ -244,12 +226,9 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
else else
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<SystemString, 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] == '.')
@@ -260,7 +239,7 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
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->d_name, Entry(std::move(fp), d->d_name, st.st_size, false))); sort.emplace(std::make_pair(d->d_name, Entry(fp, d->d_name, st.st_size, false)));
} }
m_entries.reserve(sort.size()); m_entries.reserve(sort.size());
@@ -280,4 +259,4 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
#endif #endif
} }
} } // namespace nod

File diff suppressed because it is too large Load Diff

View File

@@ -1,21 +1,27 @@
#include "nod/DiscGCN.hpp" #include "nod/DiscGCN.hpp"
#include <cinttypes>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include "nod/nod.hpp" #include "nod/nod.hpp"
#include <inttypes.h> #include "nod/Util.hpp"
#include <logvisor/logvisor.hpp>
#define BUFFER_SZ 0x8000 #define BUFFER_SZ 0x8000
namespace nod namespace nod {
{
class PartitionGCN : public DiscBase::IPartition class PartitionGCN : public IPartition {
{
public: public:
PartitionGCN(const DiscGCN& parent, uint64_t offset, bool& err) PartitionGCN(const DiscGCN& parent, uint64_t offset, bool& err)
: IPartition(parent, PartitionKind::Data, false, offset) : 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) {
{
err = true; err = true;
return; return;
} }
@@ -37,8 +43,7 @@ public:
parseDOL(*s); parseDOL(*s);
} }
class PartReadStream : public IPartReadStream class PartReadStream : public IPartReadStream {
{
const PartitionGCN& m_parent; const PartitionGCN& m_parent;
std::unique_ptr<IReadStream> m_dio; std::unique_ptr<IReadStream> m_dio;
@@ -47,21 +52,17 @@ public:
uint8_t m_buf[BUFFER_SZ]; uint8_t m_buf[BUFFER_SZ];
public: public:
PartReadStream(const PartitionGCN& parent, uint64_t offset, bool& err) PartReadStream(const PartitionGCN& parent, uint64_t offset, bool& err) : m_parent(parent), m_offset(offset) {
: m_parent(parent), m_offset(offset)
{
size_t block = m_offset / BUFFER_SZ; size_t block = m_offset / BUFFER_SZ;
m_dio = m_parent.m_parent.getDiscIO().beginReadStream(block * BUFFER_SZ); m_dio = m_parent.m_parent.getDiscIO().beginReadStream(block * BUFFER_SZ);
if (!m_dio) if (!m_dio) {
{
err = true; err = true;
return; return;
} }
m_dio->read(m_buf, BUFFER_SZ); m_dio->read(m_buf, BUFFER_SZ);
m_curBlock = block; m_curBlock = block;
} }
void seek(int64_t offset, int whence) void seek(int64_t offset, int whence) override {
{
if (whence == SEEK_SET) if (whence == SEEK_SET)
m_offset = offset; m_offset = offset;
else if (whence == SEEK_CUR) else if (whence == SEEK_CUR)
@@ -69,26 +70,22 @@ public:
else else
return; return;
size_t block = m_offset / BUFFER_SZ; size_t block = m_offset / BUFFER_SZ;
if (block != m_curBlock) if (block != m_curBlock) {
{
m_dio->seek(block * BUFFER_SZ); m_dio->seek(block * BUFFER_SZ);
m_dio->read(m_buf, BUFFER_SZ); m_dio->read(m_buf, BUFFER_SZ);
m_curBlock = block; m_curBlock = block;
} }
} }
uint64_t position() const {return m_offset;} uint64_t position() const override { return m_offset; }
uint64_t read(void* buf, uint64_t length) uint64_t read(void* buf, uint64_t length) override {
{
size_t block = m_offset / BUFFER_SZ; size_t block = m_offset / BUFFER_SZ;
size_t cacheOffset = m_offset % BUFFER_SZ; size_t cacheOffset = m_offset % BUFFER_SZ;
uint64_t cacheSize; uint64_t cacheSize;
uint64_t rem = length; uint64_t rem = length;
uint8_t* dst = (uint8_t*)buf; uint8_t* dst = (uint8_t*)buf;
while (rem) while (rem) {
{ if (block != m_curBlock) {
if (block != m_curBlock)
{
m_dio->read(m_buf, BUFFER_SZ); m_dio->read(m_buf, BUFFER_SZ);
m_curBlock = block; m_curBlock = block;
} }
@@ -109,65 +106,56 @@ public:
} }
}; };
std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset) const std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset) const override {
{ bool err = false;
bool Err = false; auto ret = std::make_unique<PartReadStream>(*this, offset, err);
auto ret = std::unique_ptr<IPartReadStream>(new PartReadStream(*this, offset, Err));
if (Err) if (err) {
return {}; return nullptr;
}
return ret; return ret;
} }
}; };
DiscGCN::DiscGCN(std::unique_ptr<IDiscIO>&& dio, bool& err) DiscGCN::DiscGCN(std::unique_ptr<IDiscIO>&& dio, bool& err) : DiscBase(std::move(dio), 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(new PartitionGCN(*this, 0, err)); m_partitions.emplace_back(std::make_unique<PartitionGCN>(*this, 0, err));
} }
DiscBuilderGCN DiscGCN::makeMergeBuilder(const SystemChar* outPath, FProgress progressCB) DiscBuilderGCN DiscGCN::makeMergeBuilder(SystemStringView outPath, FProgress progressCB) {
{
return DiscBuilderGCN(outPath, progressCB); return DiscBuilderGCN(outPath, progressCB);
} }
bool DiscGCN::extractDiscHeaderFiles(const SystemString& path, const ExtractionContext& ctx) const bool DiscGCN::extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const { return true; }
{
return true;
}
class PartitionBuilderGCN : public DiscBuilderBase::PartitionBuilderBase class PartitionBuilderGCN : public DiscBuilderBase::PartitionBuilderBase {
{
uint64_t m_curUser = 0x57058000; uint64_t m_curUser = 0x57058000;
public: public:
class PartWriteStream : public IPartWriteStream class PartWriteStream : public IPartWriteStream {
{
const PartitionBuilderGCN& m_parent; const PartitionBuilderGCN& m_parent;
uint64_t m_offset; uint64_t m_offset;
std::unique_ptr<IFileIO::IWriteStream> m_fio; std::unique_ptr<IFileIO::IWriteStream> m_fio;
public: public:
PartWriteStream(const PartitionBuilderGCN& parent, uint64_t offset, bool& err) PartWriteStream(const PartitionBuilderGCN& parent, uint64_t offset, bool& err)
: m_parent(parent), m_offset(offset) : m_parent(parent), m_offset(offset) {
{
m_fio = m_parent.m_parent.getFileIO().beginWriteStream(offset); m_fio = m_parent.m_parent.getFileIO().beginWriteStream(offset);
if (!m_fio) if (!m_fio)
err = true; err = true;
} }
void close() {m_fio.reset();} void close() override { m_fio.reset(); }
uint64_t position() const {return m_offset;} uint64_t position() const override { return m_offset; }
uint64_t write(const void* buf, uint64_t length) uint64_t write(const void* buf, uint64_t length) override {
{
uint64_t len = m_fio->write(buf, length); uint64_t len = m_fio->write(buf, length);
m_offset += len; m_offset += len;
return len; return len;
} }
void seek(size_t off) void seek(size_t off) {
{
m_offset = off; m_offset = off;
m_fio = m_parent.m_parent.getFileIO().beginWriteStream(off); m_fio = m_parent.m_parent.getFileIO().beginWriteStream(off);
} }
@@ -176,38 +164,34 @@ public:
PartitionBuilderGCN(DiscBuilderBase& parent) PartitionBuilderGCN(DiscBuilderBase& parent)
: DiscBuilderBase::PartitionBuilderBase(parent, PartitionKind::Data, false) {} : DiscBuilderBase::PartitionBuilderBase(parent, PartitionKind::Data, false) {}
uint64_t userAllocate(uint64_t reqSz, IPartWriteStream& ws) uint64_t userAllocate(uint64_t reqSz, IPartWriteStream& ws) override {
{
m_curUser -= reqSz; m_curUser -= reqSz;
m_curUser &= 0xfffffffffffffff0; m_curUser &= 0xfffffffffffffff0;
if (m_curUser < 0x30000) if (m_curUser < 0x30000) {
{ LogModule.report(logvisor::Error, FMT_STRING("user area low mark reached"));
LogModule.report(logvisor::Error, "user area low mark reached");
return -1; return -1;
} }
static_cast<PartWriteStream&>(ws).seek(m_curUser); static_cast<PartWriteStream&>(ws).seek(m_curUser);
return m_curUser; return m_curUser;
} }
uint32_t packOffset(uint64_t offset) const uint32_t packOffset(uint64_t offset) const override { return offset; }
{
return offset; std::unique_ptr<IPartWriteStream> beginWriteStream(uint64_t offset) override {
bool err = false;
auto ret = std::make_unique<PartWriteStream>(*this, offset, err);
if (err) {
return nullptr;
} }
std::unique_ptr<IPartWriteStream> beginWriteStream(uint64_t offset)
{
bool Err = false;
std::unique_ptr<IPartWriteStream> ret = std::make_unique<PartWriteStream>(*this, offset, Err);
if (Err)
return {};
return ret; return ret;
} }
bool _build(const std::function<bool(IPartWriteStream&, uint32_t, uint32_t, bool
uint32_t, uint32_t, uint32_t)>& headerFunc, _build(const std::function<bool(IPartWriteStream&, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t)>& headerFunc,
const std::function<bool(IPartWriteStream&)>& bi2Func, const std::function<bool(IPartWriteStream&)>& bi2Func,
const std::function<bool(IPartWriteStream&, size_t&)>& apploaderFunc) const std::function<bool(IPartWriteStream&, size_t&)>& apploaderFunc) {
{
std::unique_ptr<IPartWriteStream> ws = beginWriteStream(0x2440); std::unique_ptr<IPartWriteStream> ws = beginWriteStream(0x2440);
if (!ws) if (!ws)
return false; return false;
@@ -226,10 +210,8 @@ public:
fstSz += m_buildNameOff; fstSz += m_buildNameOff;
fstSz = ROUND_UP_32(fstSz); fstSz = ROUND_UP_32(fstSz);
if (fstOff + fstSz >= m_curUser) if (fstOff + fstSz >= m_curUser) {
{ LogModule.report(logvisor::Error, FMT_STRING("FST flows into user area (one or the other is too big)"));
LogModule.report(logvisor::Error,
"FST flows into user area (one or the other is too big)");
return false; return false;
} }
@@ -244,8 +226,7 @@ public:
return true; return true;
} }
bool buildFromDirectory(const SystemChar* dirIn) bool buildFromDirectory(SystemStringView dirIn) {
{
std::unique_ptr<IPartWriteStream> ws = beginWriteStream(0); std::unique_ptr<IPartWriteStream> ws = beginWriteStream(0);
if (!ws) if (!ws)
return false; return false;
@@ -256,36 +237,32 @@ public:
SystemString dirStr(dirIn); SystemString dirStr(dirIn);
/* Check Apploader */ /* Check Apploader */
SystemString apploaderIn = dirStr + _S("/sys/apploader.img"); SystemString apploaderIn = dirStr + _SYS_STR("/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, _S("unable to stat %s"), apploaderIn.c_str()); return false;
return -1;
} }
/* Check Boot */ /* Check Boot */
SystemString bootIn = dirStr + _S("/sys/boot.bin"); SystemString bootIn = dirStr + _SYS_STR("/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, _S("unable to stat %s"), bootIn.c_str()); return false;
return -1;
} }
/* Check BI2 */ /* Check BI2 */
SystemString bi2In = dirStr + _S("/sys/bi2.bin"); SystemString bi2In = dirStr + _SYS_STR("/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, _S("unable to stat %s"), bi2In.c_str()); return false;
return -1;
} }
return _build( return _build(
[this, &bootIn](IPartWriteStream& ws, uint32_t dolOff, uint32_t fstOff, uint32_t fstSz, [&bootIn](IPartWriteStream& ws, uint32_t dolOff, uint32_t fstOff, uint32_t fstSz, uint32_t userOff,
uint32_t userOff, uint32_t userSz) -> bool uint32_t userSz) -> bool {
{
std::unique_ptr<IFileIO::IReadStream> rs = NewFileIO(bootIn.c_str())->beginReadStream(); std::unique_ptr<IFileIO::IReadStream> rs = NewFileIO(bootIn.c_str())->beginReadStream();
if (!rs) if (!rs)
return false; return false;
@@ -300,8 +277,7 @@ public:
header.write(ws); header.write(ws);
return true; return true;
}, },
[this, &bi2In](IPartWriteStream& ws) -> bool [&bi2In](IPartWriteStream& ws) -> bool {
{
std::unique_ptr<IFileIO::IReadStream> rs = NewFileIO(bi2In.c_str())->beginReadStream(); std::unique_ptr<IFileIO::IReadStream> rs = NewFileIO(bi2In.c_str())->beginReadStream();
if (!rs) if (!rs)
return false; return false;
@@ -310,23 +286,19 @@ public:
bi2.write(ws); bi2.write(ws);
return true; return true;
}, },
[this, &apploaderIn](IPartWriteStream& ws, size_t& xferSz) -> bool [this, &apploaderIn](IPartWriteStream& ws, size_t& xferSz) -> bool {
{
std::unique_ptr<IFileIO::IReadStream> rs = NewFileIO(apploaderIn.c_str())->beginReadStream(); std::unique_ptr<IFileIO::IReadStream> rs = NewFileIO(apploaderIn.c_str())->beginReadStream();
if (!rs) if (!rs)
return false; return false;
char buf[8192]; char buf[8192];
while (true) while (true) {
{
size_t rdSz = rs->read(buf, 8192); size_t rdSz = rs->read(buf, 8192);
if (!rdSz) if (!rdSz)
break; break;
ws.write(buf, rdSz); ws.write(buf, rdSz);
xferSz += rdSz; xferSz += rdSz;
if (0x2440 + xferSz >= m_curUser) if (0x2440 + xferSz >= m_curUser) {
{ LogModule.report(logvisor::Error, FMT_STRING("apploader flows into user area (one or the other is too big)"));
LogModule.report(logvisor::Error,
"apploader flows into user area (one or the other is too big)");
return false; return false;
} }
m_parent.m_progressCB(m_parent.getProgressFactor(), apploaderIn, xferSz); m_parent.m_progressCB(m_parent.getProgressFactor(), apploaderIn, xferSz);
@@ -336,8 +308,7 @@ public:
}); });
} }
bool mergeFromDirectory(const PartitionGCN* partIn, const SystemChar* dirIn) bool mergeFromDirectory(const PartitionGCN* partIn, SystemStringView dirIn) {
{
std::unique_ptr<IPartWriteStream> ws = beginWriteStream(0); std::unique_ptr<IPartWriteStream> ws = beginWriteStream(0);
if (!ws) if (!ws)
return false; return false;
@@ -346,9 +317,8 @@ public:
return false; return false;
return _build( return _build(
[this, partIn](IPartWriteStream& ws, uint32_t dolOff, uint32_t fstOff, uint32_t fstSz, [partIn](IPartWriteStream& ws, uint32_t dolOff, uint32_t fstOff, uint32_t fstSz, uint32_t userOff,
uint32_t userOff, uint32_t userSz) -> bool uint32_t userSz) -> bool {
{
Header header = partIn->getHeader(); Header header = partIn->getHeader();
header.m_dolOff = dolOff; header.m_dolOff = dolOff;
header.m_fstOff = fstOff; header.m_fstOff = fstOff;
@@ -359,22 +329,18 @@ public:
header.write(ws); header.write(ws);
return true; return true;
}, },
[this, partIn](IPartWriteStream& ws) -> bool [partIn](IPartWriteStream& ws) -> bool {
{
partIn->getBI2().write(ws); partIn->getBI2().write(ws);
return true; return true;
}, },
[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(_S("<apploader>")); SystemString apploaderName(_SYS_STR("<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) {
{ LogModule.report(logvisor::Error, FMT_STRING("apploader flows into user area (one or the other is too big)"));
LogModule.report(logvisor::Error,
"apploader flows into user area (one or the other is too big)");
return false; return false;
} }
m_parent.m_progressCB(m_parent.getProgressFactor(), apploaderName, xferSz); m_parent.m_progressCB(m_parent.getProgressFactor(), apploaderName, xferSz);
@@ -384,85 +350,82 @@ public:
} }
}; };
EBuildResult DiscBuilderGCN::buildFromDirectory(const SystemChar* dirIn) EBuildResult DiscBuilderGCN::buildFromDirectory(SystemStringView 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, _S("not enough free disk space for %s"), m_outPath.c_str());
return EBuildResult::DiskFull; return EBuildResult::DiskFull;
} }
m_progressCB(getProgressFactor(), _S("Preallocating image"), -1); m_progressCB(getProgressFactor(), _SYS_STR("Preallocating image"), -1);
++m_progressIdx; ++m_progressIdx;
auto ws = m_fileIO->beginWriteStream(0x57058000 - 1); {
auto ws = m_fileIO->beginWriteStream(0);
if (!ws) if (!ws)
return EBuildResult::Failed; return EBuildResult::Failed;
ws->write("", 1); char zeroBytes[1024] = {};
for (uint64_t i = 0; i < 0x57058000; i += 1024)
ws->write(zeroBytes, 1024);
}
PartitionBuilderGCN& pb = static_cast<PartitionBuilderGCN&>(*m_partitions[0]); PartitionBuilderGCN& pb = static_cast<PartitionBuilderGCN&>(*m_partitions[0]);
return pb.buildFromDirectory(dirIn) ? EBuildResult::Success : EBuildResult::Failed; return pb.buildFromDirectory(dirIn) ? EBuildResult::Success : EBuildResult::Failed;
} }
uint64_t DiscBuilderGCN::CalculateTotalSizeRequired(const SystemChar* dirIn) std::optional<uint64_t> DiscBuilderGCN::CalculateTotalSizeRequired(SystemStringView dirIn) {
{ std::optional<uint64_t> sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeBuild(dirIn, PartitionKind::Data, false);
uint64_t sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeBuild(dirIn, PartitionKind::Data, false); if (!sz)
if (sz == -1) return sz;
return -1; *sz += 0x30000;
sz += 0x30000; if (sz > 0x57058000) {
if (sz > 0x57058000) LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("disc capacity exceeded [{} / {}]")), *sz, 0x57058000);
{ return std::nullopt;
LogModule.report(logvisor::Error, _S("disc capacity exceeded [%" PRIu64 " / %" PRIu64 "]"), sz, 0x57058000);
return -1;
} }
return sz; return sz;
} }
DiscBuilderGCN::DiscBuilderGCN(const SystemChar* outPath, FProgress progressCB) DiscBuilderGCN::DiscBuilderGCN(SystemStringView outPath, FProgress progressCB)
: DiscBuilderBase(outPath, 0x57058000, progressCB) : DiscBuilderBase(outPath, 0x57058000, progressCB) {
{ m_partitions.emplace_back(std::make_unique<PartitionBuilderGCN>(*this));
PartitionBuilderGCN* partBuilder = new PartitionBuilderGCN(*this);
m_partitions.emplace_back(partBuilder);
} }
DiscMergerGCN::DiscMergerGCN(const SystemChar* outPath, DiscGCN& sourceDisc, FProgress progressCB) DiscMergerGCN::DiscMergerGCN(SystemStringView outPath, DiscGCN& sourceDisc, FProgress progressCB)
: m_sourceDisc(sourceDisc), m_builder(sourceDisc.makeMergeBuilder(outPath, progressCB)) : m_sourceDisc(sourceDisc), m_builder(sourceDisc.makeMergeBuilder(outPath, progressCB)) {}
{}
EBuildResult DiscMergerGCN::mergeFromDirectory(const SystemChar* dirIn) EBuildResult DiscMergerGCN::mergeFromDirectory(SystemStringView 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, _S("not enough free disk space for %s"), m_builder.m_outPath.c_str());
return EBuildResult::DiskFull; return EBuildResult::DiskFull;
} }
m_builder.m_progressCB(m_builder.getProgressFactor(), _S("Preallocating image"), -1); m_builder.m_progressCB(m_builder.getProgressFactor(), _SYS_STR("Preallocating image"), -1);
++m_builder.m_progressIdx; ++m_builder.m_progressIdx;
auto ws = m_builder.m_fileIO->beginWriteStream(0x57058000 - 1); {
auto ws = m_builder.m_fileIO->beginWriteStream(0);
if (!ws) if (!ws)
return EBuildResult::Failed; return EBuildResult::Failed;
ws->write("", 1); char zeroBytes[1024] = {};
for (uint64_t i = 0; i < 0x57058000; i += 1024)
PartitionBuilderGCN& pb = static_cast<PartitionBuilderGCN&>(*m_builder.m_partitions[0]); ws->write(zeroBytes, 1024);
return pb.mergeFromDirectory(static_cast<PartitionGCN*>(m_sourceDisc.getDataPartition()), dirIn) ?
EBuildResult::Success : EBuildResult::Failed;
} }
uint64_t DiscMergerGCN::CalculateTotalSizeRequired(DiscGCN& sourceDisc, const SystemChar* dirIn) PartitionBuilderGCN& pb = static_cast<PartitionBuilderGCN&>(*m_builder.m_partitions[0]);
{ return pb.mergeFromDirectory(static_cast<PartitionGCN*>(m_sourceDisc.getDataPartition()), dirIn)
uint64_t sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeMerge( ? EBuildResult::Success
sourceDisc.getDataPartition(), dirIn); : EBuildResult::Failed;
if (sz == -1) }
return -1;
sz += 0x30000; std::optional<uint64_t> DiscMergerGCN::CalculateTotalSizeRequired(DiscGCN& sourceDisc, SystemStringView dirIn) {
if (sz > 0x57058000) std::optional<uint64_t> sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeMerge(sourceDisc.getDataPartition(), dirIn);
{ if (!sz)
LogModule.report(logvisor::Error, _S("disc capacity exceeded [%" PRIu64 " / %" PRIu64 "]"), sz, 0x57058000); return std::nullopt;
return -1; *sz += 0x30000;
if (sz > 0x57058000) {
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("disc capacity exceeded [{} / {}]")), *sz, 0x57058000);
return std::nullopt;
} }
return sz; return sz;
} }
} } // namespace nod

View File

@@ -1,69 +1,62 @@
#include <stdio.h>
#include "nod/Util.hpp"
#include "nod/IDiscIO.hpp" #include "nod/IDiscIO.hpp"
#include "nod/IFileIO.hpp" #include "nod/IFileIO.hpp"
#include "nod/Util.hpp"
namespace nod namespace nod {
{
class DiscIOISO : public IDiscIO class DiscIOISO : public IDiscIO {
{
std::unique_ptr<IFileIO> m_fio; std::unique_ptr<IFileIO> m_fio;
public:
DiscIOISO(const SystemString& fpin)
: m_fio(NewFileIO(fpin)) {}
class ReadStream : public IReadStream public:
{ DiscIOISO(SystemStringView fpin) : m_fio(NewFileIO(fpin)) {}
class ReadStream : public IReadStream {
friend class DiscIOISO; friend class DiscIOISO;
std::unique_ptr<IFileIO::IReadStream> fp; std::unique_ptr<IFileIO::IReadStream> fp;
ReadStream(std::unique_ptr<IFileIO::IReadStream>&& fpin, bool& err) ReadStream(std::unique_ptr<IFileIO::IReadStream>&& fpin, bool& err) : fp(std::move(fpin)) {
: fp(std::move(fpin)) { if (!fp) err = true; } if (!fp)
err = true;
}
public: public:
uint64_t read(void* buf, uint64_t length) uint64_t read(void* buf, uint64_t length) override { return fp->read(buf, length); }
{return fp->read(buf, length);} uint64_t position() const override { return fp->position(); }
uint64_t position() const void seek(int64_t offset, int whence) override { fp->seek(offset, whence); }
{return fp->position();}
void seek(int64_t offset, int whence)
{fp->seek(offset, whence);}
}; };
std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const override {
{ bool err = false;
bool Err = false; auto ret = std::unique_ptr<IReadStream>(new ReadStream(m_fio->beginReadStream(offset), err));
auto ret = std::unique_ptr<IReadStream>(new ReadStream(m_fio->beginReadStream(offset), Err));
if (Err) if (err)
return {}; return {};
return ret; return ret;
} }
class WriteStream : public IWriteStream class WriteStream : public IWriteStream {
{
friend class DiscIOISO; friend class DiscIOISO;
std::unique_ptr<IFileIO::IWriteStream> fp; std::unique_ptr<IFileIO::IWriteStream> fp;
WriteStream(std::unique_ptr<IFileIO::IWriteStream>&& fpin, bool& err) WriteStream(std::unique_ptr<IFileIO::IWriteStream>&& fpin, bool& err) : fp(std::move(fpin)) {
: fp(std::move(fpin)) { if (!fp) err = true; } if (!fp)
public: err = true;
uint64_t write(const void* buf, uint64_t length)
{
return fp->write(buf, length);
} }
public:
uint64_t write(const void* buf, uint64_t length) override { return fp->write(buf, length); }
}; };
std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const override {
{ bool err = false;
bool Err = false; auto ret = std::unique_ptr<IWriteStream>(new WriteStream(m_fio->beginWriteStream(offset), err));
auto ret = std::unique_ptr<IWriteStream>(new WriteStream(m_fio->beginWriteStream(offset), Err));
if (Err) if (err)
return {}; return {};
return ret; return ret;
} }
}; };
std::unique_ptr<IDiscIO> NewDiscIOISO(const SystemChar* path) std::unique_ptr<IDiscIO> NewDiscIOISO(SystemStringView path) { return std::make_unique<DiscIOISO>(path); }
{
return std::unique_ptr<IDiscIO>(new DiscIOISO(path));
}
}
} // namespace nod

271
lib/DiscIONFS.cpp Normal file
View File

@@ -0,0 +1,271 @@
#include "nod/IDiscIO.hpp"
#include "nod/IFileIO.hpp"
#include "nod/Util.hpp"
#include "nod/aes.hpp"
#include <logvisor/logvisor.hpp>
namespace nod {
/*
* NFS is the image format used to distribute Wii VC games for the Wii U.
* It is an LBA format similar to WBFS but adds its own encryption layer.
* It logically stores a standard Wii disc image with partitions.
*/
class DiscIONFS : public IDiscIO {
std::vector<std::unique_ptr<IFileIO>> files;
struct NFSHead {
uint32_t magic; // EGGS
uint32_t version;
uint32_t unknown[2]; // Signature, UUID?
uint32_t lbaRangeCount;
struct {
uint32_t startBlock;
uint32_t numBlocks;
} lbaRanges[61];
uint32_t endMagic; // SGGE
} nfsHead;
uint8_t key[16];
uint32_t calculateNumFiles() const {
uint32_t totalBlockCount = 0;
for (uint32_t i = 0; i < nfsHead.lbaRangeCount; ++i)
totalBlockCount += nfsHead.lbaRanges[i].numBlocks;
return (uint64_t(totalBlockCount) * uint64_t(0x8000) +
(uint64_t(0x200) + uint64_t(0xF9FFFFF))) / uint64_t(0xFA00000);
}
struct FBO {
uint32_t file, block, lblock, offset;
};
FBO logicalToFBO(uint64_t offset) const {
auto blockAndRemBytes = nod::div(offset, uint64_t(0x8000)); /* 32768 bytes per block */
uint32_t block = UINT32_MAX;
for (uint32_t i = 0, physicalBlock = 0; i < nfsHead.lbaRangeCount; ++i) {
const auto& range = nfsHead.lbaRanges[i];
if (blockAndRemBytes.quot >= range.startBlock && blockAndRemBytes.quot - range.startBlock < range.numBlocks) {
block = physicalBlock + (blockAndRemBytes.quot - range.startBlock);
break;
}
physicalBlock += range.numBlocks;
}
/* This offset has no physical mapping, read zeroes */
if (block == UINT32_MAX)
return {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX};
auto fileAndRemBlocks = nod::div(block, uint32_t(8000)); /* 8000 blocks per file */
return {uint32_t(fileAndRemBlocks.quot), uint32_t(fileAndRemBlocks.rem),
uint32_t(blockAndRemBytes.quot), uint32_t(blockAndRemBytes.rem)};
}
public:
DiscIONFS(SystemStringView fpin, bool& err) {
/* Validate file path format */
using SignedSize = std::make_signed<SystemString::size_type>::type;
const auto dotPos = SignedSize(fpin.rfind(_SYS_STR('.')));
const auto slashPos = SignedSize(fpin.find_last_of(_SYS_STR("/\\")));
if (fpin.size() <= 4 || dotPos == -1 || dotPos <= slashPos ||
fpin.compare(slashPos + 1, 4, _SYS_STR("hif_")) ||
fpin.compare(dotPos, fpin.size() - dotPos, _SYS_STR(".nfs"))) {
LogModule.report(logvisor::Error,
FMT_STRING(_SYS_STR("'{}' must begin with 'hif_' and end with '.nfs' to be accepted as an NFS image")), fpin);
err = true;
return;
}
/* Load key file */
const SystemString dir(fpin.begin(), fpin.begin() + slashPos + 1);
auto keyFile = NewFileIO(dir + _SYS_STR("../code/htk.bin"))->beginReadStream();
if (!keyFile)
keyFile = NewFileIO(dir + _SYS_STR("htk.bin"))->beginReadStream();
if (!keyFile) {
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("Unable to open '{}../code/htk.bin' or '{}htk.bin'")), dir, dir);
err = true;
return;
}
if (keyFile->read(key, 16) != 16) {
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("Unable to read from '{}../code/htk.bin' or '{}htk.bin'")), dir, dir);
err = true;
return;
}
/* Load header from first file */
const SystemString firstPath = fmt::format(FMT_STRING(_SYS_STR("{}hif_{:06}.nfs")), dir, 0);
files.push_back(NewFileIO(firstPath));
auto rs = files.back()->beginReadStream();
if (!rs) {
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("'{}' does not exist")), firstPath);
err = true;
return;
}
if (rs->read(&nfsHead, 0x200) != 0x200) {
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("Unable to read header from '{}'")), firstPath);
err = true;
return;
}
if (std::memcmp(&nfsHead.magic, "EGGS", 4)) {
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("Invalid magic in '{}'")), firstPath);
err = true;
return;
}
nfsHead.lbaRangeCount = SBig(nfsHead.lbaRangeCount);
for (uint32_t i = 0; i < nfsHead.lbaRangeCount; ++i) {
auto& range = nfsHead.lbaRanges[i];
range.startBlock = SBig(range.startBlock);
range.numBlocks = SBig(range.numBlocks);
}
/* Ensure remaining files exist */
const uint32_t numFiles = calculateNumFiles();
files.reserve(numFiles);
for (uint32_t i = 1; i < numFiles; ++i) {
SystemString path = fmt::format(FMT_STRING(_SYS_STR("{}hif_{:06}.nfs")), dir, i);
files.push_back(NewFileIO(path));
if (!files.back()->exists()) {
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("'{}' does not exist")), path);
err = true;
return;
}
}
}
class ReadStream : public IReadStream {
friend class DiscIONFS;
const DiscIONFS& m_parent;
std::unique_ptr<IReadStream> m_rs;
std::unique_ptr<IAES> m_aes;
/* Physical address - all UINT32_MAX indicates logical zero block */
DiscIONFS::FBO m_physAddr;
/* Logical address */
uint64_t m_offset;
/* Active file stream and its offset as set in the system.
* Block is typically one ahead of the presently decrypted block. */
uint32_t m_curFile = UINT32_MAX;
uint32_t m_curBlock = UINT32_MAX;
ReadStream(const DiscIONFS& parent, uint64_t offset, bool& err)
: m_parent(parent), m_aes(NewAES()),
m_physAddr({UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX}), m_offset(offset) {
m_aes->setKey(m_parent.key);
setLogicalAddr(offset);
}
uint8_t m_encBuf[0x8000] = {};
uint8_t m_decBuf[0x8000] = {};
void setCurFile(uint32_t curFile) {
if (curFile >= m_parent.files.size()) {
LogModule.report(logvisor::Error, FMT_STRING("Out of bounds NFS file access"));
return;
}
m_curFile = curFile;
m_curBlock = UINT32_MAX;
m_rs = m_parent.files[m_curFile]->beginReadStream();
}
void setCurBlock(uint32_t curBlock) {
m_curBlock = curBlock;
m_rs->seek(m_curBlock * 0x8000 + 0x200);
}
void setPhysicalAddr(DiscIONFS::FBO physAddr) {
/* If we're just changing the offset, nothing else needs to be done */
if (m_physAddr.file == physAddr.file && m_physAddr.block == physAddr.block) {
m_physAddr.offset = physAddr.offset;
return;
}
m_physAddr = physAddr;
/* Set logical zero block */
if (m_physAddr.file == UINT32_MAX) {
memset(m_decBuf, 0, 0x8000);
return;
}
/* Make necessary file and block current with system */
if (m_physAddr.file != m_curFile)
setCurFile(m_physAddr.file);
if (m_physAddr.block != m_curBlock)
setCurBlock(m_physAddr.block);
/* Read block, handling 0x200 overlap case */
if (m_physAddr.block == 7999) {
m_rs->read(m_encBuf, 0x7E00);
setCurFile(m_curFile + 1);
m_rs->read(m_encBuf + 0x7E00, 0x200);
m_curBlock = 0;
} else {
m_rs->read(m_encBuf, 0x8000);
++m_curBlock;
}
/* Decrypt */
const uint32_t ivBuf[] = {0, 0, 0, SBig(m_physAddr.lblock)};
m_aes->decrypt((const uint8_t*)ivBuf, m_encBuf, m_decBuf, 0x8000);
}
void setLogicalAddr(uint64_t addr) { setPhysicalAddr(m_parent.logicalToFBO(m_offset)); }
public:
uint64_t read(void* buf, uint64_t length) override {
uint64_t rem = length;
uint8_t* dst = (uint8_t*)buf;
/* Perform reads on block boundaries */
while (rem) {
uint64_t readSize = rem;
uint32_t blockOffset = (m_physAddr.offset == UINT32_MAX) ? 0 : m_physAddr.offset;
if (readSize + blockOffset > 0x8000)
readSize = 0x8000 - blockOffset;
memmove(dst, m_decBuf + blockOffset, readSize);
dst += readSize;
rem -= readSize;
m_offset += readSize;
setLogicalAddr(m_offset);
}
return dst - (uint8_t*)buf;
}
uint64_t position() const override { return m_offset; }
void seek(int64_t offset, int whence) override {
if (whence == SEEK_SET)
m_offset = offset;
else if (whence == SEEK_CUR)
m_offset += offset;
else
return;
setLogicalAddr(m_offset);
}
};
std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const override {
bool err = false;
auto ret = std::unique_ptr<IReadStream>(new ReadStream(*this, offset, err));
if (err)
return {};
return ret;
}
std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const override { return {}; }
bool hasWiiCrypto() const override { return false; }
};
std::unique_ptr<IDiscIO> NewDiscIONFS(SystemStringView path) {
bool err = false;
auto ret = std::make_unique<DiscIONFS>(path, err);
if (err)
return {};
return ret;
}
}

View File

@@ -1,31 +1,31 @@
#include <stdio.h> #include <cinttypes>
#include <inttypes.h> #include <cstdint>
#include "nod/Util.hpp" #include <cstring>
#include <memory>
#include "nod/IDiscIO.hpp" #include "nod/IDiscIO.hpp"
#include "nod/IFileIO.hpp" #include "nod/IFileIO.hpp"
#include "nod/Util.hpp"
namespace nod #include <logvisor/logvisor.hpp>
{
namespace nod {
#define ALIGN_LBA(x) (((x) + p->hd_sec_sz - 1) & (~(p->hd_sec_sz - 1))) #define ALIGN_LBA(x) (((x) + p->hd_sec_sz - 1) & (~(p->hd_sec_sz - 1)))
static uint8_t size_to_shift(uint32_t size) static uint8_t size_to_shift(uint32_t size) {
{
uint8_t ret = 0; uint8_t ret = 0;
while (size) while (size) {
{
ret++; ret++;
size >>= 1; size >>= 1;
} }
return ret - 1; return ret - 1;
} }
class DiscIOWBFS : public IDiscIO class DiscIOWBFS : public IDiscIO {
{ std::unique_ptr<IFileIO> m_fio;
SystemString filepath;
struct WBFSHead struct WBFSHead {
{
uint32_t magic; uint32_t magic;
// parameters copied in the partition for easy dumping, and bug reports // parameters copied in the partition for easy dumping, and bug reports
uint32_t n_hd_sec; // total number of hd_sec in this partition uint32_t n_hd_sec; // total number of hd_sec in this partition
@@ -36,15 +36,13 @@ class DiscIOWBFS : public IDiscIO
}; };
std::unique_ptr<uint8_t[]> wbfsHead; std::unique_ptr<uint8_t[]> wbfsHead;
struct WBFSDiscInfo struct WBFSDiscInfo {
{
uint8_t disc_header_copy[0x100]; uint8_t disc_header_copy[0x100];
uint16_t wlba_table[0]; uint16_t wlba_table[0];
}; };
std::unique_ptr<uint8_t[]> wbfsDiscInfo; std::unique_ptr<uint8_t[]> wbfsDiscInfo;
struct WBFS struct WBFS {
{
/* hdsectors, the size of the sector provided by the hosting hard drive */ /* hdsectors, the size of the sector provided by the hosting hard drive */
uint32_t hd_sec_sz; uint32_t hd_sec_sz;
uint8_t hd_sec_sz_s; // the power of two of the last number uint8_t hd_sec_sz_s; // the power of two of the last number
@@ -73,33 +71,28 @@ class DiscIOWBFS : public IDiscIO
} wbfs; } wbfs;
static int _wbfsReadSector(IFileIO::IReadStream& rs, uint32_t lba, uint32_t count, void* buf) static int _wbfsReadSector(IFileIO::IReadStream& rs, uint32_t lba, uint32_t count, void* buf) {
{
uint64_t off = lba; uint64_t off = lba;
off *= 512ULL; off *= 512ULL;
rs.seek(off, SEEK_SET); rs.seek(off, SEEK_SET);
if (rs.read(buf, count*512ULL) != count*512ULL) if (rs.read(buf, count * 512ULL) != count * 512ULL) {
{ LogModule.report(logvisor::Error, FMT_STRING("error reading disc"));
LogModule.report(logvisor::Error, "error reading disc");
return 1; return 1;
} }
return 0; return 0;
} }
public: public:
DiscIOWBFS(const SystemString& fpin) DiscIOWBFS(SystemStringView fpin) : m_fio(NewFileIO(fpin)) {
: filepath(fpin)
{
/* Temporary file handle to read LBA table */ /* Temporary file handle to read LBA table */
std::unique_ptr<IFileIO> fio = NewFileIO(filepath); std::unique_ptr<IFileIO::IReadStream> rs = m_fio->beginReadStream();
std::unique_ptr<IFileIO::IReadStream> rs = fio->beginReadStream();
if (!rs) if (!rs)
return; return;
WBFS* p = &wbfs; WBFS* p = &wbfs;
WBFSHead tmpHead; WBFSHead tmpHead;
if (rs->read(&tmpHead, sizeof(tmpHead)) != sizeof(tmpHead)) { if (rs->read(&tmpHead, sizeof(tmpHead)) != sizeof(tmpHead)) {
LogModule.report(logvisor::Error, "unable to read WBFS head"); LogModule.report(logvisor::Error, FMT_STRING("unable to read WBFS head"));
return; return;
} }
unsigned hd_sector_size = 1 << tmpHead.hd_sec_sz_s; unsigned hd_sector_size = 1 << tmpHead.hd_sec_sz_s;
@@ -109,7 +102,7 @@ public:
WBFSHead* head = (WBFSHead*)wbfsHead.get(); WBFSHead* head = (WBFSHead*)wbfsHead.get();
rs->seek(0, SEEK_SET); rs->seek(0, SEEK_SET);
if (rs->read(head, hd_sector_size) != hd_sector_size) { if (rs->read(head, hd_sector_size) != hd_sector_size) {
LogModule.report(logvisor::Error, "unable to read WBFS head"); LogModule.report(logvisor::Error, FMT_STRING("unable to read WBFS head"));
return; return;
} }
@@ -122,11 +115,11 @@ public:
if (_wbfsReadSector(*rs, p->part_lba, 1, head)) if (_wbfsReadSector(*rs, p->part_lba, 1, head))
return; return;
if (hd_sector_size && head->hd_sec_sz_s != size_to_shift(hd_sector_size)) { if (hd_sector_size && head->hd_sec_sz_s != size_to_shift(hd_sector_size)) {
LogModule.report(logvisor::Error, "hd sector size doesn't match"); LogModule.report(logvisor::Error, FMT_STRING("hd sector size doesn't match"));
return; return;
} }
if (num_hd_sector && head->n_hd_sec != SBig(num_hd_sector)) { if (num_hd_sector && head->n_hd_sec != SBig(num_hd_sector)) {
LogModule.report(logvisor::Error, "hd num sector doesn't match"); LogModule.report(logvisor::Error, FMT_STRING("hd num sector doesn't match"));
return; return;
} }
p->hd_sec_sz = 1 << head->hd_sec_sz_s; p->hd_sec_sz = 1 << head->hd_sec_sz_s;
@@ -151,11 +144,10 @@ public:
p->n_disc_open = 0; p->n_disc_open = 0;
int disc_info_sz_lba = p->disc_info_sz >> p->hd_sec_sz_s; int disc_info_sz_lba = p->disc_info_sz >> p->hd_sec_sz_s;
if (head->disc_table[0]) if (head->disc_table[0]) {
{
wbfsDiscInfo.reset(new uint8_t[p->disc_info_sz]); wbfsDiscInfo.reset(new uint8_t[p->disc_info_sz]);
if (!wbfsDiscInfo) { if (!wbfsDiscInfo) {
LogModule.report(logvisor::Error, "allocating memory"); LogModule.report(logvisor::Error, FMT_STRING("allocating memory"));
return; return;
} }
if (_wbfsReadSector(*rs, p->part_lba + 1, disc_info_sz_lba, wbfsDiscInfo.get())) if (_wbfsReadSector(*rs, p->part_lba + 1, disc_info_sz_lba, wbfsDiscInfo.get()))
@@ -166,8 +158,7 @@ public:
} }
} }
class ReadStream : public IReadStream class ReadStream : public IReadStream {
{
friend class DiscIOWBFS; friend class DiscIOWBFS;
const DiscIOWBFS& m_parent; const DiscIOWBFS& m_parent;
std::unique_ptr<IFileIO::IReadStream> fp; std::unique_ptr<IFileIO::IReadStream> fp;
@@ -175,16 +166,16 @@ public:
std::unique_ptr<uint8_t[]> m_tmpBuffer; std::unique_ptr<uint8_t[]> m_tmpBuffer;
ReadStream(const DiscIOWBFS& parent, std::unique_ptr<IFileIO::IReadStream>&& fpin, uint64_t offset, bool& err) ReadStream(const DiscIOWBFS& parent, std::unique_ptr<IFileIO::IReadStream>&& fpin, uint64_t offset, bool& err)
: m_parent(parent), : m_parent(parent), fp(std::move(fpin)), m_offset(offset), m_tmpBuffer(new uint8_t[parent.wbfs.hd_sec_sz]) {
fp(std::move(fpin)), if (!fp)
m_offset(offset), err = true;
m_tmpBuffer(new uint8_t[parent.wbfs.hd_sec_sz]) { if (!fp) err = true; } }
int wbfsReadSector(uint32_t lba, uint32_t count, void* buf) int wbfsReadSector(uint32_t lba, uint32_t count, void* buf) {
{return DiscIOWBFS::_wbfsReadSector(*fp, lba, count, buf);} return DiscIOWBFS::_wbfsReadSector(*fp, lba, count, buf);
}
int wbfsDiscRead(uint32_t offset, uint8_t *data, uint64_t len) int wbfsDiscRead(uint32_t offset, uint8_t* data, uint64_t len) {
{
const WBFS* p = &m_parent.wbfs; const WBFS* p = &m_parent.wbfs;
const WBFSDiscInfo* d = (WBFSDiscInfo*)m_parent.wbfsDiscInfo.get(); const WBFSDiscInfo* d = (WBFSDiscInfo*)m_parent.wbfsDiscInfo.get();
uint16_t wlba = offset >> (p->wbfs_sec_sz_s - 2); uint16_t wlba = offset >> (p->wbfs_sec_sz_s - 2);
@@ -198,8 +189,7 @@ public:
uint8_t* ptr = data; uint8_t* ptr = data;
if (!iwlba) if (!iwlba)
return 1; return 1;
if (off) if (off) {
{
off *= 4; off *= 4;
err = wbfsReadSector(p->part_lba + (iwlba << iwlba_shift) + lba, 1, m_tmpBuffer.get()); err = wbfsReadSector(p->part_lba + (iwlba << iwlba_shift) + lba, 1, m_tmpBuffer.get());
if (err) if (err)
@@ -211,16 +201,14 @@ public:
len -= len_copied; len -= len_copied;
ptr += len_copied; ptr += len_copied;
lba++; lba++;
if (lba>lba_mask && len) if (lba > lba_mask && len) {
{
lba = 0; lba = 0;
iwlba = SBig(d->wlba_table[++wlba]); iwlba = SBig(d->wlba_table[++wlba]);
if (!iwlba) if (!iwlba)
return 1; return 1;
} }
} }
while (len>=p->hd_sec_sz) while (len >= p->hd_sec_sz) {
{
uint32_t nlb = len >> (p->hd_sec_sz_s); uint32_t nlb = len >> (p->hd_sec_sz_s);
if (lba + nlb > p->wbfs_sec_sz) // dont cross wbfs sectors.. if (lba + nlb > p->wbfs_sec_sz) // dont cross wbfs sectors..
@@ -231,16 +219,14 @@ public:
len -= nlb << p->hd_sec_sz_s; len -= nlb << p->hd_sec_sz_s;
ptr += nlb << p->hd_sec_sz_s; ptr += nlb << p->hd_sec_sz_s;
lba += nlb; lba += nlb;
if (lba>lba_mask && len) if (lba > lba_mask && len) {
{
lba = 0; lba = 0;
iwlba = SBig(d->wlba_table[++wlba]); iwlba = SBig(d->wlba_table[++wlba]);
if (!iwlba) if (!iwlba)
return 1; return 1;
} }
} }
if (len) if (len) {
{
err = wbfsReadSector(p->part_lba + (iwlba << iwlba_shift) + lba, 1, m_tmpBuffer.get()); err = wbfsReadSector(p->part_lba + (iwlba << iwlba_shift) + lba, 1, m_tmpBuffer.get());
if (err) if (err)
return err; return err;
@@ -250,30 +236,25 @@ public:
} }
public: public:
uint64_t read(void* buf, uint64_t length) uint64_t read(void* buf, uint64_t length) override {
{
uint8_t extra[4]; uint8_t extra[4];
uint64_t rem_offset = m_offset % 4; uint64_t rem_offset = m_offset % 4;
if (rem_offset) if (rem_offset) {
{
uint64_t rem_rem = 4 - rem_offset; uint64_t rem_rem = 4 - rem_offset;
if (wbfsDiscRead((uint32_t)(m_offset / 4), extra, 4)) if (wbfsDiscRead((uint32_t)(m_offset / 4), extra, 4))
return 0; return 0;
memcpy(buf, extra + rem_offset, rem_rem); memcpy(buf, extra + rem_offset, rem_rem);
if (wbfsDiscRead((uint32_t)(m_offset / 4 + 1), (uint8_t*)buf + rem_rem, length - rem_rem)) if (wbfsDiscRead((uint32_t)(m_offset / 4 + 1), (uint8_t*)buf + rem_rem, length - rem_rem))
return 0; return 0;
} } else {
else
{
if (wbfsDiscRead((uint32_t)(m_offset / 4), (uint8_t*)buf, length)) if (wbfsDiscRead((uint32_t)(m_offset / 4), (uint8_t*)buf, length))
return 0; return 0;
} }
m_offset += length; m_offset += length;
return length; return length;
} }
uint64_t position() const {return m_offset;} uint64_t position() const override { return m_offset; }
void seek(int64_t offset, int whence) void seek(int64_t offset, int whence) override {
{
if (whence == SEEK_SET) if (whence == SEEK_SET)
m_offset = offset; m_offset = offset;
else if (whence == SEEK_CUR) else if (whence == SEEK_CUR)
@@ -281,25 +262,19 @@ public:
} }
}; };
std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const override {
{ bool err = false;
bool Err = false; auto ret = std::unique_ptr<IReadStream>(new ReadStream(*this, m_fio->beginReadStream(), offset, err));
auto ret = std::unique_ptr<IReadStream>(new ReadStream(*this, NewFileIO(filepath)->beginReadStream(), offset, Err));
if (Err) if (err)
return {}; return {};
return ret; return ret;
} }
std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const override { return {}; }
{
return std::unique_ptr<IWriteStream>();
}
}; };
std::unique_ptr<IDiscIO> NewDiscIOWBFS(const SystemChar* path) std::unique_ptr<IDiscIO> NewDiscIOWBFS(SystemStringView path) { return std::make_unique<DiscIOWBFS>(path); }
{
return std::unique_ptr<IDiscIO>(new DiscIOWBFS(path));
}
}
} // namespace nod

File diff suppressed because it is too large Load Diff

View File

@@ -1,34 +1,32 @@
#include <stdio.h> #include <cinttypes>
#include <stdlib.h> #include <cstdio>
#include <inttypes.h> #include <cstdint>
#include "nod/Util.hpp" #include <cstdlib>
#include "nod/IFileIO.hpp" #include "nod/IFileIO.hpp"
#include "nod/Util.hpp"
namespace nod #include <logvisor/logvisor.hpp>
{
class FileIOFILE : public IFileIO namespace nod {
{
class FileIOFILE : public IFileIO {
SystemString m_path; SystemString m_path;
int64_t m_maxWriteSize; int64_t m_maxWriteSize;
public:
FileIOFILE(const SystemString& path, int64_t maxWriteSize)
: m_path(path), m_maxWriteSize(maxWriteSize) {}
FileIOFILE(const SystemChar* path, int64_t maxWriteSize)
: m_path(path), m_maxWriteSize(maxWriteSize) {}
bool exists() public:
{ FileIOFILE(SystemStringView path, int64_t maxWriteSize) : m_path(path), m_maxWriteSize(maxWriteSize) {}
FILE* fp = fopen(m_path.c_str(), "rb");
bool exists() override {
FILE* fp = Fopen(m_path.c_str(), _SYS_STR("rb"));
if (!fp) if (!fp)
return false; return false;
fclose(fp); fclose(fp);
return true; return true;
} }
uint64_t size() 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);
@@ -37,120 +35,93 @@ public:
return result; return result;
} }
struct WriteStream : public IFileIO::IWriteStream struct WriteStream : public IFileIO::IWriteStream {
{
FILE* fp; FILE* fp;
int64_t m_maxWriteSize; int64_t m_maxWriteSize;
WriteStream(const SystemString& path, int64_t maxWriteSize, bool& err) WriteStream(SystemStringView path, int64_t maxWriteSize, bool& err) : m_maxWriteSize(maxWriteSize) {
: m_maxWriteSize(maxWriteSize) fp = Fopen(path.data(), _SYS_STR("wb"));
{ if (!fp) {
fp = fopen(path.c_str(), "wb"); LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to open '{}' for writing")), path);
if (!fp)
{
LogModule.report(logvisor::Error, _S("unable to open '%s' for writing"), path.c_str());
err = true; err = true;
} }
} }
WriteStream(const SystemString& path, uint64_t offset, int64_t maxWriteSize, bool& err) WriteStream(SystemStringView 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.c_str(), "ab");
if (!fp) if (!fp)
goto FailLoc; goto FailLoc;
fclose(fp); fclose(fp);
fp = fopen(path.c_str(), "r+b"); fp = Fopen(path.data(), _SYS_STR("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, _S("unable to open '%s' for writing"), path.c_str()); LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to open '{}' for writing")), path);
err = true; err = true;
} }
~WriteStream() ~WriteStream() override { fclose(fp); }
{ uint64_t write(const void* buf, uint64_t length) override {
fclose(fp); if (m_maxWriteSize >= 0) {
} if (FTell(fp) + length > m_maxWriteSize) {
uint64_t write(const void* buf, uint64_t length) LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("write operation exceeds file's {}-byte limit")),
{ m_maxWriteSize);
if (m_maxWriteSize >= 0)
{
if (FTell(fp) + length > m_maxWriteSize)
{
LogModule.report(logvisor::Error, _S("write operation exceeds file's %" PRIi64 "-byte limit"), m_maxWriteSize);
return 0; return 0;
} }
} }
return fwrite(buf, 1, length, fp); return fwrite(buf, 1, length, fp);
} }
}; };
std::unique_ptr<IWriteStream> beginWriteStream() const
{ std::unique_ptr<IWriteStream> beginWriteStream() const override {
bool Err = false; bool err = false;
auto ret = std::unique_ptr<IWriteStream>(new WriteStream(m_path, m_maxWriteSize, Err)); auto ret = std::unique_ptr<IWriteStream>(new WriteStream(m_path, m_maxWriteSize, err));
if (Err)
return {}; if (err)
return ret;
}
std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const
{
bool Err = false;
auto ret = std::unique_ptr<IWriteStream>(new WriteStream(m_path, offset, m_maxWriteSize, Err));
if (Err)
return {}; return {};
return ret; return ret;
} }
struct ReadStream : public IFileIO::IReadStream std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const override {
{ bool err = false;
auto ret = std::unique_ptr<IWriteStream>(new WriteStream(m_path, offset, m_maxWriteSize, err));
if (err)
return {};
return ret;
}
struct ReadStream : public IFileIO::IReadStream {
FILE* fp; FILE* fp;
ReadStream(const SystemString& path, bool& err) ReadStream(SystemStringView path, bool& err) {
{ fp = Fopen(path.data(), _SYS_STR("rb"));
fp = fopen(path.c_str(), "rb"); if (!fp) {
if (!fp)
{
err = true; err = true;
LogModule.report(logvisor::Error, _S("unable to open '%s' for reading"), path.c_str()); LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to open '{}' for reading")), path);
} }
} }
ReadStream(const SystemString& path, uint64_t offset, bool& err) ReadStream(SystemStringView path, uint64_t offset, bool& err) : ReadStream(path, err) {
: ReadStream(path, err)
{
if (err) if (err)
return; return;
FSeek(fp, offset, SEEK_SET); FSeek(fp, offset, SEEK_SET);
} }
~ReadStream() ~ReadStream() override { fclose(fp); }
{ void seek(int64_t offset, int whence) override { FSeek(fp, offset, whence); }
fclose(fp); uint64_t position() const override { return FTell(fp); }
} uint64_t read(void* buf, uint64_t length) override { return fread(buf, 1, length, fp); }
void seek(int64_t offset, int whence) uint64_t copyToDisc(IPartWriteStream& discio, uint64_t length) override {
{
FSeek(fp, offset, whence);
}
uint64_t position() const
{
return FTell(fp);
}
uint64_t read(void* buf, uint64_t length)
{
return fread(buf, 1, length, fp);
}
uint64_t copyToDisc(IPartWriteStream& discio, uint64_t length)
{
uint64_t written = 0; uint64_t written = 0;
uint8_t buf[0x7c00]; uint8_t buf[0x7c00];
while (length) while (length) {
{
uint64_t thisSz = nod::min(uint64_t(0x7c00), length); uint64_t thisSz = nod::min(uint64_t(0x7c00), length);
if (read(buf, thisSz) != thisSz) if (read(buf, thisSz) != thisSz) {
{ LogModule.report(logvisor::Error, FMT_STRING("unable to read enough from file"));
LogModule.report(logvisor::Error, "unable to read enough from file");
return written; return written;
} }
if (discio.write(buf, thisSz) != thisSz) if (discio.write(buf, thisSz) != thisSz) {
{ LogModule.report(logvisor::Error, FMT_STRING("unable to write enough to disc"));
LogModule.report(logvisor::Error, "unable to write enough to disc");
return written; return written;
} }
length -= thisSz; length -= thisSz;
@@ -159,32 +130,30 @@ public:
return written; return written;
} }
}; };
std::unique_ptr<IReadStream> beginReadStream() const
{ std::unique_ptr<IReadStream> beginReadStream() const override {
bool Err = false; bool err = false;
auto ret = std::unique_ptr<IReadStream>(new ReadStream(m_path, Err)); auto ret = std::unique_ptr<IReadStream>(new ReadStream(m_path, err));
if (Err)
if (err)
return {}; return {};
return ret; return ret;
} }
std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const
{ std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const override {
bool Err = false; bool err = false;
auto ret = std::unique_ptr<IReadStream>(new ReadStream(m_path, offset, Err)); auto ret = std::unique_ptr<IReadStream>(new ReadStream(m_path, offset, err));
if (Err)
if (err)
return {}; return {};
return ret; return ret;
} }
}; };
std::unique_ptr<IFileIO> NewFileIO(const SystemString& path, int64_t maxWriteSize) std::unique_ptr<IFileIO> NewFileIO(SystemStringView path, int64_t maxWriteSize) {
{ return std::make_unique<FileIOFILE>(path, maxWriteSize);
return std::unique_ptr<IFileIO>(new FileIOFILE(path, maxWriteSize));
} }
std::unique_ptr<IFileIO> NewFileIO(const SystemChar* path, int64_t maxWriteSize) } // namespace nod
{
return std::unique_ptr<IFileIO>(new FileIOFILE(path, maxWriteSize));
}
}

View File

@@ -1,41 +1,46 @@
#include <stdio.h> #include <cinttypes>
#include <stdlib.h> #include <cstdint>
#include <inttypes.h> #include <cstdio>
#include "nod/Util.hpp" #include <cstdlib>
#include "nod/IFileIO.hpp" #include "nod/IFileIO.hpp"
#include "nod/Util.hpp"
namespace nod #include <logvisor/logvisor.hpp>
{
class FileIOWin32 : public IFileIO namespace nod {
{
class FileIOWin32 : public IFileIO {
SystemString m_path; SystemString m_path;
int64_t m_maxWriteSize; int64_t m_maxWriteSize;
public:
FileIOWin32(const SystemString& path, int64_t maxWriteSize)
: m_path(path), m_maxWriteSize(maxWriteSize) {}
FileIOWin32(const SystemChar* path, int64_t maxWriteSize)
: m_path(path), m_maxWriteSize(maxWriteSize) {}
bool exists() public:
{ FileIOWin32(SystemStringView path, int64_t maxWriteSize) : m_path(path), m_maxWriteSize(maxWriteSize) {}
HANDLE fp = CreateFileW(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ,
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); bool exists() override {
#if !WINDOWS_STORE
HANDLE fp = CreateFileW(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, nullptr);
#else
HANDLE fp = CreateFile2(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr);
#endif
if (fp == INVALID_HANDLE_VALUE) if (fp == INVALID_HANDLE_VALUE)
return false; return false;
CloseHandle(fp); CloseHandle(fp);
return true; return true;
} }
uint64_t size() uint64_t size() override {
{ #if !WINDOWS_STORE
HANDLE fp = CreateFileW(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ, HANDLE fp = CreateFileW(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); FILE_ATTRIBUTE_NORMAL, nullptr);
#else
HANDLE fp = CreateFile2(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr);
#endif
if (fp == INVALID_HANDLE_VALUE) if (fp == INVALID_HANDLE_VALUE)
return 0; return 0;
LARGE_INTEGER sz; LARGE_INTEGER sz;
if (!GetFileSizeEx(fp, &sz)) if (!GetFileSizeEx(fp, &sz)) {
{
CloseHandle(fp); CloseHandle(fp);
return 0; return 0;
} }
@@ -43,29 +48,31 @@ public:
return sz.QuadPart; return sz.QuadPart;
} }
struct WriteStream : public IFileIO::IWriteStream struct WriteStream : public IFileIO::IWriteStream {
{
HANDLE fp; HANDLE fp;
int64_t m_maxWriteSize; int64_t m_maxWriteSize;
WriteStream(const SystemString& path, int64_t maxWriteSize, bool& err) WriteStream(SystemStringView path, int64_t maxWriteSize, bool& err) : m_maxWriteSize(maxWriteSize) {
: m_maxWriteSize(maxWriteSize) #if !WINDOWS_STORE
{ fp = CreateFileW(path.data(), GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
fp = CreateFileW(path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, nullptr);
nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); #else
if (fp == INVALID_HANDLE_VALUE) fp = CreateFile2(path.data(), GENERIC_WRITE, FILE_SHARE_WRITE, CREATE_ALWAYS, nullptr);
{ #endif
LogModule.report(logvisor::Error, _S("unable to open '%s' for writing"), path.c_str()); if (fp == INVALID_HANDLE_VALUE) {
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to open '{}' for writing")), path);
err = true; err = true;
} }
} }
WriteStream(const SystemString& path, uint64_t offset, int64_t maxWriteSize, bool& err) WriteStream(SystemStringView path, uint64_t offset, int64_t maxWriteSize, bool& err)
: m_maxWriteSize(maxWriteSize) : m_maxWriteSize(maxWriteSize) {
{ #if !WINDOWS_STORE
fp = CreateFileW(path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, fp = CreateFileW(path.data(), GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); nullptr);
if (fp == INVALID_HANDLE_VALUE) #else
{ fp = CreateFile2(path.data(), GENERIC_WRITE, FILE_SHARE_WRITE, OPEN_ALWAYS, nullptr);
LogModule.report(logvisor::Error, _S("unable to open '%s' for writing"), path.c_str()); #endif
if (fp == INVALID_HANDLE_VALUE) {
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to open '{}' for writing")), path);
err = true; err = true;
return; return;
} }
@@ -73,20 +80,15 @@ public:
lioffset.QuadPart = offset; lioffset.QuadPart = offset;
SetFilePointerEx(fp, lioffset, nullptr, FILE_BEGIN); SetFilePointerEx(fp, lioffset, nullptr, FILE_BEGIN);
} }
~WriteStream() ~WriteStream() override { CloseHandle(fp); }
{ uint64_t write(const void* buf, uint64_t length) override {
CloseHandle(fp); if (m_maxWriteSize >= 0) {
}
uint64_t write(const void* buf, uint64_t length)
{
if (m_maxWriteSize >= 0)
{
LARGE_INTEGER li = {}; LARGE_INTEGER li = {};
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, _S("write operation exceeds file's %" PRIi64 "-byte limit"), m_maxWriteSize); m_maxWriteSize);
return 0; return 0;
} }
} }
@@ -96,83 +98,76 @@ public:
return ret; return ret;
} }
}; };
std::unique_ptr<IWriteStream> beginWriteStream() const 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::unique_ptr<IWriteStream>(new WriteStream(m_path, m_maxWriteSize, Err));
if (Err) if (err) {
return {}; return nullptr;
}
return ret; return ret;
} }
std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const 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::unique_ptr<IWriteStream>(new WriteStream(m_path, offset, m_maxWriteSize, Err));
if (Err) if (err) {
return {}; return nullptr;
}
return ret; return ret;
} }
struct ReadStream : public IFileIO::IReadStream struct ReadStream : public IFileIO::IReadStream {
{
HANDLE fp; HANDLE fp;
ReadStream(const SystemString& path, bool& err) ReadStream(SystemStringView path, bool& err) {
{ #if !WINDOWS_STORE
fp = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, fp = CreateFileW(path.data(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); nullptr);
if (fp == INVALID_HANDLE_VALUE) #else
{ fp = CreateFile2(path.data(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr);
#endif
if (fp == INVALID_HANDLE_VALUE) {
err = true; err = true;
LogModule.report(logvisor::Error, _S("unable to open '%s' for reading"), path.c_str()); LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to open '{}' for reading")), path);
} }
} }
ReadStream(const SystemString& path, uint64_t offset, bool& err) ReadStream(SystemStringView path, uint64_t offset, bool& err) : ReadStream(path, err) {
: ReadStream(path, err)
{
if (err) if (err)
return; return;
LARGE_INTEGER lioffset; LARGE_INTEGER lioffset;
lioffset.QuadPart = offset; lioffset.QuadPart = offset;
SetFilePointerEx(fp, lioffset, nullptr, FILE_BEGIN); SetFilePointerEx(fp, lioffset, nullptr, FILE_BEGIN);
} }
~ReadStream() ~ReadStream() override { CloseHandle(fp); }
{ void seek(int64_t offset, int whence) override {
CloseHandle(fp);
}
void seek(int64_t offset, int whence)
{
LARGE_INTEGER li; LARGE_INTEGER li;
li.QuadPart = offset; li.QuadPart = offset;
SetFilePointerEx(fp, li, nullptr, whence); SetFilePointerEx(fp, li, nullptr, whence);
} }
uint64_t position() const uint64_t position() const override {
{
LARGE_INTEGER li = {}; LARGE_INTEGER li = {};
LARGE_INTEGER res; LARGE_INTEGER res;
SetFilePointerEx(fp, li, &res, FILE_CURRENT); SetFilePointerEx(fp, li, &res, FILE_CURRENT);
return res.QuadPart; return res.QuadPart;
} }
uint64_t read(void* buf, uint64_t length) uint64_t read(void* buf, uint64_t length) override {
{
DWORD ret = 0; DWORD ret = 0;
ReadFile(fp, buf, length, &ret, nullptr); ReadFile(fp, buf, length, &ret, nullptr);
return ret; return ret;
} }
uint64_t copyToDisc(IPartWriteStream& discio, uint64_t length) uint64_t copyToDisc(IPartWriteStream& discio, uint64_t length) override {
{
uint64_t written = 0; uint64_t written = 0;
uint8_t buf[0x7c00]; uint8_t buf[0x7c00];
while (length) while (length) {
{
uint64_t thisSz = nod::min(uint64_t(0x7c00), length); uint64_t thisSz = nod::min(uint64_t(0x7c00), length);
if (read(buf, thisSz) != thisSz) if (read(buf, thisSz) != thisSz) {
{ LogModule.report(logvisor::Error, FMT_STRING("unable to read enough from file"));
LogModule.report(logvisor::Error, "unable to read enough from file");
return written; return written;
} }
if (discio.write(buf, thisSz) != thisSz) if (discio.write(buf, thisSz) != thisSz) {
{ LogModule.report(logvisor::Error, FMT_STRING("unable to write enough to disc"));
LogModule.report(logvisor::Error, "unable to write enough to disc");
return written; return written;
} }
length -= thisSz; length -= thisSz;
@@ -181,32 +176,32 @@ public:
return written; return written;
} }
}; };
std::unique_ptr<IReadStream> beginReadStream() const
{ std::unique_ptr<IReadStream> beginReadStream() const override {
bool Err = false; bool err = false;
auto ret = std::unique_ptr<IReadStream>(new ReadStream(m_path, Err)); auto ret = std::make_unique<ReadStream>(m_path, err);
if (Err)
return {}; if (err) {
return nullptr;
}
return ret; return ret;
} }
std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const
{ std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const override {
bool Err = false; bool err = false;
auto ret = std::unique_ptr<IReadStream>(new ReadStream(m_path, offset, Err)); auto ret = std::make_unique<ReadStream>(m_path, offset, err);
if (Err)
return {}; if (err) {
return nullptr;
}
return ret; return ret;
} }
}; };
std::unique_ptr<IFileIO> NewFileIO(const SystemString& path, int64_t maxWriteSize) std::unique_ptr<IFileIO> NewFileIO(SystemStringView path, int64_t maxWriteSize) {
{ return std::make_unique<FileIOWin32>(path, maxWriteSize);
return std::unique_ptr<IFileIO>(new FileIOWin32(path, maxWriteSize));
} }
std::unique_ptr<IFileIO> NewFileIO(const SystemChar* path, int64_t maxWriteSize) } // namespace nod
{
return std::unique_ptr<IFileIO>(new FileIOWin32(path, maxWriteSize));
}
}

View File

@@ -1,15 +1,18 @@
#include "nod/aes.hpp" #include "nod/aes.hpp"
#include <stdio.h> #include <cstdio>
#include <string.h> #include <cstring>
#if _WIN32 #if _WIN32
#include <intrin.h> #include <intrin.h>
#else #elif __x86_64__
#include <cpuid.h> #include <cpuid.h>
#endif #endif
namespace nod #if __AES__ || (!defined(__clang__) && _MSC_VER >= 1800)
{ #define _AES_NI 1
#endif
namespace nod {
/* rotates x one bit to the left */ /* rotates x one bit to the left */
@@ -23,14 +26,12 @@ namespace nod
static const uint8_t InCo[4] = {0xB, 0xD, 0x9, 0xE}; /* Inverse Coefficients */ static const uint8_t InCo[4] = {0xB, 0xD, 0x9, 0xE}; /* Inverse Coefficients */
static inline uint32_t pack(const uint8_t* b) static uint32_t pack(const uint8_t* b) {
{
/* pack bytes into a 32-bit Word */ /* pack bytes into a 32-bit Word */
return ((uint32_t)b[3] << 24) | ((uint32_t)b[2] << 16) | ((uint32_t)b[1] << 8) | (uint32_t)b[0]; return ((uint32_t)b[3] << 24) | ((uint32_t)b[2] << 16) | ((uint32_t)b[1] << 8) | (uint32_t)b[0];
} }
static inline void unpack(uint32_t a, uint8_t* b) static void unpack(uint32_t a, uint8_t* b) {
{
/* unpack bytes from a word */ /* unpack bytes from a word */
b[0] = (uint8_t)a; b[0] = (uint8_t)a;
b[1] = (uint8_t)(a >> 8); b[1] = (uint8_t)(a >> 8);
@@ -38,13 +39,9 @@ static inline void unpack(uint32_t a, uint8_t* b)
b[3] = (uint8_t)(a >> 24); b[3] = (uint8_t)(a >> 24);
} }
static inline uint8_t xtime(uint8_t a) constexpr uint8_t xtime(uint8_t a) { return ((a << 1) ^ (((a >> 7) & 1) * 0x11B)); }
{
return ((a << 1) ^ (((a>>7) & 1) * 0x11B));
}
static const struct SoftwareAESTables static const struct SoftwareAESTables {
{
uint8_t fbsub[256]; uint8_t fbsub[256];
uint8_t rbsub[256]; uint8_t rbsub[256];
uint8_t ptab[256], ltab[256]; uint8_t ptab[256], ltab[256];
@@ -52,15 +49,15 @@ static const struct SoftwareAESTables
uint32_t rtable[256]; uint32_t rtable[256];
uint32_t rco[30]; uint32_t rco[30];
uint8_t bmul(uint8_t x, uint8_t y) const uint8_t bmul(uint8_t x, uint8_t y) const {
{
/* x.y= AntiLog(Log(x) + Log(y)) */ /* x.y= AntiLog(Log(x) + Log(y)) */
if (x && y) return ptab[(ltab[x] + ltab[y]) % 255]; if (x && y)
else return 0; return ptab[(ltab[x] + ltab[y]) % 255];
else
return 0;
} }
uint32_t SubByte(uint32_t a) const uint32_t SubByte(uint32_t a) const {
{
uint8_t b[4]; uint8_t b[4];
unpack(a, b); unpack(a, b);
b[0] = fbsub[b[0]]; b[0] = fbsub[b[0]];
@@ -70,8 +67,7 @@ static const struct SoftwareAESTables
return pack(b); return pack(b);
} }
uint8_t product(uint32_t x, uint32_t y) const uint8_t product(uint32_t x, uint32_t y) const {
{
/* dot product of two 4-byte arrays */ /* dot product of two 4-byte arrays */
uint8_t xb[4], yb[4]; uint8_t xb[4], yb[4];
unpack(x, xb); unpack(x, xb);
@@ -79,8 +75,7 @@ static const struct SoftwareAESTables
return bmul(xb[0], yb[0]) ^ bmul(xb[1], yb[1]) ^ bmul(xb[2], yb[2]) ^ bmul(xb[3], yb[3]); return bmul(xb[0], yb[0]) ^ bmul(xb[1], yb[1]) ^ bmul(xb[2], yb[2]) ^ bmul(xb[3], yb[3]);
} }
uint32_t InvMixCol(uint32_t x) const uint32_t InvMixCol(uint32_t x) const {
{
/* matrix Multiplication */ /* matrix Multiplication */
uint32_t y, m; uint32_t y, m;
uint8_t b[4]; uint8_t b[4];
@@ -97,8 +92,7 @@ static const struct SoftwareAESTables
return y; return y;
} }
uint8_t ByteSub(uint8_t x) const uint8_t ByteSub(uint8_t x) const {
{
uint8_t y = ptab[255 - ltab[x]]; /* multiplicative inverse */ uint8_t y = ptab[255 - ltab[x]]; /* multiplicative inverse */
x = y; x = y;
x = ROTL(x); x = ROTL(x);
@@ -113,8 +107,7 @@ static const struct SoftwareAESTables
return y; return y;
} }
SoftwareAESTables() SoftwareAESTables() {
{
/* generate tables */ /* generate tables */
int i; int i;
uint8_t y, b[4]; uint8_t y, b[4];
@@ -127,8 +120,7 @@ static const struct SoftwareAESTables
ptab[1] = 3; ptab[1] = 3;
ltab[3] = 1; ltab[3] = 1;
for (i = 2; i < 256; i++) for (i = 2; i < 256; i++) {
{
ptab[i] = ptab[i - 1] ^ xtime(ptab[i - 1]); ptab[i] = ptab[i - 1] ^ xtime(ptab[i - 1]);
ltab[ptab[i]] = i; ltab[ptab[i]] = i;
} }
@@ -138,22 +130,19 @@ static const struct SoftwareAESTables
fbsub[0] = 0x63; fbsub[0] = 0x63;
rbsub[0x63] = 0; rbsub[0x63] = 0;
for (i = 1; i < 256; i++) for (i = 1; i < 256; i++) {
{
y = ByteSub((uint8_t)i); y = ByteSub((uint8_t)i);
fbsub[i] = y; fbsub[i] = y;
rbsub[y] = i; rbsub[y] = i;
} }
for (i = 0, y = 1; i < 30; i++) for (i = 0, y = 1; i < 30; i++) {
{
rco[i] = y; rco[i] = y;
y = xtime(y); y = xtime(y);
} }
/* calculate forward and reverse tables */ /* calculate forward and reverse tables */
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++) {
{
y = fbsub[i]; y = fbsub[i];
b[3] = y ^ xtime(y); b[3] = y ^ xtime(y);
b[2] = y; b[2] = y;
@@ -171,8 +160,7 @@ static const struct SoftwareAESTables
} }
} AEStb; } AEStb;
class SoftwareAES : public IAES class SoftwareAES : public IAES {
{
protected: protected:
/* Parameter-dependent data */ /* Parameter-dependent data */
int Nk, Nb, Nr; int Nk, Nb, Nr;
@@ -185,13 +173,12 @@ protected:
void _decrypt(uint8_t* buff); void _decrypt(uint8_t* buff);
public: public:
void encrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len); void encrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len) override;
void decrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len); void decrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len) override;
void setKey(const uint8_t* key); void setKey(const uint8_t* key) override;
}; };
void SoftwareAES::gkey(int nb, int nk, const uint8_t* key) void SoftwareAES::gkey(int nb, int nk, const uint8_t* key) {
{
/* blocksize=32*nb bits. Key=32*nk bits */ /* blocksize=32*nb bits. Key=32*nk bits */
/* currently nb,bk = 4, 6 or 8 */ /* currently nb,bk = 4, 6 or 8 */
/* key comes as 4*Nk bytes */ /* key comes as 4*Nk bytes */
@@ -204,17 +191,23 @@ void SoftwareAES::gkey(int nb, int nk, const uint8_t* key)
Nk = nk; Nk = nk;
/* Nr is number of rounds */ /* Nr is number of rounds */
if (Nb >= Nk) Nr = 6 + Nb; if (Nb >= Nk)
else Nr = 6 + Nk; Nr = 6 + Nb;
else
Nr = 6 + Nk;
C1 = 1; C1 = 1;
if (Nb < 8) { C2 = 2; C3 = 3; } if (Nb < 8) {
else { C2 = 3; C3 = 4; } C2 = 2;
C3 = 3;
} else {
C2 = 3;
C3 = 4;
}
/* pre-calculate forward and reverse increments */ /* pre-calculate forward and reverse increments */
for (m = j = 0; j < nb; j++, m += 3) for (m = j = 0; j < nb; j++, m += 3) {
{
fi[m] = (j + C1) % nb; fi[m] = (j + C1) % nb;
fi[m + 1] = (j + C2) % nb; fi[m + 1] = (j + C2) % nb;
fi[m + 2] = (j + C3) % nb; fi[m + 2] = (j + C3) % nb;
@@ -225,61 +218,56 @@ void SoftwareAES::gkey(int nb, int nk, const uint8_t* key)
N = Nb * (Nr + 1); N = Nb * (Nr + 1);
for (i = j = 0; i < Nk; i++, j += 4) for (i = j = 0; i < Nk; i++, j += 4) {
{
CipherKey[i] = pack(key + j); CipherKey[i] = pack(key + j);
} }
for (i = 0; i < Nk; i++) fkey[i] = CipherKey[i]; for (i = 0; i < Nk; i++)
fkey[i] = CipherKey[i];
for (j = Nk, k = 0; j < N; j += Nk, k++) for (j = Nk, k = 0; j < N; j += Nk, k++) {
{
fkey[j] = fkey[j - Nk] ^ AEStb.SubByte(ROTL24(fkey[j - 1])) ^ AEStb.rco[k]; fkey[j] = fkey[j - Nk] ^ AEStb.SubByte(ROTL24(fkey[j - 1])) ^ AEStb.rco[k];
if (Nk <= 6) if (Nk <= 6) {
{
for (i = 1; i < Nk && (i + j) < N; i++) for (i = 1; i < Nk && (i + j) < N; i++)
fkey[i + j] = fkey[i + j - Nk] ^ fkey[i + j - 1]; fkey[i + j] = fkey[i + j - Nk] ^ fkey[i + j - 1];
} } else {
else
{
for (i = 1; i < 4 && (i + j) < N; i++) for (i = 1; i < 4 && (i + j) < N; i++)
fkey[i + j] = fkey[i + j - Nk] ^ fkey[i + j - 1]; fkey[i + j] = fkey[i + j - Nk] ^ fkey[i + j - 1];
if ((j + 4) < N) fkey[j + 4] = fkey[j + 4 - Nk] ^ AEStb.SubByte(fkey[j + 3]); if ((j + 4) < N)
fkey[j + 4] = fkey[j + 4 - Nk] ^ AEStb.SubByte(fkey[j + 3]);
for (i = 5; i < Nk && (i + j) < N; i++) for (i = 5; i < Nk && (i + j) < N; i++)
fkey[i + j] = fkey[i + j - Nk] ^ fkey[i + j - 1]; fkey[i + j] = fkey[i + j - Nk] ^ fkey[i + j - 1];
} }
} }
/* now for the expanded decrypt key in reverse order */ /* now for the expanded decrypt key in reverse order */
for (j = 0; j < Nb; j++) rkey[j + N - Nb] = fkey[j]; for (j = 0; j < Nb; j++)
rkey[j + N - Nb] = fkey[j];
for (i = Nb; i < N - Nb; i += Nb) for (i = Nb; i < N - Nb; i += Nb) {
{
k = N - Nb - i; k = N - Nb - i;
for (j = 0; j < Nb; j++) rkey[k + j] = AEStb.InvMixCol(fkey[i + j]); for (j = 0; j < Nb; j++)
rkey[k + j] = AEStb.InvMixCol(fkey[i + j]);
} }
for (j = N - Nb; j < N; j++) rkey[j - N + Nb] = fkey[j]; for (j = N - Nb; j < N; j++)
rkey[j - N + Nb] = fkey[j];
} }
/* There is an obvious time/space trade-off possible here. * /* There is an obvious time/space trade-off possible here. *
* Instead of just one ftable[], I could have 4, the other * * Instead of just one ftable[], I could have 4, the other *
* 3 pre-rotated to save the ROTL8, ROTL16 and ROTL24 overhead */ * 3 pre-rotated to save the ROTL8, ROTL16 and ROTL24 overhead */
void SoftwareAES::_encrypt(uint8_t* buff) void SoftwareAES::_encrypt(uint8_t* buff) {
{
int i, j, k, m; int i, j, k, m;
uint32_t a[8], b[8], *x, *y, *t; uint32_t a[8], b[8], *x, *y, *t;
for (i = j = 0; i < Nb; i++, j += 4) for (i = j = 0; i < Nb; i++, j += 4) {
{
a[i] = pack(buff + j); a[i] = pack(buff + j);
a[i] ^= fkey[i]; a[i] ^= fkey[i];
} }
@@ -289,21 +277,17 @@ void SoftwareAES::_encrypt(uint8_t* buff)
y = b; y = b;
/* State alternates between a and b */ /* State alternates between a and b */
for (i = 1; i < Nr; i++) for (i = 1; i < Nr; i++) {
{
/* Nr is number of rounds. May be odd. */ /* Nr is number of rounds. May be odd. */
/* if Nb is fixed - unroll this next /* if Nb is fixed - unroll this next
loop and hard-code in the values of fi[] */ loop and hard-code in the values of fi[] */
for (m = j = 0; j < Nb; j++, m += 3) for (m = j = 0; j < Nb; j++, m += 3) {
{
/* deal with each 32-bit element of the State */ /* deal with each 32-bit element of the State */
/* This is the time-critical bit */ /* This is the time-critical bit */
y[j] = fkey[k++] ^ AEStb.ftable[(uint8_t)x[j]] ^ y[j] = fkey[k++] ^ AEStb.ftable[(uint8_t)x[j]] ^ ROTL8(AEStb.ftable[(uint8_t)(x[fi[m]] >> 8)]) ^
ROTL8(AEStb.ftable[(uint8_t)(x[fi[m]] >> 8)])^ ROTL16(AEStb.ftable[(uint8_t)(x[fi[m + 1]] >> 16)]) ^ ROTL24(AEStb.ftable[(uint8_t)(x[fi[m + 2]] >> 24)]);
ROTL16(AEStb.ftable[(uint8_t)(x[fi[m + 1]] >> 16)])^
ROTL24(AEStb.ftable[(uint8_t)(x[fi[m + 2]] >> 24)]);
} }
t = x; t = x;
@@ -312,16 +296,13 @@ void SoftwareAES::_encrypt(uint8_t* buff)
} }
/* Last Round - unroll if possible */ /* Last Round - unroll if possible */
for (m = j = 0; j < Nb; j++, m += 3) for (m = j = 0; j < Nb; j++, m += 3) {
{ y[j] = fkey[k++] ^ (uint32_t)AEStb.fbsub[(uint8_t)x[j]] ^ ROTL8((uint32_t)AEStb.fbsub[(uint8_t)(x[fi[m]] >> 8)]) ^
y[j] = fkey[k++] ^ (uint32_t)AEStb.fbsub[(uint8_t)x[j]] ^
ROTL8((uint32_t)AEStb.fbsub[(uint8_t)(x[fi[m]] >> 8)])^
ROTL16((uint32_t)AEStb.fbsub[(uint8_t)(x[fi[m + 1]] >> 16)]) ^ ROTL16((uint32_t)AEStb.fbsub[(uint8_t)(x[fi[m + 1]] >> 16)]) ^
ROTL24((uint32_t)AEStb.fbsub[(uint8_t)(x[fi[m + 2]] >> 24)]); ROTL24((uint32_t)AEStb.fbsub[(uint8_t)(x[fi[m + 2]] >> 24)]);
} }
for (i = j = 0; i < Nb; i++, j += 4) for (i = j = 0; i < Nb; i++, j += 4) {
{
unpack(y[i], (uint8_t*)&buff[j]); unpack(y[i], (uint8_t*)&buff[j]);
x[i] = y[i] = 0; /* clean up stack */ x[i] = y[i] = 0; /* clean up stack */
} }
@@ -329,13 +310,11 @@ void SoftwareAES::_encrypt(uint8_t* buff)
return; return;
} }
void SoftwareAES::_decrypt(uint8_t* buff) void SoftwareAES::_decrypt(uint8_t* buff) {
{
int i, j, k, m; int i, j, k, m;
uint32_t a[8], b[8], *x, *y, *t; uint32_t a[8], b[8], *x, *y, *t;
for (i = j = 0; i < Nb; i++, j += 4) for (i = j = 0; i < Nb; i++, j += 4) {
{
a[i] = pack(buff + j); a[i] = pack(buff + j);
a[i] ^= rkey[i]; a[i] ^= rkey[i];
} }
@@ -345,20 +324,16 @@ void SoftwareAES::_decrypt(uint8_t* buff)
y = b; y = b;
/* State alternates between a and b */ /* State alternates between a and b */
for (i = 1; i < Nr; i++) for (i = 1; i < Nr; i++) {
{
/* Nr is number of rounds. May be odd. */ /* Nr is number of rounds. May be odd. */
/* if Nb is fixed - unroll this next /* if Nb is fixed - unroll this next
loop and hard-code in the values of ri[] */ loop and hard-code in the values of ri[] */
for (m = j = 0; j < Nb; j++, m += 3) for (m = j = 0; j < Nb; j++, m += 3) {
{
/* This is the time-critical bit */ /* This is the time-critical bit */
y[j] = rkey[k++] ^ AEStb.rtable[(uint8_t)x[j]] ^ y[j] = rkey[k++] ^ AEStb.rtable[(uint8_t)x[j]] ^ ROTL8(AEStb.rtable[(uint8_t)(x[ri[m]] >> 8)]) ^
ROTL8(AEStb.rtable[(uint8_t)(x[ri[m]] >> 8)])^ ROTL16(AEStb.rtable[(uint8_t)(x[ri[m + 1]] >> 16)]) ^ ROTL24(AEStb.rtable[(uint8_t)(x[ri[m + 2]] >> 24)]);
ROTL16(AEStb.rtable[(uint8_t)(x[ri[m + 1]] >> 16)])^
ROTL24(AEStb.rtable[(uint8_t)(x[ri[m + 2]] >> 24)]);
} }
t = x; t = x;
@@ -367,16 +342,13 @@ void SoftwareAES::_decrypt(uint8_t* buff)
} }
/* Last Round - unroll if possible */ /* Last Round - unroll if possible */
for (m = j = 0; j < Nb; j++, m += 3) for (m = j = 0; j < Nb; j++, m += 3) {
{ y[j] = rkey[k++] ^ (uint32_t)AEStb.rbsub[(uint8_t)x[j]] ^ ROTL8((uint32_t)AEStb.rbsub[(uint8_t)(x[ri[m]] >> 8)]) ^
y[j] = rkey[k++] ^ (uint32_t)AEStb.rbsub[(uint8_t)x[j]] ^
ROTL8((uint32_t)AEStb.rbsub[(uint8_t)(x[ri[m]] >> 8)])^
ROTL16((uint32_t)AEStb.rbsub[(uint8_t)(x[ri[m + 1]] >> 16)]) ^ ROTL16((uint32_t)AEStb.rbsub[(uint8_t)(x[ri[m + 1]] >> 16)]) ^
ROTL24((uint32_t)AEStb.rbsub[(uint8_t)(x[ri[m + 2]] >> 24)]); ROTL24((uint32_t)AEStb.rbsub[(uint8_t)(x[ri[m + 2]] >> 24)]);
} }
for (i = j = 0; i < Nb; i++, j += 4) for (i = j = 0; i < Nb; i++, j += 4) {
{
unpack(y[i], (uint8_t*)&buff[j]); unpack(y[i], (uint8_t*)&buff[j]);
x[i] = y[i] = 0; /* clean up stack */ x[i] = y[i] = 0; /* clean up stack */
} }
@@ -384,14 +356,10 @@ void SoftwareAES::_decrypt(uint8_t* buff)
return; return;
} }
void SoftwareAES::setKey(const uint8_t* key) void SoftwareAES::setKey(const uint8_t* key) { gkey(4, 4, key); }
{
gkey(4, 4, key);
}
// CBC mode decryption // CBC mode decryption
void SoftwareAES::decrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len) void SoftwareAES::decrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len) {
{
uint8_t block[16]; uint8_t block[16];
const uint8_t* ctext_ptr; const uint8_t* ctext_ptr;
unsigned int blockno = 0, i; unsigned int blockno = 0, i;
@@ -399,30 +367,31 @@ void SoftwareAES::decrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outb
// fprintf( stderr,"aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len ); // fprintf( stderr,"aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len );
// printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len); // printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len);
for (blockno = 0; blockno <= (len / sizeof(block)); blockno++) for (blockno = 0; blockno <= (len / sizeof(block)); blockno++) {
{
unsigned int fraction; unsigned int fraction;
if (blockno == (len / sizeof(block))) // last block if (blockno == (len / sizeof(block))) // last block
{ {
fraction = len % sizeof(block); fraction = len % sizeof(block);
if (fraction == 0) break; if (fraction == 0)
break;
memset(block, 0, sizeof(block)); memset(block, 0, sizeof(block));
} } else
else fraction = 16; fraction = 16;
// debug_printf("block %d: fraction = %d\n", blockno, fraction); // debug_printf("block %d: fraction = %d\n", blockno, fraction);
memcpy(block, inbuf + blockno * sizeof(block), fraction); memcpy(block, inbuf + blockno * sizeof(block), fraction);
_decrypt(block); _decrypt(block);
if (blockno == 0) ctext_ptr = iv; if (blockno == 0)
else ctext_ptr = (uint8_t*)(inbuf + (blockno - 1) * sizeof(block)); ctext_ptr = iv;
else
ctext_ptr = (uint8_t*)(inbuf + (blockno - 1) * sizeof(block));
for (i = 0; i < fraction; i++) for (i = 0; i < fraction; i++)
outbuf[blockno * sizeof(block) + i] = outbuf[blockno * sizeof(block) + i] = ctext_ptr[i] ^ block[i];
ctext_ptr[i] ^ block[i];
// debug_printf("Block %d output: ", blockno); // debug_printf("Block %d output: ", blockno);
// hexdump(outbuf + blockno*sizeof(block), 16); // hexdump(outbuf + blockno*sizeof(block), 16);
@@ -430,8 +399,7 @@ void SoftwareAES::decrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outb
} }
// CBC mode encryption // CBC mode encryption
void SoftwareAES::encrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len) void SoftwareAES::encrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len) {
{
uint8_t block[16]; uint8_t block[16];
uint8_t feedback[16]; uint8_t feedback[16];
memcpy(feedback, iv, 16); memcpy(feedback, iv, 16);
@@ -440,19 +408,19 @@ void SoftwareAES::encrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outb
// printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len); // printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len);
// fprintf( stderr,"aes_encrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len); // fprintf( stderr,"aes_encrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len);
for (blockno = 0; blockno <= (len / sizeof(block)); blockno++) for (blockno = 0; blockno <= (len / sizeof(block)); blockno++) {
{
unsigned int fraction; unsigned int fraction;
if (blockno == (len / sizeof(block))) // last block if (blockno == (len / sizeof(block))) // last block
{ {
fraction = len % sizeof(block); fraction = len % sizeof(block);
if (fraction == 0) break; if (fraction == 0)
break;
memset(block, 0, sizeof(block)); memset(block, 0, sizeof(block));
} } else
else fraction = 16; fraction = 16;
// debug_printf("block %d: fraction = %d\n", blockno, fraction); // debug_printf("block %d: fraction = %d\n", blockno, fraction);
memcpy(block, inbuf + blockno * sizeof(block), fraction); memcpy(block, inbuf + blockno * sizeof(block), fraction);
@@ -468,17 +436,16 @@ void SoftwareAES::encrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outb
} }
} }
#if __AES__ || _MSC_VER >= 1800 #if _AES_NI
#include <wmmintrin.h> #include <wmmintrin.h>
class NiAES : public IAES class NiAES : public IAES {
{
__m128i m_ekey[11]; __m128i m_ekey[11];
__m128i m_dkey[11]; __m128i m_dkey[11];
public: public:
void encrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len) void encrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len) {
{
__m128i feedback, data; __m128i feedback, data;
uint64_t i, j; uint64_t i, j;
if (len % 16) if (len % 16)
@@ -486,8 +453,7 @@ public:
else else
len /= 16; len /= 16;
feedback = _mm_loadu_si128((__m128i*)iv); feedback = _mm_loadu_si128((__m128i*)iv);
for (i=0 ; i<len ; i++) for (i = 0; i < len; i++) {
{
data = _mm_loadu_si128(&((__m128i*)inbuf)[i]); data = _mm_loadu_si128(&((__m128i*)inbuf)[i]);
feedback = _mm_xor_si128(data, feedback); feedback = _mm_xor_si128(data, feedback);
feedback = _mm_xor_si128(feedback, m_ekey[0]); feedback = _mm_xor_si128(feedback, m_ekey[0]);
@@ -497,8 +463,7 @@ public:
_mm_storeu_si128(&((__m128i*)outbuf)[i], feedback); _mm_storeu_si128(&((__m128i*)outbuf)[i], feedback);
} }
} }
void decrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len) void decrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len) {
{
__m128i data, feedback, last_in; __m128i data, feedback, last_in;
uint64_t i, j; uint64_t i, j;
if (len % 16) if (len % 16)
@@ -506,8 +471,7 @@ public:
else else
len /= 16; len /= 16;
feedback = _mm_loadu_si128((__m128i*)iv); feedback = _mm_loadu_si128((__m128i*)iv);
for (i=0 ; i<len ; i++) for (i = 0; i < len; i++) {
{
last_in = _mm_loadu_si128(&((__m128i*)inbuf)[i]); last_in = _mm_loadu_si128(&((__m128i*)inbuf)[i]);
data = _mm_xor_si128(last_in, m_dkey[0]); data = _mm_xor_si128(last_in, m_dkey[0]);
for (j = 1; j < 10; j++) for (j = 1; j < 10; j++)
@@ -519,8 +483,7 @@ public:
} }
} }
static inline __m128i AES_128_ASSIST (__m128i temp1, __m128i temp2) static inline __m128i AES_128_ASSIST(__m128i temp1, __m128i temp2) {
{
__m128i temp3; __m128i temp3;
temp2 = _mm_shuffle_epi32(temp2, 0xff); temp2 = _mm_shuffle_epi32(temp2, 0xff);
temp3 = _mm_slli_si128(temp1, 0x4); temp3 = _mm_slli_si128(temp1, 0x4);
@@ -533,8 +496,7 @@ public:
return temp1; return temp1;
} }
void setKey(const uint8_t* key) void setKey(const uint8_t* key) {
{
__m128i temp1, temp2; __m128i temp1, temp2;
temp1 = _mm_loadu_si128((__m128i*)key); temp1 = _mm_loadu_si128((__m128i*)key);
@@ -583,14 +545,13 @@ public:
} }
}; };
static int HAS_AES_NI = -1;
#endif #endif
static int HAS_AES_NI = -1; std::unique_ptr<IAES> NewAES() {
std::unique_ptr<IAES> NewAES() #if _AES_NI
{ if (HAS_AES_NI == -1) {
#if __AES__ || _MSC_VER >= 1800
if (HAS_AES_NI == -1)
{
#if _MSC_VER #if _MSC_VER
int info[4]; int info[4];
__cpuid(info, 1); __cpuid(info, 1);
@@ -602,13 +563,12 @@ std::unique_ptr<IAES> NewAES()
#endif #endif
} }
if (HAS_AES_NI) if (HAS_AES_NI)
return std::unique_ptr<IAES>(new NiAES); return std::make_unique<NiAES>();
else else
return std::unique_ptr<IAES>(new SoftwareAES); return std::make_unique<SoftwareAES>();
#else #else
return std::unique_ptr<IAES>(new SoftwareAES); return std::make_unique<SoftwareAES>();
#endif #endif
} }
} } // namespace nod

View File

@@ -1,22 +1,24 @@
#include <stdio.h>
#include "nod/nod.hpp" #include "nod/nod.hpp"
#include "nod/DiscBase.hpp"
namespace nod #include <cstdio>
{
#include "nod/DiscBase.hpp"
#include "nod/DiscGCN.hpp"
#include "nod/DiscWii.hpp"
namespace nod {
logvisor::Module LogModule("nod"); logvisor::Module LogModule("nod");
std::unique_ptr<IDiscIO> NewDiscIOISO(const SystemChar* path); std::unique_ptr<IDiscIO> NewDiscIOISO(SystemStringView path);
std::unique_ptr<IDiscIO> NewDiscIOWBFS(const SystemChar* path); std::unique_ptr<IDiscIO> NewDiscIOWBFS(SystemStringView path);
std::unique_ptr<IDiscIO> NewDiscIONFS(SystemStringView path);
std::unique_ptr<DiscBase> OpenDiscFromImage(const SystemChar* path, bool& isWii) std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView 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, _S("Unable to open '%s'"), path);
return {}; return {};
} }
std::unique_ptr<IFileIO::IReadStream> rs = fio->beginReadStream(); std::unique_ptr<IFileIO::IReadStream> rs = fio->beginReadStream();
@@ -26,29 +28,30 @@ std::unique_ptr<DiscBase> OpenDiscFromImage(const SystemChar* path, bool& isWii)
isWii = false; isWii = false;
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, _S("Unable to read magic from '%s'"), path);
return {}; return {};
} }
if (magic == nod::SBig((uint32_t)'WBFS')) using SignedSize = std::make_signed<SystemString::size_type>::type;
{ const auto dotPos = SignedSize(path.rfind(_SYS_STR('.')));
const auto slashPos = SignedSize(path.find_last_of(_SYS_STR("/\\")));
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 !path.compare(slashPos + 1, 4, _SYS_STR("hif_")) &&
{ !path.compare(dotPos, path.size() - dotPos, _SYS_STR(".nfs"))) {
discIO = NewDiscIONFS(path);
isWii = true;
} else {
rs->seek(0x18, SEEK_SET); rs->seek(0x18, SEEK_SET);
rs->read(&magic, 4); rs->read(&magic, 4);
magic = nod::SBig(magic); magic = nod::SBig(magic);
if (magic == 0x5D1C9EA3) if (magic == 0x5D1C9EA3) {
{
discIO = NewDiscIOISO(path); discIO = NewDiscIOISO(path);
isWii = true; isWii = true;
} } else {
else
{
rs->read(&magic, 4); rs->read(&magic, 4);
magic = nod::SBig(magic); magic = nod::SBig(magic);
if (magic == 0xC2339F3D) if (magic == 0xC2339F3D)
@@ -56,33 +59,29 @@ std::unique_ptr<DiscBase> OpenDiscFromImage(const SystemChar* 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, _S("'%s' 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);
ret = std::unique_ptr<DiscBase>(new DiscWii(std::move(discIO), Err)); if (err)
if (Err)
return {}; return {};
return ret; return ret;
} }
ret = std::unique_ptr<DiscBase>(new DiscGCN(std::move(discIO), Err)); ret = std::make_unique<DiscGCN>(std::move(discIO), err);
if (Err) if (err)
return {}; return {};
return ret; return ret;
} }
std::unique_ptr<DiscBase> OpenDiscFromImage(const SystemChar* path) std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path) {
{
bool isWii; bool isWii;
return OpenDiscFromImage(path, isWii); return OpenDiscFromImage(path, isWii);
} }
} } // namespace nod

View File

@@ -17,7 +17,7 @@
# endif # endif
#else // ! defined __LITTLE_ENDIAN__ #else // ! defined __LITTLE_ENDIAN__
#ifndef _WIN32 #ifndef _WIN32
# include <endian.h> // machine/endian.h # include <machine/endian.h>
#endif #endif
# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ # if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define SHA_BIG_ENDIAN # define SHA_BIG_ENDIAN