mirror of
https://github.com/AxioDL/nod.git
synced 2025-12-09 05:28:00 +00:00
Compare commits
121 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6febcc2c79 | |||
| 9584303083 | |||
| b513a7f4e0 | |||
|
258076c298
|
|||
| 72893dcacb | |||
|
30697375ad
|
|||
| 2f53b21740 | |||
| 45f56d21f1 | |||
| 27da856af3 | |||
|
2288e71605
|
|||
| 0396cf467b | |||
| 0985c63958 | |||
| c1635245b8 | |||
|
a525f60775
|
|||
|
8127bddb97
|
|||
|
|
3c25647b6e | ||
|
3eccde013d
|
|||
|
|
ab8f4c3990 | ||
|
6a231004b1
|
|||
| d14b798b5f | |||
| 1f110f3549 | |||
| 311d20532e | |||
| 8fdc893c86 | |||
| fdc8be487d | |||
| 3a21961a4e | |||
| da399b5b67 | |||
| 11c734be47 | |||
| 364787604d | |||
| 02c188497a | |||
| d53d677038 | |||
| 5b1b6f6f80 | |||
| 393a11ffb5 | |||
|
|
2783337c36 | ||
|
|
dffcac50c5 | ||
|
|
f147e12356 | ||
|
|
48a2981a93 | ||
|
|
19604b2a3b | ||
|
|
c1a1d1abc8 | ||
|
|
6bf4f07129 | ||
|
|
75fc574f81 | ||
|
|
11a0351d1c | ||
|
|
4ec6c6697b | ||
| ba0c2b7843 | |||
|
|
221bc7c7f2 | ||
| acdadaf963 | |||
|
d658909948
|
|||
|
|
091262ace1 | ||
| 97cfcea14e | |||
|
|
f5c3cbdcd7 | ||
|
|
7ddff919c1 | ||
|
|
4bba7af2c2 | ||
|
|
f443b60bde | ||
|
|
998d6a77c3 | ||
| 55301dd505 | |||
| 793413540d | |||
|
|
f11eb728bf | ||
|
|
a8753e273f | ||
| 63264695b0 | |||
| edc31b2107 | |||
|
|
1b3bb7815d | ||
|
|
89df98ee96 | ||
|
|
5935e84dab | ||
|
df1e450728
|
|||
| c9bf821285 | |||
|
|
18b297e312 | ||
| 255a37216f | |||
| 7da7761afb | |||
|
|
876a2ccf81 | ||
|
|
2171388b9d | ||
|
|
a572439967 | ||
|
|
ac6f2a1ed2 | ||
|
|
37792ba116 | ||
| d9b6be8446 | |||
|
|
47322b9496 | ||
|
|
77013bbd9f | ||
|
|
34b943c40f | ||
|
|
a1284ae065 | ||
|
|
4dd0375cae | ||
|
|
01237372e1 | ||
|
|
d9638cc60d | ||
|
|
0ac7140542 | ||
|
|
a5e9166194 | ||
|
|
ca2aeecc64 | ||
|
|
cd782047c8 | ||
|
|
2b7ea07cae | ||
|
|
ed28576b99 | ||
|
|
95ed2ae7dc | ||
|
|
f1c76a475d | ||
|
|
be8409681f | ||
|
|
3d380fdc3b | ||
|
|
f87b286ff3 | ||
|
|
e964a013fe | ||
|
|
eb6aa30563 | ||
| 1ad101897c | |||
|
|
6f777ebb48 | ||
|
|
42589c3604 | ||
|
|
4d9071bad7 | ||
|
|
d5f5db440c | ||
|
|
51a15e474e | ||
|
|
274a63bb30 | ||
|
|
bab7aab6fa | ||
|
|
5197abc131 | ||
|
|
648c015383 | ||
|
|
bf00fcd10f | ||
|
|
a557f86974 | ||
|
|
34de6276b0 | ||
|
|
3d70a568dc | ||
| 63ae60a967 | |||
|
|
e20fce1e6f | ||
|
|
b5916af702 | ||
|
|
58ceb47b25 | ||
|
|
69e96e3b3c | ||
|
|
27a2cb5998 | ||
|
|
c374038103 | ||
|
|
db1a6f13a2 | ||
|
|
fb2a5c91d2 | ||
| 42ef3a7958 | |||
|
|
d597400f4a | ||
| e99290e3c3 | |||
| 72169e8e77 | |||
| a7c19799e1 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -4,3 +4,7 @@ version.h
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
*.autosave
|
*.autosave
|
||||||
docs/*
|
docs/*
|
||||||
|
.idea/
|
||||||
|
cmake-build-*
|
||||||
|
build/
|
||||||
|
out/
|
||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +1,4 @@
|
|||||||
[submodule "logvisor"]
|
[submodule "logvisor"]
|
||||||
path = logvisor
|
path = logvisor
|
||||||
url = https://github.com/AxioDL/logvisor.git
|
url = ../logvisor.git
|
||||||
|
branch = master
|
||||||
|
|||||||
115
CMakeLists.txt
115
CMakeLists.txt
@@ -1,18 +1,111 @@
|
|||||||
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)
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
if (MSVC)
|
||||||
|
# Shaddup MSVC
|
||||||
|
add_compile_definitions(UNICODE=1 _UNICODE=1 __SSE__=1
|
||||||
|
_CRT_SECURE_NO_WARNINGS=1 D_SCL_SECURE_NO_WARNINGS=1
|
||||||
|
_SCL_SECURE_NO_DEPRECATE=1 _CRT_NONSTDC_NO_WARNINGS=1
|
||||||
|
_ENABLE_EXTENDED_ALIGNED_STORAGE=1 NOMINMAX=1)
|
||||||
|
add_compile_options(/IGNORE:4221 /wd4018 /wd4800 /wd4005 /wd4311 /wd4068
|
||||||
|
/wd4267 /wd4244 /wd4200 /wd4305 /wd4067 /wd4146 /wd4309 /wd4805 /utf-8 ${VS_OPTIONS})
|
||||||
|
|
||||||
|
add_compile_options(
|
||||||
|
# Disable exceptions
|
||||||
|
$<$<COMPILE_LANGUAGE:CXX>:/EHsc->
|
||||||
|
|
||||||
|
# Disable RTTI
|
||||||
|
$<$<COMPILE_LANGUAGE:CXX>:/GR->
|
||||||
|
|
||||||
|
# Enforce various standards compliant behavior.
|
||||||
|
$<$<COMPILE_LANGUAGE:CXX>:/permissive->
|
||||||
|
|
||||||
|
# Enable standard volatile semantics.
|
||||||
|
$<$<COMPILE_LANGUAGE:CXX>:/volatile:iso>
|
||||||
|
|
||||||
|
# Reports the proper value for the __cplusplus preprocessor macro.
|
||||||
|
$<$<COMPILE_LANGUAGE:CXX>:/Zc:__cplusplus>
|
||||||
|
|
||||||
|
# Use latest C++ standard.
|
||||||
|
$<$<COMPILE_LANGUAGE:CXX>:/std:c++latest>
|
||||||
|
)
|
||||||
|
add_compile_definitions(FMT_EXCEPTIONS=0 _HAS_EXCEPTIONS=0)
|
||||||
|
|
||||||
|
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||||
|
# Flags for MSVC (not clang-cl)
|
||||||
|
add_compile_options(
|
||||||
|
# Allow constexpr variables to have explicit external linkage.
|
||||||
|
$<$<COMPILE_LANGUAGE:CXX>:/Zc:externConstexpr>
|
||||||
|
|
||||||
|
# Assume that new throws exceptions, allowing better code generation.
|
||||||
|
$<$<COMPILE_LANGUAGE:CXX>:/Zc:throwingNew>
|
||||||
|
|
||||||
|
# Link-time Code Generation for Release builds
|
||||||
|
$<$<OR:$<CONFIG:Release>,$<CONFIG:RelWithDebInfo>>:/GL>
|
||||||
|
)
|
||||||
|
|
||||||
|
# Link-time Code Generation for Release builds
|
||||||
|
set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "/LTCG")
|
||||||
|
set(CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO "/LTCG")
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/RELEASE /LTCG /OPT:REF /OPT:ICF /INCREMENTAL:NO")
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "/DEBUG /RELEASE /LTCG /OPT:REF /OPT:ICF /INCREMENTAL:NO /DEBUGTYPE:cv,fixup")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NOT TARGET logvisor)
|
include (CMakePackageConfigHelpers)
|
||||||
add_subdirectory(logvisor)
|
|
||||||
set(LOGVISOR_INCLUDE_DIR logvisor/include)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include_directories(include ${LOGVISOR_INCLUDE_DIR})
|
if (WIN32 AND NOT TARGET nowide)
|
||||||
file(GLOB NOD_HEADERS include/nod/*.h*)
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(
|
||||||
|
nowide
|
||||||
|
URL https://github.com/boostorg/nowide/releases/download/v11.3.0/nowide_standalone_v11.3.0.tar.gz
|
||||||
|
URL_HASH SHA256=153ac93173c8de9c08e7701e471fa750f84c27e51fe329570c5aa06016591f8c
|
||||||
|
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
||||||
|
EXCLUDE_FROM_ALL
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(nowide)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if(NOT TARGET spdlog)
|
||||||
|
find_package(spdlog REQUIRED)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_subdirectory(lib)
|
add_subdirectory(lib)
|
||||||
add_subdirectory(driver)
|
add_subdirectory(driver)
|
||||||
install(DIRECTORY include/nod DESTINATION include/nod)
|
|
||||||
|
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||||
|
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}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
4
Config.cmake.in
Normal file
4
Config.cmake.in
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/nodTargets.cmake")
|
||||||
|
check_required_components(nod)
|
||||||
@@ -34,19 +34,19 @@ a content pipeline using the `nod::DiscBuilderBase` interface.
|
|||||||
```cpp
|
```cpp
|
||||||
/* Sample logging lambda for progress feedback */
|
/* Sample logging lambda for progress feedback */
|
||||||
size_t lastIdx = -1;
|
size_t lastIdx = -1;
|
||||||
auto progFunc = [&](size_t idx, const nod::SystemString& name, size_t bytes)
|
auto progFunc = [&](size_t idx, const std::string& name, size_t bytes)
|
||||||
{
|
{
|
||||||
if (idx != lastIdx)
|
if (idx != lastIdx)
|
||||||
{
|
{
|
||||||
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
add_executable(nodtool main.cpp)
|
add_executable(nodtool main.cpp)
|
||||||
|
|
||||||
target_link_libraries(nodtool nod logvisor)
|
target_link_libraries(nodtool nod spdlog::spdlog)
|
||||||
if (NOT WIN32)
|
if (NOT WIN32)
|
||||||
target_link_libraries(nodtool pthread)
|
target_link_libraries(nodtool pthread)
|
||||||
if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||||
target_link_libraries(nodtool execinfo)
|
target_link_libraries(nodtool execinfo)
|
||||||
else()
|
else ()
|
||||||
target_link_libraries(nodtool dl)
|
target_link_libraries(nodtool dl)
|
||||||
endif()
|
endif ()
|
||||||
endif()
|
else ()
|
||||||
|
target_sources(nodtool PRIVATE app.manifest)
|
||||||
|
endif ()
|
||||||
|
|||||||
9
driver/app.manifest
Normal file
9
driver/app.manifest
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<assemblyIdentity type="win32" name="..." version="6.0.0.0"/>
|
||||||
|
<application>
|
||||||
|
<windowsSettings>
|
||||||
|
<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
|
||||||
|
</windowsSettings>
|
||||||
|
</application>
|
||||||
|
</assembly>
|
||||||
393
driver/main.cpp
393
driver/main.cpp
@@ -1,265 +1,316 @@
|
|||||||
#include <stdio.h>
|
#include <array>
|
||||||
#include <string.h>
|
#include <cstddef>
|
||||||
#include "logvisor/logvisor.hpp"
|
#include <cstdint>
|
||||||
#include "nod/nod.hpp"
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#if _WIN32
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <io.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
static void printHelp()
|
#include <spdlog/spdlog.h>
|
||||||
{
|
|
||||||
fprintf(stderr, "Usage:\n"
|
#include <nod/DiscBase.hpp>
|
||||||
" nodtool extract [-f] <image-in> [<dir-out>]\n"
|
#include <nod/DiscGCN.hpp>
|
||||||
" nodtool makegcn <fsroot-in> [<image-out>]\n"
|
#include <nod/DiscWii.hpp>
|
||||||
" nodtool makewii <fsroot-in> [<image-out>]\n"
|
#include <nod/nod.hpp>
|
||||||
" nodtool mergegcn <fsroot-in> <image-in> [<image-out>]\n"
|
#include "../lib/Util.hpp"
|
||||||
" nodtool mergewii <fsroot-in> <image-in> [<image-out>]\n");
|
|
||||||
|
static void printHelp() {
|
||||||
|
fmt::print(stderr,
|
||||||
|
"Usage:\n"
|
||||||
|
" nodtool extract [options] <image-in> [<dir-out>]\n"
|
||||||
|
" nodtool makegcn [options] <fsroot-in> [<image-out>]\n"
|
||||||
|
" nodtool makewii [options] <fsroot-in> [<image-out>]\n"
|
||||||
|
" nodtool mergegcn [options] <fsroot-in> <image-in> [<image-out>]\n"
|
||||||
|
" nodtool mergewii [options] <fsroot-in> <image-in> [<image-out>]\n"
|
||||||
|
"Options:\n"
|
||||||
|
" -f Force (extract only)\n"
|
||||||
|
" -v Verbose details (extract only).\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if NOD_UCS2
|
#if _MSC_VER
|
||||||
#ifdef strcasecmp
|
#include <nowide/args.hpp>
|
||||||
#undef strcasecmp
|
|
||||||
#endif
|
|
||||||
#define strcasecmp _wcsicmp
|
|
||||||
#define PRISize "Iu"
|
#define PRISize "Iu"
|
||||||
int wmain(int argc, wchar_t* argv[])
|
int main(int argc, char* argv[]) {
|
||||||
|
nowide::args _(argc, argv);
|
||||||
#else
|
#else
|
||||||
#define PRISize "zu"
|
#define PRISize "zu"
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[]) {
|
||||||
#endif
|
#endif
|
||||||
{
|
int argidx = 1;
|
||||||
if (argc < 3 ||
|
std::string errand;
|
||||||
(!strcasecmp(argv[1], _S("makegcn")) && argc < 3) ||
|
bool verbose = false;
|
||||||
(!strcasecmp(argv[1], _S("makewii")) && argc < 3) ||
|
nod::ExtractionContext ctx = {true, [&](std::string_view str, float c) {
|
||||||
(!strcasecmp(argv[1], _S("mergegcn")) && argc < 4) ||
|
if (verbose)
|
||||||
(!strcasecmp(argv[1], _S("mergewii")) && argc < 4))
|
fmt::print(stderr, "Current node: {}, Extraction {:g}% Complete\n", str,
|
||||||
{
|
c * 100.f);
|
||||||
|
}};
|
||||||
|
while (argidx < argc) {
|
||||||
|
if (!nod::StrCaseCmp(argv[argidx], "-f")) {
|
||||||
|
ctx.force = true;
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else if (!nod::StrCaseCmp(argv[argidx], "-v")) {
|
||||||
|
verbose = true;
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else if (errand.empty()) {
|
||||||
|
errand = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errand.empty()) {
|
||||||
printHelp();
|
printHelp();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable logging to console */
|
auto progFunc = [&](float prog, std::string_view name, size_t bytes) {
|
||||||
logvisor::RegisterStandardExceptions();
|
fmt::print("\r ");
|
||||||
logvisor::RegisterConsoleLogger();
|
if (bytes != SIZE_MAX)
|
||||||
|
fmt::print("\r{:g}% {} {} B", prog * 100.f, name, bytes);
|
||||||
bool verbose = false;
|
|
||||||
nod::ExtractionContext ctx = {true,
|
|
||||||
[&](const std::string& str, float c) {
|
|
||||||
if (verbose)
|
|
||||||
fprintf(stderr, "Current node: %s, Extraction %g%% Complete\n", str.c_str(), c * 100.f);
|
|
||||||
}};
|
|
||||||
const nod::SystemChar* inDir = nullptr;
|
|
||||||
const nod::SystemChar* outDir = _S(".");
|
|
||||||
|
|
||||||
for (int a=2 ; a<argc ; ++a)
|
|
||||||
{
|
|
||||||
if (argv[a][0] == '-' && argv[a][1] == 'f')
|
|
||||||
ctx.force = true;
|
|
||||||
else if (argv[a][0] == '-' && argv[a][1] == 'v')
|
|
||||||
verbose = true;
|
|
||||||
|
|
||||||
else if (!inDir)
|
|
||||||
inDir = argv[a];
|
|
||||||
else
|
else
|
||||||
outDir = argv[a];
|
fmt::print("\r{:g}% {}", prog * 100.f, name);
|
||||||
}
|
|
||||||
|
|
||||||
auto progFunc = [&](float prog, const nod::SystemString& name, size_t bytes)
|
|
||||||
{
|
|
||||||
nod::Printf(_S("\r "));
|
|
||||||
if (bytes != -1)
|
|
||||||
nod::Printf(_S("\r%g%% %s %" PRISize " B"), prog * 100.f, name.c_str(), bytes);
|
|
||||||
else
|
|
||||||
nod::Printf(_S("\r%g%% %s"), prog * 100.f, name.c_str());
|
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!strcasecmp(argv[1], _S("extract")))
|
if (errand == "extract") {
|
||||||
{
|
std::string imageIn;
|
||||||
|
std::string dirOut;
|
||||||
|
while (argidx < argc) {
|
||||||
|
if (imageIn.empty()) {
|
||||||
|
imageIn = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else if (dirOut.empty()) {
|
||||||
|
dirOut = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
printHelp();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dirOut.empty())
|
||||||
|
dirOut = ".";
|
||||||
|
|
||||||
bool isWii;
|
bool isWii;
|
||||||
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(inDir, isWii);
|
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(imageIn, isWii);
|
||||||
if (!disc)
|
if (!disc)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
nod::Mkdir(outDir, 0755);
|
nod::Mkdir(dirOut.c_str(), 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(dirOut, ctx))
|
||||||
|
return 1;
|
||||||
|
} else if (errand == "makegcn") {
|
||||||
|
std::string fsrootIn;
|
||||||
|
std::string imageOut;
|
||||||
|
while (argidx < argc) {
|
||||||
|
if (fsrootIn.empty()) {
|
||||||
|
fsrootIn = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else if (imageOut.empty()) {
|
||||||
|
imageOut = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
printHelp();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if (!strcasecmp(argv[1], _S("makegcn")))
|
}
|
||||||
{
|
if (imageOut.empty())
|
||||||
|
imageOut = fsrootIn + ".gcm";
|
||||||
|
|
||||||
/* Pre-validate path */
|
/* Pre-validate path */
|
||||||
nod::Sstat theStat;
|
nod::Sstat theStat;
|
||||||
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode))
|
if (nod::Stat(fsrootIn.c_str(), &theStat) || !S_ISDIR(theStat.st_mode)) {
|
||||||
{
|
spdlog::error("unable to stat {} as directory");
|
||||||
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(fsrootIn))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
nod::EBuildResult ret;
|
nod::EBuildResult ret;
|
||||||
|
|
||||||
if (argc < 4)
|
nod::DiscBuilderGCN b(imageOut, progFunc);
|
||||||
{
|
ret = b.buildFromDirectory(fsrootIn);
|
||||||
nod::SystemString outPath(argv[2]);
|
|
||||||
outPath.append(_S(".iso"));
|
|
||||||
nod::DiscBuilderGCN b(outPath.c_str(), progFunc);
|
|
||||||
ret = b.buildFromDirectory(argv[2]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nod::DiscBuilderGCN b(argv[3], progFunc);
|
|
||||||
ret = b.buildFromDirectory(argv[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\n");
|
fmt::print("\n");
|
||||||
if (ret != nod::EBuildResult::Success)
|
if (ret != nod::EBuildResult::Success)
|
||||||
return 1;
|
return 1;
|
||||||
|
} else if (errand == "makewii") {
|
||||||
|
std::string fsrootIn;
|
||||||
|
std::string imageOut;
|
||||||
|
while (argidx < argc) {
|
||||||
|
if (fsrootIn.empty()) {
|
||||||
|
fsrootIn = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else if (imageOut.empty()) {
|
||||||
|
imageOut = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
printHelp();
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
else if (!strcasecmp(argv[1], _S("makewii")))
|
}
|
||||||
{
|
if (imageOut.empty())
|
||||||
|
imageOut = fsrootIn + ".iso";
|
||||||
|
|
||||||
/* Pre-validate path */
|
/* Pre-validate path */
|
||||||
nod::Sstat theStat;
|
nod::Sstat theStat;
|
||||||
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode))
|
if (nod::Stat(fsrootIn.c_str(), &theStat) || !S_ISDIR(theStat.st_mode)) {
|
||||||
{
|
spdlog::error("unable to stat {} as directory");
|
||||||
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(fsrootIn, dual))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
nod::EBuildResult ret;
|
nod::EBuildResult ret;
|
||||||
|
|
||||||
if (argc < 4)
|
nod::DiscBuilderWii b(imageOut, dual, progFunc);
|
||||||
{
|
ret = b.buildFromDirectory(fsrootIn);
|
||||||
nod::SystemString outPath(argv[2]);
|
|
||||||
outPath.append(_S(".iso"));
|
|
||||||
nod::DiscBuilderWii b(outPath.c_str(), dual, progFunc);
|
|
||||||
ret = b.buildFromDirectory(argv[2]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nod::DiscBuilderWii b(argv[3], dual, progFunc);
|
|
||||||
ret = b.buildFromDirectory(argv[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\n");
|
fmt::print("\n");
|
||||||
if (ret != nod::EBuildResult::Success)
|
if (ret != nod::EBuildResult::Success)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
} else if (errand == "mergegcn") {
|
||||||
else if (!strcasecmp(argv[1], _S("mergegcn")))
|
std::string fsrootIn;
|
||||||
{
|
std::string imageIn;
|
||||||
/* Pre-validate paths */
|
std::string imageOut;
|
||||||
nod::Sstat theStat;
|
while (argidx < argc) {
|
||||||
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode))
|
if (fsrootIn.empty()) {
|
||||||
{
|
fsrootIn = argv[argidx];
|
||||||
nod::LogModule.report(logvisor::Error, _S("unable to stat %s as directory"), argv[2]);
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else if (imageIn.empty()) {
|
||||||
|
imageIn = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else if (imageOut.empty()) {
|
||||||
|
imageOut = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
printHelp();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (nod::Stat(argv[3], &theStat) || !S_ISREG(theStat.st_mode))
|
}
|
||||||
{
|
if (imageOut.empty())
|
||||||
nod::LogModule.report(logvisor::Error, _S("unable to stat %s as file"), argv[3]);
|
imageOut = fsrootIn + ".gcm";
|
||||||
|
|
||||||
|
/* Pre-validate paths */
|
||||||
|
nod::Sstat theStat;
|
||||||
|
if (nod::Stat(fsrootIn.c_str(), &theStat) || !S_ISDIR(theStat.st_mode)) {
|
||||||
|
spdlog::error("unable to stat {} as directory");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (nod::Stat(imageIn.c_str(), &theStat) || !S_ISREG(theStat.st_mode)) {
|
||||||
|
spdlog::error("unable to stat {} as file");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isWii;
|
bool isWii;
|
||||||
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(argv[3], isWii);
|
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(imageIn, isWii);
|
||||||
if (!disc)
|
if (!disc) {
|
||||||
{
|
spdlog::error("unable to open image {}");
|
||||||
nod::LogModule.report(logvisor::Error, _S("unable to open image %s"), argv[3]);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (isWii)
|
if (isWii) {
|
||||||
{
|
spdlog::error("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), fsrootIn))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
nod::EBuildResult ret;
|
nod::EBuildResult ret;
|
||||||
|
|
||||||
if (argc < 5)
|
nod::DiscMergerGCN b(imageOut, static_cast<nod::DiscGCN&>(*disc), progFunc);
|
||||||
{
|
ret = b.mergeFromDirectory(fsrootIn);
|
||||||
nod::SystemString outPath(argv[2]);
|
|
||||||
outPath.append(_S(".iso"));
|
|
||||||
nod::DiscMergerGCN b(outPath.c_str(), static_cast<nod::DiscGCN&>(*disc), progFunc);
|
|
||||||
ret = b.mergeFromDirectory(argv[2]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nod::DiscMergerGCN b(argv[4], static_cast<nod::DiscGCN&>(*disc), progFunc);
|
|
||||||
ret = b.mergeFromDirectory(argv[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\n");
|
fmt::print("\n");
|
||||||
if (ret != nod::EBuildResult::Success)
|
if (ret != nod::EBuildResult::Success)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
} else if (errand == "mergewii") {
|
||||||
else if (!strcasecmp(argv[1], _S("mergewii")))
|
std::string fsrootIn;
|
||||||
{
|
std::string imageIn;
|
||||||
/* Pre-validate paths */
|
std::string imageOut;
|
||||||
nod::Sstat theStat;
|
while (argidx < argc) {
|
||||||
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode))
|
if (fsrootIn.empty()) {
|
||||||
{
|
fsrootIn = argv[argidx];
|
||||||
nod::LogModule.report(logvisor::Error, _S("unable to stat %s as directory"), argv[2]);
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else if (imageIn.empty()) {
|
||||||
|
imageIn = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else if (imageOut.empty()) {
|
||||||
|
imageOut = argv[argidx];
|
||||||
|
++argidx;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
printHelp();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (nod::Stat(argv[3], &theStat) || !S_ISREG(theStat.st_mode))
|
}
|
||||||
{
|
if (imageOut.empty())
|
||||||
nod::LogModule.report(logvisor::Error, _S("unable to stat %s as file"), argv[3]);
|
imageOut = fsrootIn + ".iso";
|
||||||
|
|
||||||
|
/* Pre-validate paths */
|
||||||
|
nod::Sstat theStat;
|
||||||
|
if (nod::Stat(fsrootIn.c_str(), &theStat) || !S_ISDIR(theStat.st_mode)) {
|
||||||
|
spdlog::error("unable to stat {} as directory");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (nod::Stat(imageIn.c_str(), &theStat) || !S_ISREG(theStat.st_mode)) {
|
||||||
|
spdlog::error("unable to stat {} as file");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isWii;
|
bool isWii;
|
||||||
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(argv[3], isWii);
|
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(imageIn, isWii);
|
||||||
if (!disc)
|
if (!disc) {
|
||||||
{
|
spdlog::error("unable to open image {}");
|
||||||
nod::LogModule.report(logvisor::Error, _S("unable to open image %s"), argv[3]);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (!isWii)
|
if (!isWii) {
|
||||||
{
|
spdlog::error("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), fsrootIn, dual))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
nod::EBuildResult ret;
|
nod::EBuildResult ret;
|
||||||
|
|
||||||
if (argc < 5)
|
nod::DiscMergerWii b(imageOut, static_cast<nod::DiscWii&>(*disc), dual, progFunc);
|
||||||
{
|
ret = b.mergeFromDirectory(fsrootIn);
|
||||||
nod::SystemString outPath(argv[2]);
|
|
||||||
outPath.append(_S(".iso"));
|
|
||||||
nod::DiscMergerWii b(outPath.c_str(), static_cast<nod::DiscWii&>(*disc), dual, progFunc);
|
|
||||||
ret = b.mergeFromDirectory(argv[2]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nod::DiscMergerWii b(argv[4], static_cast<nod::DiscWii&>(*disc), dual, progFunc);
|
|
||||||
ret = b.mergeFromDirectory(argv[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\n");
|
fmt::print("\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!"));
|
spdlog::info("Success!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,73 +1,52 @@
|
|||||||
#ifndef __NOD_DIRECTORY_ENUMERATOR__
|
#pragma once
|
||||||
#define __NOD_DIRECTORY_ENUMERATOR__
|
|
||||||
|
|
||||||
#include "Util.hpp"
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
namespace nod
|
namespace nod {
|
||||||
{
|
|
||||||
|
|
||||||
struct CaseInsensitiveCompare
|
/**
|
||||||
{
|
* @brief Case-insensitive comparator for std::map sorting
|
||||||
bool operator()(const std::string& lhs, const std::string& rhs) const
|
*/
|
||||||
{
|
struct CaseInsensitiveCompare {
|
||||||
#if _WIN32
|
// Allow heterogeneous lookup with maps that use this comparator.
|
||||||
if (_stricmp(lhs.c_str(), rhs.c_str()) < 0)
|
using is_transparent = void;
|
||||||
#else
|
|
||||||
if (strcasecmp(lhs.c_str(), rhs.c_str()) < 0)
|
bool operator()(std::string_view lhs, std::string_view rhs) const {
|
||||||
#endif
|
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](char lhs, char rhs) {
|
||||||
return true;
|
return std::tolower(static_cast<unsigned char>(lhs)) < std::tolower(static_cast<unsigned char>(rhs));
|
||||||
return false;
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#if _WIN32
|
|
||||||
bool operator()(const std::wstring& lhs, const std::wstring& rhs) const
|
|
||||||
{
|
|
||||||
if (_wcsicmp(lhs.c_str(), rhs.c_str()) < 0)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DirectoryEnumerator
|
class DirectoryEnumerator {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
enum class Mode
|
enum class Mode { Native, DirsSorted, FilesSorted, DirsThenFilesSorted };
|
||||||
{
|
struct Entry {
|
||||||
Native,
|
std::string m_path;
|
||||||
DirsSorted,
|
std::string m_name;
|
||||||
FilesSorted,
|
|
||||||
DirsThenFilesSorted
|
|
||||||
};
|
|
||||||
struct Entry
|
|
||||||
{
|
|
||||||
SystemString m_path;
|
|
||||||
SystemString m_name;
|
|
||||||
size_t m_fileSz;
|
size_t m_fileSz;
|
||||||
bool m_isDir;
|
bool m_isDir;
|
||||||
|
|
||||||
private:
|
Entry(std::string path, std::string name, size_t sz, bool isDir)
|
||||||
friend class DirectoryEnumerator;
|
: m_path(std::move(path)), m_name(std::move(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(std::string_view 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;}
|
explicit operator bool() const { return !m_entries.empty(); }
|
||||||
size_t size() const {return m_entries.size();}
|
[[nodiscard]] size_t size() const { return m_entries.size(); }
|
||||||
std::vector<Entry>::const_iterator begin() const {return m_entries.cbegin();}
|
[[nodiscard]] std::vector<Entry>::const_iterator begin() const { return m_entries.cbegin(); }
|
||||||
std::vector<Entry>::const_iterator end() const {return m_entries.cend();}
|
[[nodiscard]] std::vector<Entry>::const_iterator end() const { return m_entries.cend(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace nod
|
||||||
|
|
||||||
#endif // __NOD_DIRECTORY_ENUMERATOR__
|
|
||||||
|
|||||||
@@ -1,65 +1,52 @@
|
|||||||
#ifndef __NOD_DISC_BASE__
|
#pragma once
|
||||||
#define __NOD_DISC_BASE__
|
|
||||||
|
|
||||||
#include <vector>
|
#include <cstddef>
|
||||||
#include <memory>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <cstring>
|
||||||
#include <unordered_map>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include "Util.hpp"
|
#include <optional>
|
||||||
#include "IDiscIO.hpp"
|
#include <string>
|
||||||
#include "IFileIO.hpp"
|
#include <string_view>
|
||||||
|
|
||||||
namespace nod
|
#include "nod/IDiscIO.hpp"
|
||||||
{
|
#include "nod/IFileIO.hpp"
|
||||||
|
#include "nod/OSUTF.h"
|
||||||
|
#include "nod/Endian.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, std::string_view fileName, size_t fileBytesXfered)>;
|
||||||
{
|
|
||||||
Success,
|
|
||||||
Failed,
|
|
||||||
DiskFull
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class PartitionKind : uint32_t
|
enum class EBuildResult { Success, Failed, DiskFull };
|
||||||
{
|
|
||||||
Data,
|
|
||||||
Update,
|
|
||||||
Channel
|
|
||||||
};
|
|
||||||
const SystemChar* getKindString(PartitionKind kind);
|
|
||||||
|
|
||||||
class FSTNode
|
enum class PartitionKind : uint32_t { Data, Update, Channel };
|
||||||
{
|
const char* getKindString(PartitionKind kind);
|
||||||
|
|
||||||
|
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 +72,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 +97,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 +115,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 +130,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 +147,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,37 +166,14 @@ struct BI2Header
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ExtractionContext;
|
struct ExtractionContext;
|
||||||
class DiscBase
|
class IPartition;
|
||||||
{
|
class DiscBase;
|
||||||
|
|
||||||
|
class Node {
|
||||||
public:
|
public:
|
||||||
virtual ~DiscBase() = default;
|
enum class Kind { File, Directory };
|
||||||
|
|
||||||
class IPartition
|
private:
|
||||||
{
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Node
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum class Kind
|
|
||||||
{
|
|
||||||
File,
|
|
||||||
Directory
|
|
||||||
};
|
|
||||||
private:
|
|
||||||
friend class IPartition;
|
friend class IPartition;
|
||||||
const IPartition& m_parent;
|
const IPartition& m_parent;
|
||||||
Kind m_kind;
|
Kind m_kind;
|
||||||
@@ -228,69 +185,49 @@ public:
|
|||||||
std::vector<Node>::iterator m_childrenBegin;
|
std::vector<Node>::iterator m_childrenBegin;
|
||||||
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();
|
||||||
{
|
for (; it != end(); ++it) {
|
||||||
DirectoryIterator it=begin();
|
if (it->getName() == name)
|
||||||
for (; it != end() ; ++it)
|
|
||||||
{
|
|
||||||
if (!it->getName().compare(name))
|
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
return it;
|
return it;
|
||||||
@@ -298,9 +235,25 @@ public:
|
|||||||
return end();
|
return end();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool extractToDirectory(const SystemString& basePath, const ExtractionContext& ctx) const;
|
bool extractToDirectory(std::string_view 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;
|
||||||
uint64_t m_dolOff;
|
uint64_t m_dolOff;
|
||||||
@@ -313,7 +266,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 +274,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;
|
||||||
|
|
||||||
@@ -338,132 +290,128 @@ 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(std::string_view 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(std::string_view path, const ExtractionContext& ctx) const { return true; }
|
||||||
};
|
bool extractSysFiles(std::string_view 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(std::string_view path, const ExtractionContext& ctx) {
|
||||||
{
|
|
||||||
for (std::unique_ptr<IPartition>& part : m_partitions)
|
for (std::unique_ptr<IPartition>& part : m_partitions)
|
||||||
part->extractToDirectory(path, ctx);
|
part->extractToDirectory(path, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool extractDiscHeaderFiles(const SystemString& path, const ExtractionContext& ctx) const=0;
|
virtual bool extractDiscHeaderFiles(std::string_view 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<std::string, std::pair<uint64_t, uint64_t>> m_fileOffsetsSizes;
|
||||||
std::vector<FSTNode> m_buildNodes;
|
std::vector<FSTNode> m_buildNodes;
|
||||||
std::vector<std::string> m_buildNames;
|
std::vector<std::string> m_buildNames;
|
||||||
size_t m_buildNameOff = 0;
|
size_t m_buildNameOff = 0;
|
||||||
virtual uint64_t userAllocate(uint64_t reqSz, IPartWriteStream& ws)=0;
|
virtual uint64_t userAllocate(uint64_t reqSz, IPartWriteStream& ws) = 0;
|
||||||
virtual uint32_t packOffset(uint64_t offset) const=0;
|
virtual uint32_t packOffset(uint64_t offset) const = 0;
|
||||||
|
|
||||||
void recursiveBuildNodesPre(const SystemChar* dirIn);
|
void recursiveBuildNodesPre(std::string_view dirIn);
|
||||||
bool recursiveBuildNodes(IPartWriteStream& ws, bool system, const SystemChar* dirIn);
|
bool recursiveBuildNodes(IPartWriteStream& ws, bool system, std::string_view dirIn);
|
||||||
|
|
||||||
bool recursiveBuildFST(const SystemChar* dirIn,
|
bool recursiveBuildFST(std::string_view 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, std::string_view dirIn);
|
||||||
bool recursiveMergeNodes(IPartWriteStream& ws, bool system,
|
bool recursiveMergeNodes(IPartWriteStream& ws, bool system, const Node* nodeIn, std::string_view dirIn,
|
||||||
const DiscBase::IPartition::Node* nodeIn, const SystemChar* dirIn,
|
std::string_view keyPath);
|
||||||
const SystemString& keyPath);
|
bool recursiveMergeFST(const Node* nodeIn, std::string_view dirIn, std::function<void(void)> incParents,
|
||||||
bool recursiveMergeFST(const DiscBase::IPartition::Node* nodeIn,
|
size_t parentDirIdx, std::string_view 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, std::string_view dirIn);
|
||||||
const DiscBase::IPartition::Node* nodeIn,
|
|
||||||
const SystemChar* dirIn);
|
|
||||||
|
|
||||||
void addBuildName(const SystemString& str)
|
void addBuildName(std::string_view str) {
|
||||||
{
|
UTF8ToSJIS nameView(str);
|
||||||
SystemUTF8View utf8View(str);
|
m_buildNames.emplace_back(nameView.str());
|
||||||
m_buildNames.push_back(utf8View.utf8_str());
|
m_buildNameOff += nameView.str().size() + 1;
|
||||||
m_buildNameOff += str.size() + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscBuilderBase& m_parent;
|
DiscBuilderBase& m_parent;
|
||||||
@@ -471,36 +419,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, std::string_view dirIn);
|
||||||
bool buildFromDirectory(IPartWriteStream& ws,
|
static std::optional<uint64_t> CalculateTotalSizeBuild(std::string_view dirIn, PartitionKind kind, bool isWii);
|
||||||
const SystemChar* dirIn);
|
bool mergeFromDirectory(IPartWriteStream& ws, const IPartition* partIn, std::string_view dirIn);
|
||||||
static uint64_t CalculateTotalSizeBuild(const SystemChar* dirIn,
|
static std::optional<uint64_t> CalculateTotalSizeMerge(const IPartition* partIn, std::string_view dirIn);
|
||||||
PartitionKind kind, bool isWii);
|
|
||||||
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;
|
std::string m_outPath;
|
||||||
std::unique_ptr<IFileIO> m_fileIO;
|
std::unique_ptr<IFileIO> m_fileIO;
|
||||||
std::vector<std::unique_ptr<PartitionBuilderBase>> m_partitions;
|
std::vector<std::unique_ptr<PartitionBuilderBase>> m_partitions;
|
||||||
int64_t m_discCapacity;
|
int64_t m_discCapacity;
|
||||||
|
|
||||||
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 +454,15 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual ~DiscBuilderBase() = default;
|
virtual ~DiscBuilderBase() = default;
|
||||||
DiscBuilderBase(const SystemChar* outPath,
|
DiscBuilderBase(std::string_view 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__
|
|
||||||
|
|||||||
@@ -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(std::string_view 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(std::string_view path, const ExtractionContext& ctx) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DiscBuilderGCN : public DiscBuilderBase
|
class DiscBuilderGCN : public DiscBuilderBase {
|
||||||
{
|
|
||||||
friend class DiscMergerGCN;
|
friend class DiscMergerGCN;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DiscBuilderGCN(const SystemChar* outPath, FProgress progressCB);
|
DiscBuilderGCN(std::string_view outPath, FProgress progressCB);
|
||||||
EBuildResult buildFromDirectory(const SystemChar* dirIn);
|
EBuildResult buildFromDirectory(std::string_view dirIn);
|
||||||
static uint64_t CalculateTotalSizeRequired(const SystemChar* dirIn);
|
static std::optional<uint64_t> CalculateTotalSizeRequired(std::string_view 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(std::string_view outPath, DiscGCN& sourceDisc, FProgress progressCB);
|
||||||
EBuildResult mergeFromDirectory(const SystemChar* dirIn);
|
EBuildResult mergeFromDirectory(std::string_view dirIn);
|
||||||
static uint64_t CalculateTotalSizeRequired(DiscGCN& sourceDisc, const SystemChar* dirIn);
|
static std::optional<uint64_t> CalculateTotalSizeRequired(DiscGCN& sourceDisc, std::string_view dirIn);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace nod
|
||||||
|
|
||||||
|
|
||||||
#endif // __NOD_DISC_GCN__
|
|
||||||
|
|||||||
@@ -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(std::string_view outPath, bool dualLayer, FProgress progressCB);
|
||||||
bool extractDiscHeaderFiles(const SystemString& path, const ExtractionContext& ctx) const;
|
bool extractDiscHeaderFiles(std::string_view 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(std::string_view outPath, bool dualLayer, FProgress progressCB);
|
||||||
EBuildResult buildFromDirectory(const SystemChar* dirIn);
|
EBuildResult buildFromDirectory(std::string_view dirIn);
|
||||||
static uint64_t CalculateTotalSizeRequired(const SystemChar* dirIn, bool& dualLayer);
|
static std::optional<uint64_t> CalculateTotalSizeRequired(std::string_view 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(std::string_view outPath, DiscWii& sourceDisc, bool dualLayer, FProgress progressCB);
|
||||||
bool dualLayer, FProgress progressCB);
|
EBuildResult mergeFromDirectory(std::string_view dirIn);
|
||||||
EBuildResult mergeFromDirectory(const SystemChar* dirIn);
|
static std::optional<uint64_t> CalculateTotalSizeRequired(DiscWii& sourceDisc, std::string_view dirIn, bool& dualLayer);
|
||||||
static uint64_t CalculateTotalSizeRequired(DiscWii& sourceDisc, const SystemChar* dirIn,
|
|
||||||
bool& dualLayer);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace nod
|
||||||
|
|
||||||
#endif // __NOD_DISC_WII__
|
|
||||||
|
|||||||
78
include/nod/Endian.hpp
Normal file
78
include/nod/Endian.hpp
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#undef bswap16
|
||||||
|
#undef bswap32
|
||||||
|
#undef bswap64
|
||||||
|
|
||||||
|
namespace nod {
|
||||||
|
/* Type-sensitive byte swappers */
|
||||||
|
template <typename T>
|
||||||
|
static inline T bswap16(T val) {
|
||||||
|
#if __GNUC__
|
||||||
|
return __builtin_bswap16(val);
|
||||||
|
#elif _WIN32
|
||||||
|
return _byteswap_ushort(val);
|
||||||
|
#else
|
||||||
|
return (val = (val << 8) | ((val >> 8) & 0xFF));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline T bswap32(T val) {
|
||||||
|
#if __GNUC__
|
||||||
|
return __builtin_bswap32(val);
|
||||||
|
#elif _WIN32
|
||||||
|
return _byteswap_ulong(val);
|
||||||
|
#else
|
||||||
|
val = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16;
|
||||||
|
val = (val & 0x00FF00FF) << 8 | (val & 0xFF00FF00) >> 8;
|
||||||
|
return val;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline T bswap64(T val) {
|
||||||
|
#if __GNUC__
|
||||||
|
return __builtin_bswap64(val);
|
||||||
|
#elif _WIN32
|
||||||
|
return _byteswap_uint64(val);
|
||||||
|
#else
|
||||||
|
return ((val & 0xFF00000000000000ULL) >> 56) | ((val & 0x00FF000000000000ULL) >> 40) |
|
||||||
|
((val & 0x0000FF0000000000ULL) >> 24) | ((val & 0x000000FF00000000ULL) >> 8) |
|
||||||
|
((val & 0x00000000FF000000ULL) << 8) | ((val & 0x0000000000FF0000ULL) << 24) |
|
||||||
|
((val & 0x000000000000FF00ULL) << 40) | ((val & 0x00000000000000FFULL) << 56);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||||
|
static inline int16_t SBig(int16_t val) { return bswap16(val); }
|
||||||
|
static inline uint16_t SBig(uint16_t val) { return bswap16(val); }
|
||||||
|
static inline int32_t SBig(int32_t val) { return bswap32(val); }
|
||||||
|
static inline uint32_t SBig(uint32_t val) { return bswap32(val); }
|
||||||
|
static inline int64_t SBig(int64_t val) { return bswap64(val); }
|
||||||
|
static inline uint64_t SBig(uint64_t val) { return bswap64(val); }
|
||||||
|
|
||||||
|
static inline int16_t SLittle(int16_t val) { return val; }
|
||||||
|
static inline uint16_t SLittle(uint16_t val) { return val; }
|
||||||
|
static inline int32_t SLittle(int32_t val) { return val; }
|
||||||
|
static inline uint32_t SLittle(uint32_t val) { return val; }
|
||||||
|
static inline int64_t SLittle(int64_t val) { return val; }
|
||||||
|
static inline uint64_t SLittle(uint64_t val) { return val; }
|
||||||
|
#else
|
||||||
|
static inline int16_t SLittle(int16_t val) { return bswap16(val); }
|
||||||
|
static inline uint16_t SLittle(uint16_t val) { return bswap16(val); }
|
||||||
|
static inline int32_t SLittle(int32_t val) { return bswap32(val); }
|
||||||
|
static inline uint32_t SLittle(uint32_t val) { return bswap32(val); }
|
||||||
|
static inline int64_t SLittle(int64_t val) { return bswap64(val); }
|
||||||
|
static inline uint64_t SLittle(uint64_t val) { return bswap64(val); }
|
||||||
|
|
||||||
|
static inline int16_t SBig(int16_t val) { return val; }
|
||||||
|
static inline uint16_t SBig(uint16_t val) { return val; }
|
||||||
|
static inline int32_t SBig(int32_t val) { return val; }
|
||||||
|
static inline uint32_t SBig(uint32_t val) { return val; }
|
||||||
|
static inline int64_t SBig(int64_t val) { return val; }
|
||||||
|
static inline uint64_t SBig(uint64_t val) { return val; }
|
||||||
|
#endif
|
||||||
|
} // namespace nod
|
||||||
@@ -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__
|
|
||||||
|
|||||||
@@ -1,87 +1,34 @@
|
|||||||
#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 <string_view>
|
||||||
#include "Util.hpp"
|
|
||||||
|
|
||||||
namespace nod
|
#include "nod/IDiscIO.hpp"
|
||||||
{
|
|
||||||
|
|
||||||
class IFileIO
|
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 copyFromDisc(IPartReadStream& discio, uint64_t length, const std::function<void(float)>& prog);
|
||||||
{
|
|
||||||
uint64_t read = 0;
|
|
||||||
uint8_t buf[0x7c00];
|
|
||||||
while (length)
|
|
||||||
{
|
|
||||||
uint64_t thisSz = nod::min(uint64_t(0x7c00), length);
|
|
||||||
uint64_t readSz = discio.read(buf, thisSz);
|
|
||||||
if (thisSz != readSz)
|
|
||||||
{
|
|
||||||
LogModule.report(logvisor::Error, "unable to read enough from disc");
|
|
||||||
return read;
|
|
||||||
}
|
|
||||||
if (write(buf, readSz) != readSz)
|
|
||||||
{
|
|
||||||
LogModule.report(logvisor::Error, "unable to write in file");
|
|
||||||
return read;
|
|
||||||
}
|
|
||||||
length -= thisSz;
|
|
||||||
read += thisSz;
|
|
||||||
}
|
|
||||||
return read;
|
|
||||||
}
|
|
||||||
uint64_t copyFromDisc(IPartReadStream& discio, uint64_t length, const std::function<void(float)>& prog)
|
|
||||||
{
|
|
||||||
uint64_t read = 0;
|
|
||||||
uint8_t buf[0x7c00];
|
|
||||||
uint64_t total = length;
|
|
||||||
while (length)
|
|
||||||
{
|
|
||||||
uint64_t thisSz = nod::min(uint64_t(0x7c00), length);
|
|
||||||
uint64_t readSz = discio.read(buf, thisSz);
|
|
||||||
if (thisSz != readSz)
|
|
||||||
{
|
|
||||||
LogModule.report(logvisor::Error, "unable to read enough from disc");
|
|
||||||
return read;
|
|
||||||
}
|
|
||||||
if (write(buf, readSz) != readSz)
|
|
||||||
{
|
|
||||||
LogModule.report(logvisor::Error, "unable to write in file");
|
|
||||||
return read;
|
|
||||||
}
|
|
||||||
length -= thisSz;
|
|
||||||
read += thisSz;
|
|
||||||
prog(read / float(total));
|
|
||||||
}
|
|
||||||
return read;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
virtual std::unique_ptr<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(std::string_view path, int64_t maxWriteSize = -1);
|
||||||
std::unique_ptr<IFileIO> NewFileIO(const SystemChar* path, int64_t maxWriteSize=-1);
|
|
||||||
|
|
||||||
}
|
} // namespace nod
|
||||||
|
|
||||||
#endif // __NOD_IFILE_IO__
|
|
||||||
|
|||||||
113
include/nod/OSUTF.h
Normal file
113
include/nod/OSUTF.h
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
#ifdef __cplusplus
|
||||||
|
#include <array>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#if !__cpp_char8_t
|
||||||
|
using char8_t = uint8_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define OS_CONSTEXPR constexpr
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define OS_CONSTEXPR
|
||||||
|
|
||||||
|
typedef uint8_t char8_t;
|
||||||
|
typedef uint16_t char16_t;
|
||||||
|
typedef uint32_t char32_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
OS_CONSTEXPR inline bool IsSjisLeadByte(char8_t c) { return (c > 0x80 && c < 0xa0) || (c > 0xdf && c < 0xfd); }
|
||||||
|
|
||||||
|
OS_CONSTEXPR inline bool IsSjisTrailByte(char8_t c) { return c > 0x3f && c < 0xfd && c != 0x7f; }
|
||||||
|
|
||||||
|
char32_t OSSJISToUTF32(char16_t sjis);
|
||||||
|
|
||||||
|
char16_t OSUTF32ToSJIS(char32_t utf32);
|
||||||
|
|
||||||
|
char8_t OSUTF32ToAnsi(char32_t utf32);
|
||||||
|
|
||||||
|
char16_t* OSUTF32To16(char32_t utf32, char16_t* utf16);
|
||||||
|
|
||||||
|
char8_t* OSUTF32To8(char32_t utf32, char8_t* utf8);
|
||||||
|
|
||||||
|
const char16_t* OSUTF16To32(const char16_t* utf16, char32_t* utf32);
|
||||||
|
|
||||||
|
const char8_t* OSUTF8To32(const char8_t* utf8, char32_t* utf32);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
|
||||||
|
class SJISToUTF8 {
|
||||||
|
private:
|
||||||
|
std::string out;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SJISToUTF8(std::string_view sv) {
|
||||||
|
const auto* in = reinterpret_cast<const char8_t*>(sv.data());
|
||||||
|
const auto* end = in + sv.size();
|
||||||
|
std::array<char8_t, 4> u8arr{};
|
||||||
|
while (in < end) {
|
||||||
|
if (IsSjisLeadByte(*in)) {
|
||||||
|
char16_t sjis = static_cast<char16_t>(*in) << 8 | *(in + 1);
|
||||||
|
in += 2;
|
||||||
|
char32_t utf32 = OSSJISToUTF32(sjis);
|
||||||
|
if (utf32 == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
char8_t* u8out = u8arr.data();
|
||||||
|
char8_t* u8end = OSUTF32To8(utf32, u8out);
|
||||||
|
if (u8end == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto length = static_cast<size_t>(u8end - u8out);
|
||||||
|
out.append(std::string_view{reinterpret_cast<char*>(u8out), length});
|
||||||
|
} else {
|
||||||
|
out.push_back(static_cast<char>(*in++));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const std::string& str() const { return out; }
|
||||||
|
|
||||||
|
[[nodiscard]] std::string& str() { return out; }
|
||||||
|
|
||||||
|
[[nodiscard]] const char* c_str() const { return out.c_str(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class UTF8ToSJIS {
|
||||||
|
private:
|
||||||
|
std::string out;
|
||||||
|
|
||||||
|
public:
|
||||||
|
UTF8ToSJIS(std::string_view sv) {
|
||||||
|
const auto* in = reinterpret_cast<const char8_t*>(sv.data());
|
||||||
|
const auto* end = in + sv.size();
|
||||||
|
while (in < end) {
|
||||||
|
char32_t utf32 = 0;
|
||||||
|
const char8_t* next = OSUTF8To32(in, &utf32);
|
||||||
|
if (next == nullptr) {
|
||||||
|
utf32 = *in;
|
||||||
|
in++;
|
||||||
|
} else {
|
||||||
|
in = next;
|
||||||
|
}
|
||||||
|
char16_t sjis = OSUTF32ToSJIS(utf32);
|
||||||
|
char8_t lead = (sjis >> 8) & 0xFF;
|
||||||
|
if (IsSjisLeadByte(lead)) {
|
||||||
|
out.push_back(static_cast<char>(lead));
|
||||||
|
}
|
||||||
|
out.push_back(static_cast<char>(sjis & 0xFF));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const std::string& str() const { return out; }
|
||||||
|
|
||||||
|
[[nodiscard]] std::string& str() { return out; }
|
||||||
|
|
||||||
|
[[nodiscard]] const char* c_str() const { return out.c_str(); }
|
||||||
|
};
|
||||||
|
#endif
|
||||||
@@ -1,352 +0,0 @@
|
|||||||
#ifndef __NOD_UTIL_HPP__
|
|
||||||
#define __NOD_UTIL_HPP__
|
|
||||||
|
|
||||||
#if _WIN32 && UNICODE
|
|
||||||
#include <wctype.h>
|
|
||||||
#include <direct.h>
|
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
|
||||||
#define WIN32_LEAN_AND_MEAN 1
|
|
||||||
#endif
|
|
||||||
#ifndef NOMINMAX
|
|
||||||
#define NOMINMAX
|
|
||||||
#endif
|
|
||||||
#include <windows.h>
|
|
||||||
#else
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <sys/file.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/param.h>
|
|
||||||
#include <sys/statvfs.h>
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <cstring>
|
|
||||||
#include <algorithm>
|
|
||||||
#include "logvisor/logvisor.hpp"
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#pragma warning(disable : 4996)
|
|
||||||
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
|
|
||||||
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
|
|
||||||
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(S_ISLNK)
|
|
||||||
#define S_ISLNK(m) 0
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#undef min
|
|
||||||
#undef max
|
|
||||||
|
|
||||||
namespace nod
|
|
||||||
{
|
|
||||||
/* define our own min/max to avoid MSVC BS */
|
|
||||||
template<typename T>
|
|
||||||
inline T min(T a, T b) { return a < b ? a : b; }
|
|
||||||
template<typename T>
|
|
||||||
inline T max(T a, T b) { return a > b ? a : b; }
|
|
||||||
|
|
||||||
/* Log Module */
|
|
||||||
extern logvisor::Module LogModule;
|
|
||||||
|
|
||||||
/* filesystem char type */
|
|
||||||
#if _WIN32 && UNICODE
|
|
||||||
#define NOD_UCS2 1
|
|
||||||
typedef struct _stat Sstat;
|
|
||||||
static inline int Mkdir(const wchar_t* path, int) {return _wmkdir(path);}
|
|
||||||
static inline int Stat(const wchar_t* path, Sstat* statout) {return _wstat(path, statout);}
|
|
||||||
#else
|
|
||||||
typedef struct stat Sstat;
|
|
||||||
static inline int Mkdir(const char* path, mode_t mode) {return mkdir(path, mode);}
|
|
||||||
static inline int Stat(const char* path, Sstat* statout) {return stat(path, statout);}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* String-converting views */
|
|
||||||
#if NOD_UCS2
|
|
||||||
typedef wchar_t SystemChar;
|
|
||||||
typedef std::wstring SystemString;
|
|
||||||
static inline void ToLower(SystemString& str)
|
|
||||||
{std::transform(str.begin(), str.end(), str.begin(), towlower);}
|
|
||||||
static inline void ToUpper(SystemString& str)
|
|
||||||
{std::transform(str.begin(), str.end(), str.begin(), towupper);}
|
|
||||||
static inline size_t StrLen(const SystemChar* str) {return wcslen(str);}
|
|
||||||
class SystemUTF8View
|
|
||||||
{
|
|
||||||
std::string m_utf8;
|
|
||||||
public:
|
|
||||||
explicit SystemUTF8View(const SystemString& str)
|
|
||||||
{
|
|
||||||
int len = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), str.size(), nullptr, 0, nullptr, nullptr);
|
|
||||||
m_utf8.assign(len, '\0');
|
|
||||||
WideCharToMultiByte(CP_UTF8, 0, str.c_str(), str.size(), &m_utf8[0], len, nullptr, nullptr);
|
|
||||||
}
|
|
||||||
inline const std::string& utf8_str() {return m_utf8;}
|
|
||||||
};
|
|
||||||
class SystemStringView
|
|
||||||
{
|
|
||||||
std::wstring m_sys;
|
|
||||||
public:
|
|
||||||
explicit SystemStringView(const std::string& str)
|
|
||||||
{
|
|
||||||
int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.size(), nullptr, 0);
|
|
||||||
m_sys.assign(len, L'\0');
|
|
||||||
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.size(), &m_sys[0], len);
|
|
||||||
}
|
|
||||||
inline const std::wstring& sys_str() {return m_sys;}
|
|
||||||
};
|
|
||||||
#ifndef _S
|
|
||||||
#define _S(val) L ## val
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
typedef char SystemChar;
|
|
||||||
typedef std::string SystemString;
|
|
||||||
static inline void ToLower(SystemString& str)
|
|
||||||
{std::transform(str.begin(), str.end(), str.begin(), tolower);}
|
|
||||||
static inline void ToUpper(SystemString& str)
|
|
||||||
{std::transform(str.begin(), str.end(), str.begin(), toupper);}
|
|
||||||
static inline size_t StrLen(const SystemChar* str) {return strlen(str);}
|
|
||||||
class SystemUTF8View
|
|
||||||
{
|
|
||||||
const std::string& m_utf8;
|
|
||||||
public:
|
|
||||||
explicit SystemUTF8View(const SystemString& str)
|
|
||||||
: m_utf8(str) {}
|
|
||||||
inline const std::string& utf8_str() {return m_utf8;}
|
|
||||||
};
|
|
||||||
class SystemStringView
|
|
||||||
{
|
|
||||||
const std::string& m_sys;
|
|
||||||
public:
|
|
||||||
explicit SystemStringView(const std::string& str)
|
|
||||||
: m_sys(str) {}
|
|
||||||
inline const std::string& sys_str() {return m_sys;}
|
|
||||||
};
|
|
||||||
#ifndef _S
|
|
||||||
#define _S(val) val
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline void Unlink(const SystemChar* file)
|
|
||||||
{
|
|
||||||
#if NOD_UCS2
|
|
||||||
_wunlink(file);
|
|
||||||
#else
|
|
||||||
unlink(file);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int StrCmp(const SystemChar* str1, const SystemChar* str2)
|
|
||||||
{
|
|
||||||
#if NOD_UCS2
|
|
||||||
return wcscmp(str1, str2);
|
|
||||||
#else
|
|
||||||
return strcmp(str1, str2);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int StrCaseCmp(const SystemChar* str1, const SystemChar* str2)
|
|
||||||
{
|
|
||||||
#if NOD_UCS2
|
|
||||||
return _wcsicmp(str1, str2);
|
|
||||||
#else
|
|
||||||
return strcasecmp(str1, str2);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef bswap16
|
|
||||||
#undef bswap32
|
|
||||||
#undef bswap64
|
|
||||||
/* Type-sensitive byte swappers */
|
|
||||||
template <typename T>
|
|
||||||
static inline T bswap16(T val)
|
|
||||||
{
|
|
||||||
#if __GNUC__
|
|
||||||
return __builtin_bswap16(val);
|
|
||||||
#elif _WIN32
|
|
||||||
return _byteswap_ushort(val);
|
|
||||||
#else
|
|
||||||
return (val = (val << 8) | ((val >> 8) & 0xFF));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static inline T bswap32(T val)
|
|
||||||
{
|
|
||||||
#if __GNUC__
|
|
||||||
return __builtin_bswap32(val);
|
|
||||||
#elif _WIN32
|
|
||||||
return _byteswap_ulong(val);
|
|
||||||
#else
|
|
||||||
val = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16;
|
|
||||||
val = (val & 0x00FF00FF) << 8 | (val & 0xFF00FF00) >> 8;
|
|
||||||
return val;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static inline T bswap64(T val)
|
|
||||||
{
|
|
||||||
#if __GNUC__
|
|
||||||
return __builtin_bswap64(val);
|
|
||||||
#elif _WIN32
|
|
||||||
return _byteswap_uint64(val);
|
|
||||||
#else
|
|
||||||
return ((val & 0xFF00000000000000ULL) >> 56) |
|
|
||||||
((val & 0x00FF000000000000ULL) >> 40) |
|
|
||||||
((val & 0x0000FF0000000000ULL) >> 24) |
|
|
||||||
((val & 0x000000FF00000000ULL) >> 8) |
|
|
||||||
((val & 0x00000000FF000000ULL) << 8) |
|
|
||||||
((val & 0x0000000000FF0000ULL) << 24) |
|
|
||||||
((val & 0x000000000000FF00ULL) << 40) |
|
|
||||||
((val & 0x00000000000000FFULL) << 56);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
|
||||||
static inline int16_t SBig(int16_t val) {return bswap16(val);}
|
|
||||||
static inline uint16_t SBig(uint16_t val) {return bswap16(val);}
|
|
||||||
static inline int32_t SBig(int32_t val) {return bswap32(val);}
|
|
||||||
static inline uint32_t SBig(uint32_t val) {return bswap32(val);}
|
|
||||||
static inline int64_t SBig(int64_t val) {return bswap64(val);}
|
|
||||||
static inline uint64_t SBig(uint64_t val) {return bswap64(val);}
|
|
||||||
|
|
||||||
static inline int16_t SLittle(int16_t val) {return val;}
|
|
||||||
static inline uint16_t SLittle(uint16_t val) {return val;}
|
|
||||||
static inline int32_t SLittle(int32_t val) {return val;}
|
|
||||||
static inline uint32_t SLittle(uint32_t val) {return val;}
|
|
||||||
static inline int64_t SLittle(int64_t val) {return val;}
|
|
||||||
static inline uint64_t SLittle(uint64_t val) {return val;}
|
|
||||||
#else
|
|
||||||
static inline int16_t SLittle(int16_t val) {return bswap16(val);}
|
|
||||||
static inline uint16_t SLittle(uint16_t val) {return bswap16(val);}
|
|
||||||
static inline int32_t SLittle(int32_t val) {return bswap32(val);}
|
|
||||||
static inline uint32_t SLittle(uint32_t val) {return bswap32(val);}
|
|
||||||
static inline int64_t SLittle(int64_t val) {return bswap64(val);}
|
|
||||||
static inline uint64_t SLittle(uint64_t val) {return bswap64(val);}
|
|
||||||
|
|
||||||
static inline int16_t SBig(int16_t val) {return val;}
|
|
||||||
static inline uint16_t SBig(uint16_t val) {return val;}
|
|
||||||
static inline int32_t SBig(int32_t val) {return val;}
|
|
||||||
static inline uint32_t SBig(uint32_t val) {return val;}
|
|
||||||
static inline int64_t SBig(int64_t val) {return val;}
|
|
||||||
static inline uint64_t SBig(uint64_t val) {return val;}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ROUND_UP_32
|
|
||||||
#define ROUND_UP_32(val) (((val) + 31) & ~31)
|
|
||||||
#define ROUND_UP_16(val) (((val) + 15) & ~15)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum class FileLockType
|
|
||||||
{
|
|
||||||
None = 0,
|
|
||||||
Read,
|
|
||||||
Write
|
|
||||||
};
|
|
||||||
static inline FILE* Fopen(const SystemChar* path, const SystemChar* mode, FileLockType lock=FileLockType::None)
|
|
||||||
{
|
|
||||||
#if NOD_UCS2
|
|
||||||
FILE* fp = _wfopen(path, mode);
|
|
||||||
if (!fp)
|
|
||||||
return nullptr;
|
|
||||||
#else
|
|
||||||
FILE* fp = fopen(path, mode);
|
|
||||||
if (!fp)
|
|
||||||
return nullptr;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (lock != FileLockType::None)
|
|
||||||
{
|
|
||||||
#if _WIN32
|
|
||||||
OVERLAPPED ov = {};
|
|
||||||
LockFileEx((HANDLE)(uintptr_t)_fileno(fp), (lock == FileLockType::Write) ? LOCKFILE_EXCLUSIVE_LOCK : 0, 0, 0, 1, &ov);
|
|
||||||
#else
|
|
||||||
if (flock(fileno(fp), ((lock == FileLockType::Write) ? LOCK_EX : LOCK_SH) | LOCK_NB))
|
|
||||||
LogModule.report(logvisor::Error, "flock %s: %s", path, strerror(errno));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return fp;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int FSeek(FILE* fp, int64_t offset, int whence)
|
|
||||||
{
|
|
||||||
#if _WIN32
|
|
||||||
return _fseeki64(fp, offset, whence);
|
|
||||||
#elif __APPLE__ || __FreeBSD__
|
|
||||||
return fseeko(fp, offset, whence);
|
|
||||||
#else
|
|
||||||
return fseeko64(fp, offset, whence);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int64_t FTell(FILE* fp)
|
|
||||||
{
|
|
||||||
#if _WIN32
|
|
||||||
return _ftelli64(fp);
|
|
||||||
#elif __APPLE__ || __FreeBSD__
|
|
||||||
return ftello(fp);
|
|
||||||
#else
|
|
||||||
return ftello64(fp);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool CheckFreeSpace(const SystemChar* path, size_t reqSz)
|
|
||||||
{
|
|
||||||
#if _WIN32
|
|
||||||
ULARGE_INTEGER freeBytes;
|
|
||||||
wchar_t buf[1024];
|
|
||||||
wchar_t* end;
|
|
||||||
DWORD ret = GetFullPathNameW(path, 1024, buf, &end);
|
|
||||||
if (!ret || ret > 1024)
|
|
||||||
{
|
|
||||||
LogModule.report(logvisor::Error, _S("GetFullPathNameW %s"), path);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (end)
|
|
||||||
end[0] = L'\0';
|
|
||||||
if (!GetDiskFreeSpaceExW(buf, &freeBytes, nullptr, nullptr))
|
|
||||||
{
|
|
||||||
LogModule.report(logvisor::Error, _S("GetDiskFreeSpaceExW %s: %d"), path, GetLastError());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return reqSz < freeBytes.QuadPart;
|
|
||||||
#else
|
|
||||||
struct statvfs svfs;
|
|
||||||
if (statvfs(path, &svfs))
|
|
||||||
{
|
|
||||||
LogModule.report(logvisor::Error, "statvfs %s: %s", path, strerror(errno));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return reqSz < svfs.f_frsize * svfs.f_bavail;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if __GNUC__
|
|
||||||
__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__
|
|
||||||
@@ -1,24 +1,19 @@
|
|||||||
#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;
|
||||||
virtual void decrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len)=0;
|
virtual void decrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len) = 0;
|
||||||
virtual void setKey(const uint8_t* key)=0;
|
virtual void setKey(const uint8_t* key) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<IAES> NewAES();
|
std::unique_ptr<IAES> NewAES();
|
||||||
|
|
||||||
}
|
} // namespace nod
|
||||||
|
|
||||||
#endif //__AES_HPP__
|
|
||||||
|
|||||||
@@ -1,29 +1,19 @@
|
|||||||
#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_view>
|
||||||
|
|
||||||
namespace nod
|
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(std::string_view path);
|
||||||
std::unique_ptr<DiscBase> OpenDiscFromImage(const SystemChar* path, bool& isWii);
|
std::unique_ptr<DiscBase> OpenDiscFromImage(std::string_view path, bool& isWii);
|
||||||
|
|
||||||
}
|
} // namespace nod
|
||||||
|
|
||||||
#include "DiscGCN.hpp"
|
|
||||||
#include "DiscWii.hpp"
|
|
||||||
#include "IDiscIO.hpp"
|
|
||||||
|
|
||||||
#endif // __NOD_LIB__
|
|
||||||
|
|||||||
@@ -1,21 +1,57 @@
|
|||||||
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
|
IFileIO.cpp
|
||||||
nod.cpp
|
nod.cpp
|
||||||
${PLAT_SRCS}
|
OSUTF.c
|
||||||
${NOD_HEADERS})
|
Util.cpp
|
||||||
if(NOT MSVC)
|
Util.hpp
|
||||||
set_source_files_properties(aes.cpp PROPERTIES COMPILE_FLAGS -maes)
|
|
||||||
|
../include/nod/aes.hpp
|
||||||
|
../include/nod/DirectoryEnumerator.hpp
|
||||||
|
../include/nod/DiscBase.hpp
|
||||||
|
../include/nod/DiscGCN.hpp
|
||||||
|
../include/nod/DiscWii.hpp
|
||||||
|
../include/nod/Endian.hpp
|
||||||
|
../include/nod/IDiscIO.hpp
|
||||||
|
../include/nod/IFileIO.hpp
|
||||||
|
../include/nod/nod.hpp
|
||||||
|
../include/nod/OSUTF.h
|
||||||
|
../include/nod/sha1.h
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(nod PUBLIC
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(nod PUBLIC $<BUILD_INTERFACE:spdlog::spdlog>)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
target_sources(nod PRIVATE FileIOWin32.cpp)
|
||||||
|
target_link_libraries(nod PRIVATE nowide::nowide)
|
||||||
|
else()
|
||||||
|
target_compile_options(nod PRIVATE -Wno-multichar)
|
||||||
|
target_sources(nod PRIVATE FileIOFILE.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(NOT MSVC AND ${CMAKE_SYSTEM_PROCESSOR} STREQUAL x86_64)
|
||||||
|
set_source_files_properties(aes.cpp PROPERTIES COMPILE_FLAGS -maes)
|
||||||
|
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)
|
||||||
|
|||||||
@@ -1,147 +1,168 @@
|
|||||||
|
#include "nod/DirectoryEnumerator.hpp"
|
||||||
|
#include "Util.hpp"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#else
|
#else
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "nod/DirectoryEnumerator.hpp"
|
namespace nod {
|
||||||
|
|
||||||
namespace nod
|
DirectoryEnumerator::DirectoryEnumerator(std::string_view 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);
|
std::wstring wc = nowide::widen(path);
|
||||||
wc += _S("/*");
|
wc += L"/*";
|
||||||
WIN32_FIND_DATAW d;
|
WIN32_FIND_DATAW d;
|
||||||
HANDLE dir = FindFirstFileW(wc.c_str(), &d);
|
HANDLE dir = FindFirstFileW(wc.c_str(), &d);
|
||||||
if (dir == INVALID_HANDLE_VALUE)
|
if (dir == INVALID_HANDLE_VALUE) {
|
||||||
return;
|
return;
|
||||||
switch (mode)
|
}
|
||||||
{
|
switch (mode) {
|
||||||
case Mode::Native:
|
case Mode::Native:
|
||||||
do
|
do {
|
||||||
{
|
if (!wcscmp(d.cFileName, L".") || !wcscmp(d.cFileName, L"..")) {
|
||||||
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);
|
}
|
||||||
fp += _S('/');
|
std::string fileName = nowide::narrow(d.cFileName);
|
||||||
fp += d.cFileName;
|
std::string fp(path);
|
||||||
|
fp += '/';
|
||||||
|
fp += fileName;
|
||||||
Sstat st;
|
Sstat st;
|
||||||
if (Stat(fp.c_str(), &st))
|
if (Stat(fp.c_str(), &st))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
size_t sz = 0;
|
size_t sz = 0;
|
||||||
bool isDir = false;
|
bool isDir = false;
|
||||||
if (S_ISDIR(st.st_mode))
|
if (S_ISDIR(st.st_mode)) {
|
||||||
isDir = true;
|
isDir = true;
|
||||||
else if (S_ISREG(st.st_mode))
|
} else if (S_ISREG(st.st_mode)) {
|
||||||
sz = st.st_size;
|
sz = st.st_size;
|
||||||
else
|
} else {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
m_entries.push_back(std::move(Entry(std::move(fp), d.cFileName, sz, isDir)));
|
m_entries.emplace_back(fp, fileName, sz, isDir);
|
||||||
} while (FindNextFileW(dir, &d));
|
} while (FindNextFileW(dir, &d));
|
||||||
break;
|
break;
|
||||||
case Mode::DirsThenFilesSorted:
|
case Mode::DirsThenFilesSorted:
|
||||||
case Mode::DirsSorted:
|
case Mode::DirsSorted: {
|
||||||
{
|
std::map<std::string, Entry, CaseInsensitiveCompare> sort;
|
||||||
std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
|
do {
|
||||||
do
|
if (!wcscmp(d.cFileName, L".") || !wcscmp(d.cFileName, L"..")) {
|
||||||
{
|
|
||||||
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);
|
}
|
||||||
fp +=_S('/');
|
std::string fileName = nowide::narrow(d.cFileName);
|
||||||
fp += d.cFileName;
|
std::string fp(path);
|
||||||
|
fp += '/';
|
||||||
|
fp += fileName;
|
||||||
Sstat st;
|
Sstat st;
|
||||||
if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode))
|
if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode)) {
|
||||||
continue;
|
continue;
|
||||||
sort.emplace(std::make_pair(d.cFileName, Entry(std::move(fp), d.cFileName, 0, true)));
|
}
|
||||||
|
sort.emplace(fileName, Entry{fp, fileName, 0, true});
|
||||||
} while (FindNextFileW(dir, &d));
|
} while (FindNextFileW(dir, &d));
|
||||||
|
|
||||||
m_entries.reserve(sort.size());
|
m_entries.reserve(sort.size());
|
||||||
if (reverse)
|
if (reverse) {
|
||||||
for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
|
for (auto it = sort.crbegin(); it != sort.crend(); ++it) {
|
||||||
m_entries.push_back(std::move(it->second));
|
m_entries.emplace_back(std::move(it->second));
|
||||||
else
|
}
|
||||||
for (auto& e : sort)
|
} else {
|
||||||
m_entries.push_back(std::move(e.second));
|
for (auto& e : sort) {
|
||||||
|
m_entries.emplace_back(std::move(e.second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mode == Mode::DirsSorted)
|
if (mode == Mode::DirsSorted) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
FindClose(dir);
|
FindClose(dir);
|
||||||
dir = FindFirstFileW(wc.c_str(), &d);
|
dir = FindFirstFileW(wc.c_str(), &d);
|
||||||
}
|
}
|
||||||
case Mode::FilesSorted:
|
case Mode::FilesSorted: {
|
||||||
{
|
if (mode == Mode::FilesSorted) {
|
||||||
if (mode == Mode::FilesSorted)
|
|
||||||
m_entries.clear();
|
m_entries.clear();
|
||||||
|
|
||||||
if (sizeSort)
|
|
||||||
{
|
|
||||||
std::multimap<size_t, Entry> sort;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (!wcscmp(d.cFileName, _S(".")) || !wcscmp(d.cFileName, _S("..")))
|
|
||||||
continue;
|
|
||||||
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
|
|
||||||
continue;
|
|
||||||
SystemString fp(path);
|
|
||||||
fp += _S('/');
|
|
||||||
fp += d.cFileName;
|
|
||||||
Sstat st;
|
|
||||||
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
|
|
||||||
continue;
|
|
||||||
sort.emplace(std::make_pair(st.st_size, Entry(std::move(fp), d.cFileName, st.st_size, false)));
|
|
||||||
} while (FindNextFileW(dir, &d));
|
|
||||||
|
|
||||||
m_entries.reserve(sort.size());
|
|
||||||
if (reverse)
|
|
||||||
for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
|
|
||||||
m_entries.push_back(std::move(it->second));
|
|
||||||
else
|
|
||||||
for (auto& e : sort)
|
|
||||||
m_entries.push_back(std::move(e.second));
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
if (sizeSort) {
|
||||||
std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
|
std::multimap<size_t, Entry> sort;
|
||||||
do
|
do {
|
||||||
{
|
if (!wcscmp(d.cFileName, L".") || !wcscmp(d.cFileName, L"..")) {
|
||||||
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);
|
}
|
||||||
fp += _S('/');
|
std::string fileName = nowide::narrow(d.cFileName);
|
||||||
fp += d.cFileName;
|
std::string fp(path);
|
||||||
|
fp += '/';
|
||||||
|
fp += fileName;
|
||||||
Sstat st;
|
Sstat st;
|
||||||
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
|
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode)) {
|
||||||
continue;
|
continue;
|
||||||
sort.emplace(std::make_pair(d.cFileName, Entry(std::move(fp), d.cFileName, st.st_size, false)));
|
}
|
||||||
|
sort.emplace(st.st_size, Entry{fp, fileName, static_cast<size_t>(st.st_size), false});
|
||||||
} while (FindNextFileW(dir, &d));
|
} while (FindNextFileW(dir, &d));
|
||||||
|
|
||||||
m_entries.reserve(sort.size());
|
m_entries.reserve(m_entries.size() + sort.size());
|
||||||
if (reverse)
|
if (reverse) {
|
||||||
for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
|
for (auto it = sort.crbegin(); it != sort.crend(); ++it) {
|
||||||
m_entries.push_back(std::move(it->second));
|
m_entries.emplace_back(std::move(it->second));
|
||||||
else
|
}
|
||||||
for (auto& e : sort)
|
} else {
|
||||||
m_entries.push_back(std::move(e.second));
|
for (auto& e : sort) {
|
||||||
|
m_entries.emplace_back(std::move(e.second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::map<std::string, Entry, CaseInsensitiveCompare> sort;
|
||||||
|
do {
|
||||||
|
if (!wcscmp(d.cFileName, L".") || !wcscmp(d.cFileName, L"..")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::string fileName = nowide::narrow(d.cFileName);
|
||||||
|
std::string fp(path);
|
||||||
|
fp += '/';
|
||||||
|
fp += fileName;
|
||||||
|
Sstat st;
|
||||||
|
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sort.emplace(fileName, Entry{fp, fileName, static_cast<size_t>(st.st_size), false});
|
||||||
|
} while (FindNextFileW(dir, &d));
|
||||||
|
|
||||||
|
m_entries.reserve(m_entries.size() + sort.size());
|
||||||
|
if (reverse) {
|
||||||
|
for (auto it = sort.crbegin(); it != sort.crend(); ++it) {
|
||||||
|
m_entries.emplace_back(std::move(it->second));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (auto& e : sort) {
|
||||||
|
m_entries.emplace_back(std::move(e.second));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -151,20 +172,18 @@ 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] == '.')
|
||||||
continue;
|
continue;
|
||||||
SystemString fp(path);
|
std::string fp(path);
|
||||||
fp += '/';
|
fp += '/';
|
||||||
fp += d->d_name;
|
fp += d->d_name;
|
||||||
Sstat st;
|
Sstat st;
|
||||||
@@ -180,31 +199,29 @@ 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<std::string, 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] == '.')
|
||||||
continue;
|
continue;
|
||||||
SystemString fp(path);
|
std::string fp(path);
|
||||||
fp += '/';
|
fp += '/';
|
||||||
fp += d->d_name;
|
fp += d->d_name;
|
||||||
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());
|
||||||
if (reverse)
|
if (reverse)
|
||||||
for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
|
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
|
||||||
m_entries.push_back(std::move(it->second));
|
m_entries.push_back(std::move(it->second));
|
||||||
else
|
else
|
||||||
for (auto& e : sort)
|
for (auto& e : sort)
|
||||||
@@ -213,59 +230,54 @@ 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] == '.')
|
||||||
continue;
|
continue;
|
||||||
SystemString fp(path);
|
std::string fp(path);
|
||||||
fp += '/';
|
fp += '/';
|
||||||
fp += d->d_name;
|
fp += d->d_name;
|
||||||
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());
|
||||||
if (reverse)
|
if (reverse)
|
||||||
for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
|
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
|
||||||
m_entries.push_back(std::move(it->second));
|
m_entries.push_back(std::move(it->second));
|
||||||
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<std::string, Entry, CaseInsensitiveCompare> sort;
|
||||||
{
|
while ((d = readdir(dir))) {
|
||||||
std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
|
|
||||||
while ((d = readdir(dir)))
|
|
||||||
{
|
|
||||||
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
|
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
|
||||||
continue;
|
continue;
|
||||||
if (noHidden && d->d_name[0] == '.')
|
if (noHidden && d->d_name[0] == '.')
|
||||||
continue;
|
continue;
|
||||||
SystemString fp(path);
|
std::string fp(path);
|
||||||
fp += '/';
|
fp += '/';
|
||||||
fp += d->d_name;
|
fp += d->d_name;
|
||||||
Sstat st;
|
Sstat st;
|
||||||
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());
|
||||||
if (reverse)
|
if (reverse)
|
||||||
for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
|
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
|
||||||
m_entries.push_back(std::move(it->second));
|
m_entries.push_back(std::move(it->second));
|
||||||
else
|
else
|
||||||
for (auto& e : sort)
|
for (auto& e : sort)
|
||||||
@@ -280,4 +292,4 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace nod
|
||||||
|
|||||||
767
lib/DiscBase.cpp
767
lib/DiscBase.cpp
File diff suppressed because it is too large
Load Diff
309
lib/DiscGCN.cpp
309
lib/DiscGCN.cpp
@@ -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 "Util.hpp"
|
||||||
|
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
#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(std::string_view outPath, FProgress progressCB) {
|
||||||
{
|
|
||||||
return DiscBuilderGCN(outPath, progressCB);
|
return DiscBuilderGCN(outPath, progressCB);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DiscGCN::extractDiscHeaderFiles(const SystemString& path, const ExtractionContext& ctx) const
|
bool DiscGCN::extractDiscHeaderFiles(std::string_view 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) {
|
||||||
{
|
spdlog::error("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;
|
||||||
@@ -217,19 +201,17 @@ public:
|
|||||||
|
|
||||||
size_t fstOff = ROUND_UP_32(xferSz);
|
size_t fstOff = ROUND_UP_32(xferSz);
|
||||||
size_t fstSz = sizeof(FSTNode) * m_buildNodes.size();
|
size_t fstSz = sizeof(FSTNode) * m_buildNodes.size();
|
||||||
for (size_t i=0 ; i<fstOff-xferSz ; ++i)
|
for (size_t i = 0; i < fstOff - xferSz; ++i)
|
||||||
ws->write("\xff", 1);
|
ws->write("\xff", 1);
|
||||||
fstOff += 0x2440;
|
fstOff += 0x2440;
|
||||||
ws->write(m_buildNodes.data(), fstSz);
|
ws->write(m_buildNodes.data(), fstSz);
|
||||||
for (const std::string& str : m_buildNames)
|
for (const std::string& str : m_buildNames)
|
||||||
ws->write(str.data(), str.size()+1);
|
ws->write(str.data(), str.size() + 1);
|
||||||
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) {
|
||||||
{
|
spdlog::error("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(std::string_view dirIn) {
|
||||||
{
|
|
||||||
std::unique_ptr<IPartWriteStream> ws = beginWriteStream(0);
|
std::unique_ptr<IPartWriteStream> ws = beginWriteStream(0);
|
||||||
if (!ws)
|
if (!ws)
|
||||||
return false;
|
return false;
|
||||||
@@ -253,39 +234,35 @@ public:
|
|||||||
if (!result)
|
if (!result)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
SystemString dirStr(dirIn);
|
std::string dirStr(dirIn);
|
||||||
|
|
||||||
/* Check Apploader */
|
/* Check Apploader */
|
||||||
SystemString apploaderIn = dirStr + _S("/sys/apploader.img");
|
std::string apploaderIn = dirStr + "/sys/apploader.img";
|
||||||
Sstat apploaderStat;
|
Sstat apploaderStat;
|
||||||
if (Stat(apploaderIn.c_str(), &apploaderStat))
|
if (Stat(apploaderIn.c_str(), &apploaderStat)) {
|
||||||
{
|
spdlog::error("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");
|
std::string bootIn = dirStr + "/sys/boot.bin";
|
||||||
Sstat bootStat;
|
Sstat bootStat;
|
||||||
if (Stat(bootIn.c_str(), &bootStat))
|
if (Stat(bootIn.c_str(), &bootStat)) {
|
||||||
{
|
spdlog::error("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");
|
std::string bi2In = dirStr + "/sys/bi2.bin";
|
||||||
Sstat bi2Stat;
|
Sstat bi2Stat;
|
||||||
if (Stat(bi2In.c_str(), &bi2Stat))
|
if (Stat(bi2In.c_str(), &bi2Stat)) {
|
||||||
{
|
spdlog::error("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) {
|
||||||
{
|
spdlog::error("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, std::string_view dirIn) {
|
||||||
{
|
|
||||||
std::unique_ptr<IPartWriteStream> ws = beginWriteStream(0);
|
std::unique_ptr<IPartWriteStream> ws = beginWriteStream(0);
|
||||||
if (!ws)
|
if (!ws)
|
||||||
return false;
|
return false;
|
||||||
@@ -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>"));
|
std::string apploaderName("<apploader>");
|
||||||
ws.write(apploaderBuf.get(), apploaderSz);
|
ws.write(apploaderBuf.get(), apploaderSz);
|
||||||
xferSz += apploaderSz;
|
xferSz += apploaderSz;
|
||||||
if (0x2440 + xferSz >= m_curUser)
|
if (0x2440 + xferSz >= m_curUser) {
|
||||||
{
|
spdlog::error("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,84 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
EBuildResult DiscBuilderGCN::buildFromDirectory(const SystemChar* dirIn)
|
EBuildResult DiscBuilderGCN::buildFromDirectory(std::string_view dirIn) {
|
||||||
{
|
|
||||||
if (!m_fileIO->beginWriteStream())
|
if (!m_fileIO->beginWriteStream())
|
||||||
return EBuildResult::Failed;
|
return EBuildResult::Failed;
|
||||||
if (!CheckFreeSpace(m_outPath.c_str(), 0x57058000))
|
if (!CheckFreeSpace(m_outPath.c_str(), 0x57058000)) {
|
||||||
{
|
spdlog::error("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(), "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(std::string_view dirIn) {
|
||||||
{
|
std::optional<uint64_t> sz =
|
||||||
uint64_t sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeBuild(dirIn, PartitionKind::Data, false);
|
DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeBuild(dirIn, PartitionKind::Data, false);
|
||||||
if (sz == -1)
|
if (!sz)
|
||||||
return -1;
|
return sz;
|
||||||
sz += 0x30000;
|
*sz += 0x30000;
|
||||||
if (sz > 0x57058000)
|
if (sz > 0x57058000) {
|
||||||
{
|
spdlog::error("disc capacity exceeded [{} / {}]", *sz, 0x57058000);
|
||||||
LogModule.report(logvisor::Error, _S("disc capacity exceeded [%" PRIu64 " / %" PRIu64 "]"), sz, 0x57058000);
|
return std::nullopt;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
return sz;
|
return sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscBuilderGCN::DiscBuilderGCN(const SystemChar* outPath, FProgress progressCB)
|
DiscBuilderGCN::DiscBuilderGCN(std::string_view outPath, FProgress progressCB)
|
||||||
: DiscBuilderBase(outPath, 0x57058000, progressCB)
|
: DiscBuilderBase(outPath, 0x57058000, progressCB) {
|
||||||
{
|
m_partitions.emplace_back(std::make_unique<PartitionBuilderGCN>(*this));
|
||||||
PartitionBuilderGCN* partBuilder = new PartitionBuilderGCN(*this);
|
|
||||||
m_partitions.emplace_back(partBuilder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscMergerGCN::DiscMergerGCN(const SystemChar* outPath, DiscGCN& sourceDisc, FProgress progressCB)
|
DiscMergerGCN::DiscMergerGCN(std::string_view 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(std::string_view dirIn) {
|
||||||
{
|
|
||||||
if (!m_builder.getFileIO().beginWriteStream())
|
if (!m_builder.getFileIO().beginWriteStream())
|
||||||
return EBuildResult::Failed;
|
return EBuildResult::Failed;
|
||||||
if (!CheckFreeSpace(m_builder.m_outPath.c_str(), 0x57058000))
|
if (!CheckFreeSpace(m_builder.m_outPath.c_str(), 0x57058000)) {
|
||||||
{
|
spdlog::error("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(), "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)
|
||||||
|
ws->write(zeroBytes, 1024);
|
||||||
|
}
|
||||||
|
|
||||||
PartitionBuilderGCN& pb = static_cast<PartitionBuilderGCN&>(*m_builder.m_partitions[0]);
|
PartitionBuilderGCN& pb = static_cast<PartitionBuilderGCN&>(*m_builder.m_partitions[0]);
|
||||||
return pb.mergeFromDirectory(static_cast<PartitionGCN*>(m_sourceDisc.getDataPartition()), dirIn) ?
|
return pb.mergeFromDirectory(static_cast<PartitionGCN*>(m_sourceDisc.getDataPartition()), dirIn)
|
||||||
EBuildResult::Success : EBuildResult::Failed;
|
? EBuildResult::Success
|
||||||
|
: EBuildResult::Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t DiscMergerGCN::CalculateTotalSizeRequired(DiscGCN& sourceDisc, const SystemChar* dirIn)
|
std::optional<uint64_t> DiscMergerGCN::CalculateTotalSizeRequired(DiscGCN& sourceDisc, std::string_view dirIn) {
|
||||||
{
|
std::optional<uint64_t> sz =
|
||||||
uint64_t sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeMerge(
|
DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeMerge(sourceDisc.getDataPartition(), dirIn);
|
||||||
sourceDisc.getDataPartition(), dirIn);
|
if (!sz)
|
||||||
if (sz == -1)
|
return std::nullopt;
|
||||||
return -1;
|
*sz += 0x30000;
|
||||||
sz += 0x30000;
|
if (sz > 0x57058000) {
|
||||||
if (sz > 0x57058000)
|
spdlog::error("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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace nod
|
||||||
|
|||||||
@@ -1,69 +1,63 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include "nod/Util.hpp"
|
|
||||||
#include "nod/IDiscIO.hpp"
|
#include "nod/IDiscIO.hpp"
|
||||||
#include "nod/IFileIO.hpp"
|
#include "nod/IFileIO.hpp"
|
||||||
|
|
||||||
namespace nod
|
#include "Util.hpp"
|
||||||
{
|
|
||||||
|
|
||||||
class DiscIOISO : public IDiscIO
|
namespace nod {
|
||||||
{
|
|
||||||
|
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(std::string_view 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(std::string_view path) { return std::make_unique<DiscIOISO>(path); }
|
||||||
{
|
|
||||||
return std::unique_ptr<IDiscIO>(new DiscIOISO(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
} // namespace nod
|
||||||
|
|||||||
272
lib/DiscIONFS.cpp
Normal file
272
lib/DiscIONFS.cpp
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
#include "nod/IDiscIO.hpp"
|
||||||
|
#include "nod/IFileIO.hpp"
|
||||||
|
#include "nod/aes.hpp"
|
||||||
|
#include "nod/Endian.hpp"
|
||||||
|
#include "Util.hpp"
|
||||||
|
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
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(std::string_view fpin, bool& err) {
|
||||||
|
/* Validate file path format */
|
||||||
|
using SignedSize = std::make_signed<std::string::size_type>::type;
|
||||||
|
const auto dotPos = SignedSize(fpin.rfind('.'));
|
||||||
|
const auto slashPos = SignedSize(fpin.find_last_of("/\\"));
|
||||||
|
if (fpin.size() <= 4 || dotPos == -1 || dotPos <= slashPos || fpin.compare(slashPos + 1, 4, "hif_") ||
|
||||||
|
fpin.compare(dotPos, fpin.size() - dotPos, ".nfs")) {
|
||||||
|
spdlog::error("'{}' must begin with 'hif_' and end with '.nfs' to be accepted as an NFS image", fpin);
|
||||||
|
err = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load key file */
|
||||||
|
const std::string dir(fpin.begin(), fpin.begin() + slashPos + 1);
|
||||||
|
auto keyFile = NewFileIO(dir + "../code/htk.bin")->beginReadStream();
|
||||||
|
if (!keyFile)
|
||||||
|
keyFile = NewFileIO(dir + "htk.bin")->beginReadStream();
|
||||||
|
if (!keyFile) {
|
||||||
|
spdlog::error("Unable to open '{}../code/htk.bin' or '{}htk.bin'", dir, dir);
|
||||||
|
err = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (keyFile->read(key, 16) != 16) {
|
||||||
|
spdlog::error("Unable to read from '{}../code/htk.bin' or '{}htk.bin'", dir, dir);
|
||||||
|
err = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load header from first file */
|
||||||
|
const std::string firstPath = fmt::format("{}hif_{:06}.nfs", dir, 0);
|
||||||
|
files.push_back(NewFileIO(firstPath));
|
||||||
|
auto rs = files.back()->beginReadStream();
|
||||||
|
if (!rs) {
|
||||||
|
spdlog::error("'{}' does not exist", firstPath);
|
||||||
|
err = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (rs->read(&nfsHead, 0x200) != 0x200) {
|
||||||
|
spdlog::error("Unable to read header from '{}'", firstPath);
|
||||||
|
err = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (std::memcmp(&nfsHead.magic, "EGGS", 4)) {
|
||||||
|
spdlog::error("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) {
|
||||||
|
std::string path = fmt::format("{}hif_{:06}.nfs", dir, i);
|
||||||
|
files.push_back(NewFileIO(path));
|
||||||
|
if (!files.back()->exists()) {
|
||||||
|
spdlog::error("'{}' 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()) {
|
||||||
|
spdlog::error("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(std::string_view path) {
|
||||||
|
bool err = false;
|
||||||
|
auto ret = std::make_unique<DiscIONFS>(path, err);
|
||||||
|
if (err)
|
||||||
|
return {};
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace nod
|
||||||
@@ -1,31 +1,32 @@
|
|||||||
#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/Endian.hpp"
|
||||||
|
#include "Util.hpp"
|
||||||
|
|
||||||
namespace nod
|
#include <spdlog/spdlog.h>
|
||||||
{
|
|
||||||
|
|
||||||
#define ALIGN_LBA(x) (((x)+p->hd_sec_sz-1)&(~(p->hd_sec_sz-1)))
|
namespace nod {
|
||||||
|
|
||||||
static uint8_t size_to_shift(uint32_t size)
|
#define ALIGN_LBA(x) (((x) + p->hd_sec_sz - 1) & (~(p->hd_sec_sz - 1)))
|
||||||
{
|
|
||||||
|
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 +37,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
|
||||||
@@ -66,40 +65,35 @@ class DiscIOWBFS : public IDiscIO
|
|||||||
|
|
||||||
uint16_t max_disc;
|
uint16_t max_disc;
|
||||||
uint32_t freeblks_lba;
|
uint32_t freeblks_lba;
|
||||||
uint32_t *freeblks;
|
uint32_t* freeblks;
|
||||||
uint16_t disc_info_sz;
|
uint16_t disc_info_sz;
|
||||||
|
|
||||||
uint32_t n_disc_open;
|
uint32_t n_disc_open;
|
||||||
|
|
||||||
} 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) {
|
||||||
{
|
spdlog::error("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(std::string_view 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");
|
spdlog::error("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,65 +103,63 @@ 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");
|
spdlog::error("unable to read WBFS head");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//constants, but put here for consistancy
|
// constants, but put here for consistancy
|
||||||
p->wii_sec_sz = 0x8000;
|
p->wii_sec_sz = 0x8000;
|
||||||
p->wii_sec_sz_s = size_to_shift(0x8000);
|
p->wii_sec_sz_s = size_to_shift(0x8000);
|
||||||
p->n_wii_sec = (num_hd_sector/0x8000)*hd_sector_size;
|
p->n_wii_sec = (num_hd_sector / 0x8000) * hd_sector_size;
|
||||||
p->n_wii_sec_per_disc = 143432*2;//support for double layers discs..
|
p->n_wii_sec_per_disc = 143432 * 2; // support for double layers discs..
|
||||||
p->part_lba = 0;
|
p->part_lba = 0;
|
||||||
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");
|
spdlog::error("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");
|
spdlog::error("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;
|
||||||
p->hd_sec_sz_s = head->hd_sec_sz_s;
|
p->hd_sec_sz_s = head->hd_sec_sz_s;
|
||||||
p->n_hd_sec = SBig(head->n_hd_sec);
|
p->n_hd_sec = SBig(head->n_hd_sec);
|
||||||
|
|
||||||
p->n_wii_sec = (p->n_hd_sec/p->wii_sec_sz)*(p->hd_sec_sz);
|
p->n_wii_sec = (p->n_hd_sec / p->wii_sec_sz) * (p->hd_sec_sz);
|
||||||
|
|
||||||
p->wbfs_sec_sz_s = head->wbfs_sec_sz_s;
|
p->wbfs_sec_sz_s = head->wbfs_sec_sz_s;
|
||||||
p->wbfs_sec_sz = 1<<p->wbfs_sec_sz_s;
|
p->wbfs_sec_sz = 1 << p->wbfs_sec_sz_s;
|
||||||
p->n_wbfs_sec = p->n_wii_sec >> (p->wbfs_sec_sz_s - p->wii_sec_sz_s);
|
p->n_wbfs_sec = p->n_wii_sec >> (p->wbfs_sec_sz_s - p->wii_sec_sz_s);
|
||||||
p->n_wbfs_sec_per_disc = p->n_wii_sec_per_disc >> (p->wbfs_sec_sz_s - p->wii_sec_sz_s);
|
p->n_wbfs_sec_per_disc = p->n_wii_sec_per_disc >> (p->wbfs_sec_sz_s - p->wii_sec_sz_s);
|
||||||
p->disc_info_sz = ALIGN_LBA(uint16_t(sizeof(WBFSDiscInfo)) + p->n_wbfs_sec_per_disc*2);
|
p->disc_info_sz = ALIGN_LBA(uint16_t(sizeof(WBFSDiscInfo)) + p->n_wbfs_sec_per_disc * 2);
|
||||||
|
|
||||||
p->freeblks_lba = (p->wbfs_sec_sz - p->n_wbfs_sec/8)>>p->hd_sec_sz_s;
|
p->freeblks_lba = (p->wbfs_sec_sz - p->n_wbfs_sec / 8) >> p->hd_sec_sz_s;
|
||||||
|
|
||||||
p->freeblks = 0; // will alloc and read only if needed
|
p->freeblks = 0; // will alloc and read only if needed
|
||||||
p->max_disc = (p->freeblks_lba-1)/(p->disc_info_sz>>p->hd_sec_sz_s);
|
p->max_disc = (p->freeblks_lba - 1) / (p->disc_info_sz >> p->hd_sec_sz_s);
|
||||||
if(p->max_disc > p->hd_sec_sz - sizeof(WBFSHead))
|
if (p->max_disc > p->hd_sec_sz - sizeof(WBFSHead))
|
||||||
p->max_disc = p->hd_sec_sz - sizeof(WBFSHead);
|
p->max_disc = p->hd_sec_sz - sizeof(WBFSHead);
|
||||||
|
|
||||||
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");
|
spdlog::error("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()))
|
||||||
return;
|
return;
|
||||||
p->n_disc_open++;
|
p->n_disc_open++;
|
||||||
//for(i=0;i<p->n_wbfs_sec_per_disc;i++)
|
// for(i=0;i<p->n_wbfs_sec_per_disc;i++)
|
||||||
// printf("%d,",wbfs_ntohs(d->header->wlba_table[i]));
|
// printf("%d,",wbfs_ntohs(d->header->wlba_table[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,33 +167,32 @@ 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);
|
||||||
uint32_t iwlba_shift = p->wbfs_sec_sz_s - p->hd_sec_sz_s;
|
uint32_t iwlba_shift = p->wbfs_sec_sz_s - p->hd_sec_sz_s;
|
||||||
uint32_t lba_mask = (p->wbfs_sec_sz-1)>>(p->hd_sec_sz_s);
|
uint32_t lba_mask = (p->wbfs_sec_sz - 1) >> (p->hd_sec_sz_s);
|
||||||
uint64_t lba = (offset>>(p->hd_sec_sz_s-2))&lba_mask;
|
uint64_t lba = (offset >> (p->hd_sec_sz_s - 2)) & lba_mask;
|
||||||
uint64_t off = offset&((p->hd_sec_sz>>2)-1);
|
uint64_t off = offset & ((p->hd_sec_sz >> 2) - 1);
|
||||||
uint16_t iwlba = SBig(d->wlba_table[wlba]);
|
uint16_t iwlba = SBig(d->wlba_table[wlba]);
|
||||||
uint64_t len_copied;
|
uint64_t len_copied;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
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)
|
||||||
return err;
|
return err;
|
||||||
len_copied = p->hd_sec_sz - off;
|
len_copied = p->hd_sec_sz - off;
|
||||||
@@ -211,37 +202,33 @@ 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;
|
|
||||||
iwlba = SBig(d->wlba_table[++wlba]);
|
|
||||||
if (!iwlba)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (len>=p->hd_sec_sz)
|
|
||||||
{
|
|
||||||
uint32_t nlb = len>>(p->hd_sec_sz_s);
|
|
||||||
|
|
||||||
if (lba + nlb > p->wbfs_sec_sz) // dont cross wbfs sectors..
|
|
||||||
nlb = p->wbfs_sec_sz-lba;
|
|
||||||
err = wbfsReadSector(p->part_lba + (iwlba<<iwlba_shift) + lba, nlb, ptr);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
len -= nlb<<p->hd_sec_sz_s;
|
|
||||||
ptr += nlb<<p->hd_sec_sz_s;
|
|
||||||
lba += nlb;
|
|
||||||
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)
|
while (len >= p->hd_sec_sz) {
|
||||||
{
|
uint32_t nlb = len >> (p->hd_sec_sz_s);
|
||||||
err = wbfsReadSector(p->part_lba + (iwlba<<iwlba_shift) + lba, 1, m_tmpBuffer.get());
|
|
||||||
|
if (lba + nlb > p->wbfs_sec_sz) // dont cross wbfs sectors..
|
||||||
|
nlb = p->wbfs_sec_sz - lba;
|
||||||
|
err = wbfsReadSector(p->part_lba + (iwlba << iwlba_shift) + lba, nlb, ptr);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
len -= nlb << p->hd_sec_sz_s;
|
||||||
|
ptr += nlb << p->hd_sec_sz_s;
|
||||||
|
lba += nlb;
|
||||||
|
if (lba > lba_mask && len) {
|
||||||
|
lba = 0;
|
||||||
|
iwlba = SBig(d->wlba_table[++wlba]);
|
||||||
|
if (!iwlba)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (len) {
|
||||||
|
err = wbfsReadSector(p->part_lba + (iwlba << iwlba_shift) + lba, 1, m_tmpBuffer.get());
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
memcpy(ptr, m_tmpBuffer.get(), len);
|
memcpy(ptr, m_tmpBuffer.get(), len);
|
||||||
@@ -250,30 +237,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 +263,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(std::string_view path) { return std::make_unique<DiscIOWBFS>(path); }
|
||||||
{
|
|
||||||
return std::unique_ptr<IDiscIO>(new DiscIOWBFS(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
} // namespace nod
|
||||||
|
|||||||
707
lib/DiscWii.cpp
707
lib/DiscWii.cpp
File diff suppressed because it is too large
Load Diff
@@ -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 "Util.hpp"
|
||||||
|
|
||||||
namespace nod
|
#include <spdlog/spdlog.h>
|
||||||
{
|
|
||||||
|
|
||||||
class FileIOFILE : public IFileIO
|
namespace nod {
|
||||||
{
|
|
||||||
SystemString m_path;
|
class FileIOFILE : public IFileIO {
|
||||||
|
std::string 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(std::string_view 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(), "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(), "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,92 @@ 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(std::string_view path, int64_t maxWriteSize, bool& err) : m_maxWriteSize(maxWriteSize) {
|
||||||
: m_maxWriteSize(maxWriteSize)
|
fp = Fopen(path.data(), "wb");
|
||||||
{
|
if (!fp) {
|
||||||
fp = fopen(path.c_str(), "wb");
|
spdlog::error("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(std::string_view path, uint64_t offset, int64_t maxWriteSize, bool& err)
|
||||||
: m_maxWriteSize(maxWriteSize)
|
: m_maxWriteSize(maxWriteSize) {
|
||||||
{
|
fp = Fopen(path.data(), "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(), "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());
|
spdlog::error("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)
|
spdlog::error("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(std::string_view path, bool& err) {
|
||||||
{
|
fp = Fopen(path.data(), "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());
|
spdlog::error("unable to open '{}' for reading", path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ReadStream(const SystemString& path, uint64_t offset, bool& err)
|
ReadStream(std::string_view 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) {
|
||||||
{
|
spdlog::error("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) {
|
||||||
{
|
spdlog::error("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 +129,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(std::string_view 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,41 +1,56 @@
|
|||||||
#include <stdio.h>
|
#include <cstdint>
|
||||||
#include <stdlib.h>
|
#if _WIN32
|
||||||
#include <inttypes.h>
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
#include "nod/Util.hpp"
|
#define WIN32_LEAN_AND_MEAN 1
|
||||||
|
#endif
|
||||||
|
#ifndef NOMINMAX
|
||||||
|
#define NOMINMAX
|
||||||
|
#endif
|
||||||
|
#include <Windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "nod/IFileIO.hpp"
|
#include "nod/IFileIO.hpp"
|
||||||
|
#include "Util.hpp"
|
||||||
|
|
||||||
namespace nod
|
#include <spdlog/spdlog.h>
|
||||||
{
|
|
||||||
|
|
||||||
class FileIOWin32 : public IFileIO
|
#include <nowide/convert.hpp>
|
||||||
{
|
#include <nowide/stackstring.hpp>
|
||||||
SystemString m_path;
|
|
||||||
|
namespace nod {
|
||||||
|
|
||||||
|
class FileIOWin32 : public IFileIO {
|
||||||
|
std::wstring m_wpath;
|
||||||
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(std::string_view path, int64_t maxWriteSize)
|
||||||
HANDLE fp = CreateFileW(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ,
|
: m_wpath(nowide::widen(path)), m_maxWriteSize(maxWriteSize) {}
|
||||||
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
|
||||||
|
bool exists() override {
|
||||||
|
#if !WINDOWS_STORE
|
||||||
|
HANDLE fp = CreateFileW(m_wpath.data(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
|
#else
|
||||||
|
HANDLE fp = CreateFile2(m_path.get(), 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_wpath.data(), 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.get(), 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 +58,33 @@ 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(std::wstring_view wpath, int64_t maxWriteSize, bool& err) : m_maxWriteSize(maxWriteSize) {
|
||||||
: m_maxWriteSize(maxWriteSize)
|
#if !WINDOWS_STORE
|
||||||
{
|
fp = CreateFileW(wpath.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(wpath.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) {
|
||||||
|
const nowide::stackstring path(wpath.data(), wpath.data() + wpath.size());
|
||||||
|
spdlog::error("unable to open '{}' for writing", path.get());
|
||||||
err = true;
|
err = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WriteStream(const SystemString& path, uint64_t offset, int64_t maxWriteSize, bool& err)
|
WriteStream(std::wstring_view wpath, uint64_t offset, int64_t maxWriteSize, bool& err)
|
||||||
: m_maxWriteSize(maxWriteSize)
|
: m_maxWriteSize(maxWriteSize) {
|
||||||
{
|
#if !WINDOWS_STORE
|
||||||
fp = CreateFileW(path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE,
|
fp = CreateFileW(wpath.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(wpath.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) {
|
||||||
|
const nowide::stackstring path(wpath.data(), wpath.data() + wpath.size());
|
||||||
|
spdlog::error("unable to open '{}' for writing", path.get());
|
||||||
err = true;
|
err = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -73,20 +92,14 @@ 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) {
|
||||||
{
|
spdlog::error("write operation exceeds file's {}-byte limit", m_maxWriteSize);
|
||||||
LogModule.report(logvisor::Error, _S("write operation exceeds file's %" PRIi64 "-byte limit"), m_maxWriteSize);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,83 +109,77 @@ 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_wpath, 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_wpath, 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(std::wstring_view wpath, bool& err) {
|
||||||
{
|
#if !WINDOWS_STORE
|
||||||
fp = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ,
|
fp = CreateFileW(wpath.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(wpath.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());
|
const nowide::stackstring path(wpath.data(), wpath.data() + wpath.size());
|
||||||
|
spdlog::error("unable to open '{}' for reading", path.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ReadStream(const SystemString& path, uint64_t offset, bool& err)
|
ReadStream(std::wstring_view wpath, uint64_t offset, bool& err) : ReadStream(wpath, 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) {
|
||||||
{
|
spdlog::error("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) {
|
||||||
{
|
spdlog::error("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 +188,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_wpath, 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_wpath, 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(std::string_view 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
48
lib/IFileIO.cpp
Normal file
48
lib/IFileIO.cpp
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#include "nod/IFileIO.hpp"
|
||||||
|
#include "Util.hpp"
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
namespace nod {
|
||||||
|
uint64_t IFileIO::IWriteStream::copyFromDisc(IPartReadStream& discio, uint64_t length) {
|
||||||
|
uint64_t read = 0;
|
||||||
|
uint8_t buf[0x7c00];
|
||||||
|
while (length) {
|
||||||
|
uint64_t thisSz = nod::min(uint64_t(0x7c00), length);
|
||||||
|
uint64_t readSz = discio.read(buf, thisSz);
|
||||||
|
if (thisSz != readSz) {
|
||||||
|
spdlog::error("unable to read enough from disc");
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
if (write(buf, readSz) != readSz) {
|
||||||
|
spdlog::error("unable to write in file");
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
length -= thisSz;
|
||||||
|
read += thisSz;
|
||||||
|
}
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t IFileIO::IWriteStream::copyFromDisc(IPartReadStream& discio, uint64_t length,
|
||||||
|
const std::function<void(float)>& prog) {
|
||||||
|
uint64_t read = 0;
|
||||||
|
uint8_t buf[0x7c00];
|
||||||
|
uint64_t total = length;
|
||||||
|
while (length) {
|
||||||
|
uint64_t thisSz = nod::min(uint64_t(0x7c00), length);
|
||||||
|
uint64_t readSz = discio.read(buf, thisSz);
|
||||||
|
if (thisSz != readSz) {
|
||||||
|
spdlog::error("unable to read enough from disc");
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
if (write(buf, readSz) != readSz) {
|
||||||
|
spdlog::error("unable to write in file");
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
length -= thisSz;
|
||||||
|
read += thisSz;
|
||||||
|
prog(read / float(total));
|
||||||
|
}
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
} // namespace nod
|
||||||
3149
lib/OSUTF.c
Normal file
3149
lib/OSUTF.c
Normal file
File diff suppressed because it is too large
Load Diff
71
lib/Util.cpp
Normal file
71
lib/Util.cpp
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
#include "Util.hpp"
|
||||||
|
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN 1
|
||||||
|
#endif
|
||||||
|
#ifndef NOMINMAX
|
||||||
|
#define NOMINMAX
|
||||||
|
#endif
|
||||||
|
#include <Windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace nod {
|
||||||
|
FILE* Fopen(const char* path, const char* mode, FileLockType lock) {
|
||||||
|
#if _WIN32
|
||||||
|
const nowide::wstackstring wpath(path);
|
||||||
|
const nowide::wshort_stackstring wmode(mode);
|
||||||
|
FILE* fp = _wfopen(wpath.get(), wmode.get());
|
||||||
|
if (!fp)
|
||||||
|
return nullptr;
|
||||||
|
#else
|
||||||
|
FILE* fp = fopen(path, mode);
|
||||||
|
if (!fp)
|
||||||
|
return nullptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (lock != FileLockType::None) {
|
||||||
|
#if _WIN32
|
||||||
|
OVERLAPPED ov = {};
|
||||||
|
LockFileEx((HANDLE)(uintptr_t)_fileno(fp), (lock == FileLockType::Write) ? LOCKFILE_EXCLUSIVE_LOCK : 0, 0, 0, 1,
|
||||||
|
&ov);
|
||||||
|
#else
|
||||||
|
if (flock(fileno(fp), ((lock == FileLockType::Write) ? LOCK_EX : LOCK_SH) | LOCK_NB))
|
||||||
|
spdlog::error("flock {}: {}", path, strerror(errno));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckFreeSpace(const char* path, size_t reqSz) {
|
||||||
|
#if _WIN32
|
||||||
|
ULARGE_INTEGER freeBytes;
|
||||||
|
const nowide::wstackstring wpath(path);
|
||||||
|
std::array<wchar_t, 1024> buf{};
|
||||||
|
wchar_t* end = nullptr;
|
||||||
|
DWORD ret = GetFullPathNameW(wpath.get(), 1024, buf.data(), &end);
|
||||||
|
if (ret == 0 || ret > 1024) {
|
||||||
|
spdlog::error("GetFullPathNameW {}", path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (end != nullptr) {
|
||||||
|
end[0] = L'\0';
|
||||||
|
}
|
||||||
|
if (!GetDiskFreeSpaceExW(buf.data(), &freeBytes, nullptr, nullptr)) {
|
||||||
|
spdlog::error("GetDiskFreeSpaceExW {}: {}", path, GetLastError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return reqSz < freeBytes.QuadPart;
|
||||||
|
#else
|
||||||
|
struct statvfs svfs;
|
||||||
|
if (statvfs(path, &svfs)) {
|
||||||
|
spdlog::error("statvfs {}: {}", path, strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return reqSz < svfs.f_frsize * svfs.f_bavail;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} // namespace nod
|
||||||
126
lib/Util.hpp
Normal file
126
lib/Util.hpp
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
#include <array>
|
||||||
|
#include <cwctype>
|
||||||
|
#include <direct.h>
|
||||||
|
#include <nowide/stackstring.hpp>
|
||||||
|
#include <winapifamily.h>
|
||||||
|
#if defined(WINAPI_FAMILY) && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP
|
||||||
|
#define WINDOWS_STORE 1
|
||||||
|
#else
|
||||||
|
#define WINDOWS_STORE 0
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#include <cctype>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/statvfs.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(disable : 4996)
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
|
||||||
|
#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
|
||||||
|
#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(S_ISLNK)
|
||||||
|
#define S_ISLNK(m) 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef min
|
||||||
|
#undef max
|
||||||
|
|
||||||
|
namespace nod {
|
||||||
|
/* define our own min/max to avoid MSVC BS */
|
||||||
|
template <typename T>
|
||||||
|
constexpr T min(T a, T b) {
|
||||||
|
return a < b ? a : b;
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
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};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* filesystem char type */
|
||||||
|
#if _WIN32
|
||||||
|
static inline int Mkdir(const char* path, int) {
|
||||||
|
const nowide::wstackstring str(path);
|
||||||
|
return _wmkdir(str.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
using Sstat = struct ::_stat64;
|
||||||
|
static inline int Stat(const char* path, Sstat* statout) {
|
||||||
|
const nowide::wstackstring wpath(path);
|
||||||
|
return _wstat64(wpath.get(), statout);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline int Mkdir(const char* path, mode_t mode) { return mkdir(path, mode); }
|
||||||
|
|
||||||
|
typedef struct stat Sstat;
|
||||||
|
static inline int Stat(const char* path, Sstat* statout) { return stat(path, statout); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline int StrCaseCmp(const char* str1, const char* str2) {
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
return _stricmp(str1, str2);
|
||||||
|
#else
|
||||||
|
return strcasecmp(str1, str2);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef ROUND_UP_32
|
||||||
|
#define ROUND_UP_32(val) (((val) + 31) & ~31)
|
||||||
|
#define ROUND_UP_16(val) (((val) + 15) & ~15)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum class FileLockType { None = 0, Read, Write };
|
||||||
|
FILE* Fopen(const char* path, const char* mode, FileLockType lock = FileLockType::None);
|
||||||
|
|
||||||
|
static inline int FSeek(FILE* fp, int64_t offset, int whence) {
|
||||||
|
#if _WIN32
|
||||||
|
return _fseeki64(fp, offset, whence);
|
||||||
|
#elif __APPLE__ || __FreeBSD__
|
||||||
|
return fseeko(fp, offset, whence);
|
||||||
|
#else
|
||||||
|
return fseeko64(fp, offset, whence);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int64_t FTell(FILE* fp) {
|
||||||
|
#if _WIN32
|
||||||
|
return _ftelli64(fp);
|
||||||
|
#elif __APPLE__ || __FreeBSD__
|
||||||
|
return ftello(fp);
|
||||||
|
#else
|
||||||
|
return ftello64(fp);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckFreeSpace(const char* path, size_t reqSz);
|
||||||
|
|
||||||
|
} // namespace nod
|
||||||
330
lib/aes.cpp
330
lib/aes.cpp
@@ -1,36 +1,37 @@
|
|||||||
#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 */
|
||||||
|
|
||||||
#define ROTL(x) (((x)>>7)|((x)<<1))
|
#define ROTL(x) (((x) >> 7) | ((x) << 1))
|
||||||
|
|
||||||
/* Rotates 32-bit word left by 1, 2 or 3 byte */
|
/* Rotates 32-bit word left by 1, 2 or 3 byte */
|
||||||
|
|
||||||
#define ROTL8(x) (((x)<<8)|((x)>>24))
|
#define ROTL8(x) (((x) << 8) | ((x) >> 24))
|
||||||
#define ROTL16(x) (((x)<<16)|((x)>>16))
|
#define ROTL16(x) (((x) << 16) | ((x) >> 16))
|
||||||
#define ROTL24(x) (((x)<<24)|((x)>>8))
|
#define ROTL24(x) (((x) << 24) | ((x) >> 8))
|
||||||
|
|
||||||
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,17 +67,15 @@ 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);
|
||||||
unpack(y, yb);
|
unpack(y, yb);
|
||||||
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]] ^
|
ROTL16((uint32_t)AEStb.fbsub[(uint8_t)(x[fi[m + 1]] >> 16)]) ^
|
||||||
ROTL8((uint32_t)AEStb.fbsub[(uint8_t)(x[fi[m]] >> 8)])^
|
|
||||||
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]] ^
|
ROTL16((uint32_t)AEStb.rbsub[(uint8_t)(x[ri[m + 1]] >> 16)]) ^
|
||||||
ROTL8((uint32_t)AEStb.rbsub[(uint8_t)(x[ri[m]] >> 8)])^
|
|
||||||
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,45 +356,42 @@ 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;
|
||||||
|
|
||||||
//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,29 +399,28 @@ 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);
|
||||||
unsigned int blockno = 0, i;
|
unsigned int blockno = 0, i;
|
||||||
|
|
||||||
//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,49 +436,45 @@ 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)
|
len = len / 16 + 1;
|
||||||
len = len/16+1;
|
|
||||||
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]);
|
||||||
for (j=1 ; j<10 ; j++)
|
for (j = 1; j < 10; j++)
|
||||||
feedback = _mm_aesenc_si128(feedback, m_ekey[j]);
|
feedback = _mm_aesenc_si128(feedback, m_ekey[j]);
|
||||||
feedback = _mm_aesenclast_si128(feedback, m_ekey[j]);
|
feedback = _mm_aesenclast_si128(feedback, m_ekey[j]);
|
||||||
_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)
|
len = len / 16 + 1;
|
||||||
len = len/16+1;
|
|
||||||
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++)
|
||||||
data = _mm_aesdec_si128(data, m_dkey[j]);
|
data = _mm_aesdec_si128(data, m_dkey[j]);
|
||||||
data = _mm_aesdeclast_si128(data, m_dkey[j]);
|
data = _mm_aesdeclast_si128(data, m_dkey[j]);
|
||||||
data = _mm_xor_si128(data, feedback);
|
data = _mm_xor_si128(data, feedback);
|
||||||
@@ -519,22 +483,20 @@ 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);
|
||||||
temp1 = _mm_xor_si128 (temp1, temp3);
|
temp1 = _mm_xor_si128(temp1, temp3);
|
||||||
temp3 = _mm_slli_si128 (temp3, 0x4);
|
temp3 = _mm_slli_si128(temp3, 0x4);
|
||||||
temp1 = _mm_xor_si128 (temp1, temp3);
|
temp1 = _mm_xor_si128(temp1, temp3);
|
||||||
temp3 = _mm_slli_si128 (temp3, 0x4);
|
temp3 = _mm_slli_si128(temp3, 0x4);
|
||||||
temp1 = _mm_xor_si128 (temp1, temp3);
|
temp1 = _mm_xor_si128(temp1, temp3);
|
||||||
temp1 = _mm_xor_si128 (temp1, temp2);
|
temp1 = _mm_xor_si128(temp1, temp2);
|
||||||
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,32 +545,30 @@ 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);
|
||||||
HAS_AES_NI = ((info[2] & 0x2000000) != 0);
|
HAS_AES_NI = ((info[2] & 0x2000000) != 0);
|
||||||
#else
|
#else
|
||||||
unsigned int a,b,c,d;
|
unsigned int a, b, c, d;
|
||||||
__cpuid(1, a,b,c,d);
|
__cpuid(1, a, b, c, d);
|
||||||
HAS_AES_NI = ((c & 0x2000000) != 0);
|
HAS_AES_NI = ((c & 0x2000000) != 0);
|
||||||
#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
|
||||||
|
|
||||||
|
|||||||
76
lib/nod.cpp
76
lib/nod.cpp
@@ -1,22 +1,23 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include "nod/nod.hpp"
|
#include "nod/nod.hpp"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
#include "nod/DiscBase.hpp"
|
#include "nod/DiscBase.hpp"
|
||||||
|
#include "nod/DiscGCN.hpp"
|
||||||
|
#include "nod/DiscWii.hpp"
|
||||||
|
|
||||||
namespace nod
|
#include <spdlog/spdlog.h>
|
||||||
{
|
|
||||||
|
|
||||||
logvisor::Module LogModule("nod");
|
namespace nod {
|
||||||
|
std::unique_ptr<IDiscIO> NewDiscIOISO(std::string_view path);
|
||||||
|
std::unique_ptr<IDiscIO> NewDiscIOWBFS(std::string_view path);
|
||||||
|
std::unique_ptr<IDiscIO> NewDiscIONFS(std::string_view path);
|
||||||
|
|
||||||
std::unique_ptr<IDiscIO> NewDiscIOISO(const SystemChar* path);
|
std::unique_ptr<DiscBase> OpenDiscFromImage(std::string_view path, bool& isWii) {
|
||||||
std::unique_ptr<IDiscIO> NewDiscIOWBFS(const SystemChar* path);
|
|
||||||
|
|
||||||
std::unique_ptr<DiscBase> OpenDiscFromImage(const SystemChar* 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()) {
|
||||||
{
|
spdlog::error("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 +27,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) {
|
||||||
{
|
spdlog::error("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<std::string::size_type>::type;
|
||||||
{
|
const auto dotPos = SignedSize(path.rfind('.'));
|
||||||
|
const auto slashPos = SignedSize(path.find_last_of("/\\"));
|
||||||
|
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, "hif_") &&
|
||||||
{
|
!path.compare(dotPos, path.size() - dotPos, ".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 +58,29 @@ std::unique_ptr<DiscBase> OpenDiscFromImage(const SystemChar* path, bool& isWii)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!discIO)
|
if (!discIO) {
|
||||||
{
|
spdlog::error("'{}' 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(std::string_view path) {
|
||||||
{
|
|
||||||
bool isWii;
|
bool isWii;
|
||||||
return OpenDiscFromImage(path, isWii);
|
return OpenDiscFromImage(path, isWii);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace nod
|
||||||
|
|
||||||
|
|||||||
1
logvisor
1
logvisor
Submodule logvisor deleted from f8ab0e03ba
Reference in New Issue
Block a user