Compare commits
138 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3bb52c0a9 | ||
|
|
ab350b8975 | ||
|
|
42a00877a2 | ||
|
|
9619964e8c | ||
|
|
cfb7fd395c | ||
|
|
b62a8ca43e | ||
|
|
79504f1a39 | ||
|
|
25cd5d9dda | ||
|
|
2624b1eae6 | ||
|
|
ca5ed50655 | ||
|
|
baff9ffcac | ||
|
|
66ac7cf730 | ||
|
|
53fbf8e206 | ||
|
|
3ea3de4ecd | ||
|
|
3b8a8cf825 | ||
|
|
354811e556 | ||
|
|
acbae572d3 | ||
|
|
b1fa647f28 | ||
|
|
2d2e235bcf | ||
|
|
f6bb905182 | ||
|
|
551882e512 | ||
|
|
ed9ae5a977 | ||
|
|
999fc2fece | ||
|
|
bea9ed2548 | ||
|
|
00573fb2c9 | ||
|
|
56c6a5def8 | ||
|
|
0c885249df | ||
|
|
3472c00b3b | ||
|
|
0530dd6ea1 | ||
|
|
d8a90e6536 | ||
|
|
cbaf1bc711 | ||
|
|
bbb5623f52 | ||
|
|
a91acd5365 | ||
|
|
fde8102a41 | ||
|
|
ada9b7fb77 | ||
|
|
f49ffdd648 | ||
|
|
1b829fbd7a | ||
|
|
31a76410e8 | ||
|
|
c02464f64e | ||
|
|
4539073ce1 | ||
|
|
6ac97405df | ||
|
|
836ec9176a | ||
|
|
e23289d869 | ||
|
|
c4ed791164 | ||
|
|
d09456fc41 | ||
|
|
fe97d34156 | ||
|
|
dbb1cbce67 | ||
|
|
db96034ea4 | ||
|
|
404362e1b0 | ||
|
|
9f972b7d01 | ||
|
|
1ee060ca0d | ||
|
|
df72480395 | ||
|
|
2b601e8636 | ||
|
|
e6f9231ef0 | ||
|
|
cb6808b4d0 | ||
|
|
2aabd1eb05 | ||
|
|
feb243b08d | ||
|
|
fc2f8963bb | ||
|
|
2dace90346 | ||
|
|
fe86109877 | ||
|
|
969a4cc4da | ||
|
|
f482b4b40d | ||
|
|
b14277ef97 | ||
|
|
1f9ac1541f | ||
|
|
03d5a5d9de | ||
|
|
2296e921d2 | ||
|
|
34ec64233a | ||
|
|
167d36ec3c | ||
|
|
c8135b3c18 | ||
|
|
6b13d08822 | ||
|
|
83d8bf9af9 | ||
|
|
a93f6e51d3 | ||
|
|
f808258ed9 | ||
|
|
e050594706 | ||
|
|
a9de967fa3 | ||
|
|
ff0b14ee62 | ||
|
|
b724a4d90c | ||
|
|
e0ff98dd34 | ||
|
|
a8ffe6eee4 | ||
|
|
e143adc3cf | ||
|
|
4605e4d6ff | ||
|
|
f00641459e | ||
|
|
257b1d2c4b | ||
|
|
85feaf3005 | ||
|
|
d6672501ac | ||
|
|
9c6ae697f5 | ||
|
|
8928aa3008 | ||
|
|
504095cea9 | ||
|
|
ed51c2abda | ||
|
|
acfd771e79 | ||
|
|
664019954a | ||
|
|
1c3490a8db | ||
|
|
f14bb61acd | ||
|
|
929fc849e9 | ||
|
|
5429ea0e69 | ||
|
|
62fa00f586 | ||
|
|
53e94c7be8 | ||
|
|
8e86fa7e60 | ||
|
|
f5d538f118 | ||
|
|
5cc2f99fab | ||
|
|
61cd7eb47d | ||
|
|
06ab28263b | ||
|
|
253a17451b | ||
|
|
5b89291308 | ||
|
|
df96a214ae | ||
|
|
4f2acc54f5 | ||
|
|
7f0f37fca7 | ||
|
|
04bb47f57f | ||
|
|
09f884b7bd | ||
|
|
1cc0e4b4d8 | ||
|
|
35c1607f23 | ||
|
|
d888ac7d20 | ||
|
|
238208ee30 | ||
|
|
61678c4e9f | ||
|
|
e8868c2ed1 | ||
|
|
87c64c41d2 | ||
|
|
a10d64ea79 | ||
|
|
9893da8e2c | ||
|
|
1a45b15a8c | ||
|
|
4a2d9c6454 | ||
|
|
a77ee63f65 | ||
|
|
0a5456feb9 | ||
|
|
07691f994a | ||
|
|
cf946312ca | ||
|
|
1146049de0 | ||
|
|
15660bd857 | ||
|
|
dd2ff23621 | ||
|
|
8725b37a35 | ||
|
|
9b837c6069 | ||
|
|
24bd068a08 | ||
|
|
a5af1161c9 | ||
|
|
6cfff2c3f6 | ||
|
|
0105368cc1 | ||
|
|
e586921c28 | ||
|
|
e3f0c93230 | ||
|
|
2e511246fa | ||
|
|
c5bdccfecb | ||
|
|
dd4a02d15c |
@@ -7,7 +7,7 @@ if grep -nrI '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .ci* dis
|
||||
fi
|
||||
|
||||
# Default clang-format points to default 3.5 version one
|
||||
CLANG_FORMAT=clang-format-6.0
|
||||
CLANG_FORMAT=clang-format-10
|
||||
$CLANG_FORMAT --version
|
||||
|
||||
if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then
|
||||
|
||||
@@ -7,7 +7,7 @@ if grep -nrI '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .travis*
|
||||
fi
|
||||
|
||||
# Default clang-format points to default 3.5 version one
|
||||
CLANG_FORMAT=clang-format-6.0
|
||||
CLANG_FORMAT=clang-format-10.0
|
||||
$CLANG_FORMAT --version
|
||||
|
||||
if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then
|
||||
|
||||
@@ -161,7 +161,7 @@ macro(yuzu_find_packages)
|
||||
# Cmake Pkg Prefix Version Conan Pkg
|
||||
"Boost 1.73 boost/1.73.0"
|
||||
"Catch2 2.13 catch2/2.13.0"
|
||||
"fmt 7.0 fmt/7.0.1"
|
||||
"fmt 7.0 fmt/7.0.3"
|
||||
# can't use until https://github.com/bincrafters/community/issues/1173
|
||||
#"libzip 1.5 libzip/1.5.2@bincrafters/stable"
|
||||
"lz4 1.8 lz4/1.9.2"
|
||||
@@ -456,7 +456,7 @@ endif()
|
||||
# against all the src files. This should be used before making a pull request.
|
||||
# =======================================================================
|
||||
|
||||
set(CLANG_FORMAT_POSTFIX "-6.0")
|
||||
set(CLANG_FORMAT_POSTFIX "-10")
|
||||
find_program(CLANG_FORMAT
|
||||
NAMES clang-format${CLANG_FORMAT_POSTFIX}
|
||||
clang-format
|
||||
|
||||
2
externals/dynarmic
vendored
2
externals/dynarmic
vendored
Submodule externals/dynarmic updated: 82417da780...0e1112b7df
@@ -60,9 +60,14 @@ else()
|
||||
-Wmissing-declarations
|
||||
-Wno-attributes
|
||||
-Wno-unused-parameter
|
||||
-fconcepts
|
||||
)
|
||||
|
||||
# TODO: Remove when we update to a GCC compiler that enables this
|
||||
# by default (i.e. GCC 10 or newer).
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU)
|
||||
add_compile_options(-fconcepts)
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_x86_64)
|
||||
add_compile_options("-mcx16")
|
||||
endif()
|
||||
|
||||
@@ -78,7 +78,7 @@ public:
|
||||
const s16 surround_left{samples[i + 4]};
|
||||
const s16 surround_right{samples[i + 5]};
|
||||
// Not used in the ATSC reference implementation
|
||||
[[maybe_unused]] const s16 low_frequency_effects { samples[i + 3] };
|
||||
[[maybe_unused]] const s16 low_frequency_effects{samples[i + 3]};
|
||||
|
||||
constexpr s32 clev{707}; // center mixing level coefficient
|
||||
constexpr s32 slev{707}; // surround mixing level coefficient
|
||||
|
||||
@@ -172,7 +172,6 @@ add_library(common STATIC
|
||||
virtual_buffer.h
|
||||
wall_clock.cpp
|
||||
wall_clock.h
|
||||
web_result.h
|
||||
zstd_compression.cpp
|
||||
zstd_compression.h
|
||||
)
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
namespace Common {
|
||||
|
||||
template <class ForwardIt, class T, class Compare = std::less<>>
|
||||
ForwardIt BinaryFind(ForwardIt first, ForwardIt last, const T& value, Compare comp = {}) {
|
||||
[[nodiscard]] ForwardIt BinaryFind(ForwardIt first, ForwardIt last, const T& value,
|
||||
Compare comp = {}) {
|
||||
// Note: BOTH type T and the type after ForwardIt is dereferenced
|
||||
// must be implicitly convertible to BOTH Type1 and Type2, used in Compare.
|
||||
// This is stricter than lower_bound requirement (see above)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
namespace Common {
|
||||
|
||||
template <typename T>
|
||||
constexpr T AlignUp(T value, std::size_t size) {
|
||||
[[nodiscard]] constexpr T AlignUp(T value, std::size_t size) {
|
||||
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
|
||||
auto mod{static_cast<T>(value % size)};
|
||||
value -= mod;
|
||||
@@ -17,31 +17,31 @@ constexpr T AlignUp(T value, std::size_t size) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr T AlignDown(T value, std::size_t size) {
|
||||
[[nodiscard]] constexpr T AlignDown(T value, std::size_t size) {
|
||||
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
|
||||
return static_cast<T>(value - value % size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr T AlignBits(T value, std::size_t align) {
|
||||
[[nodiscard]] constexpr T AlignBits(T value, std::size_t align) {
|
||||
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
|
||||
return static_cast<T>((value + ((1ULL << align) - 1)) >> align << align);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr bool Is4KBAligned(T value) {
|
||||
[[nodiscard]] constexpr bool Is4KBAligned(T value) {
|
||||
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
|
||||
return (value & 0xFFF) == 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr bool IsWordAligned(T value) {
|
||||
[[nodiscard]] constexpr bool IsWordAligned(T value) {
|
||||
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
|
||||
return (value & 0b11) == 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr bool IsAligned(T value, std::size_t alignment) {
|
||||
[[nodiscard]] constexpr bool IsAligned(T value, std::size_t alignment) {
|
||||
using U = typename std::make_unsigned<T>::type;
|
||||
const U mask = static_cast<U>(alignment - 1);
|
||||
return (value & mask) == 0;
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
template <typename T2>
|
||||
constexpr AlignmentAllocator(const AlignmentAllocator<T2, Align>&) noexcept {}
|
||||
|
||||
T* allocate(size_type n) {
|
||||
[[nodiscard]] T* allocate(size_type n) {
|
||||
return static_cast<T*>(::operator new (n * sizeof(T), std::align_val_t{Align}));
|
||||
}
|
||||
|
||||
|
||||
@@ -14,50 +14,55 @@ namespace Common {
|
||||
|
||||
#if _MSC_VER
|
||||
|
||||
bool AtomicCompareAndSwap(u8 volatile* pointer, u8 value, u8 expected) {
|
||||
u8 result = _InterlockedCompareExchange8((char*)pointer, value, expected);
|
||||
bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
|
||||
const u8 result =
|
||||
_InterlockedCompareExchange8(reinterpret_cast<volatile char*>(pointer), value, expected);
|
||||
return result == expected;
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(u16 volatile* pointer, u16 value, u16 expected) {
|
||||
u16 result = _InterlockedCompareExchange16((short*)pointer, value, expected);
|
||||
bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
|
||||
const u16 result =
|
||||
_InterlockedCompareExchange16(reinterpret_cast<volatile short*>(pointer), value, expected);
|
||||
return result == expected;
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(u32 volatile* pointer, u32 value, u32 expected) {
|
||||
u32 result = _InterlockedCompareExchange((long*)pointer, value, expected);
|
||||
bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
|
||||
const u32 result =
|
||||
_InterlockedCompareExchange(reinterpret_cast<volatile long*>(pointer), value, expected);
|
||||
return result == expected;
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(u64 volatile* pointer, u64 value, u64 expected) {
|
||||
u64 result = _InterlockedCompareExchange64((__int64*)pointer, value, expected);
|
||||
bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
|
||||
const u64 result = _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*>(pointer),
|
||||
value, expected);
|
||||
return result == expected;
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(u64 volatile* pointer, u128 value, u128 expected) {
|
||||
return _InterlockedCompareExchange128((__int64*)pointer, value[1], value[0],
|
||||
(__int64*)expected.data()) != 0;
|
||||
bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
|
||||
return _InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), value[1],
|
||||
value[0],
|
||||
reinterpret_cast<__int64*>(expected.data())) != 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool AtomicCompareAndSwap(u8 volatile* pointer, u8 value, u8 expected) {
|
||||
bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
|
||||
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(u16 volatile* pointer, u16 value, u16 expected) {
|
||||
bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
|
||||
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(u32 volatile* pointer, u32 value, u32 expected) {
|
||||
bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
|
||||
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(u64 volatile* pointer, u64 value, u64 expected) {
|
||||
bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
|
||||
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(u64 volatile* pointer, u128 value, u128 expected) {
|
||||
bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
|
||||
unsigned __int128 value_a;
|
||||
unsigned __int128 expected_a;
|
||||
std::memcpy(&value_a, value.data(), sizeof(u128));
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
|
||||
namespace Common {
|
||||
|
||||
bool AtomicCompareAndSwap(u8 volatile* pointer, u8 value, u8 expected);
|
||||
bool AtomicCompareAndSwap(u16 volatile* pointer, u16 value, u16 expected);
|
||||
bool AtomicCompareAndSwap(u32 volatile* pointer, u32 value, u32 expected);
|
||||
bool AtomicCompareAndSwap(u64 volatile* pointer, u64 value, u64 expected);
|
||||
bool AtomicCompareAndSwap(u64 volatile* pointer, u128 value, u128 expected);
|
||||
[[nodiscard]] bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected);
|
||||
[[nodiscard]] bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected);
|
||||
[[nodiscard]] bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected);
|
||||
[[nodiscard]] bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected);
|
||||
[[nodiscard]] bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected);
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -36,13 +36,6 @@
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/swap.h"
|
||||
|
||||
// Inlining
|
||||
#ifdef _WIN32
|
||||
#define FORCE_INLINE __forceinline
|
||||
#else
|
||||
#define FORCE_INLINE inline __attribute__((always_inline))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Abstract bitfield class
|
||||
*
|
||||
@@ -142,8 +135,8 @@ public:
|
||||
* containing several bitfields can be assembled by formatting each of their values and ORing
|
||||
* the results together.
|
||||
*/
|
||||
static constexpr FORCE_INLINE StorageType FormatValue(const T& value) {
|
||||
return ((StorageType)value << position) & mask;
|
||||
[[nodiscard]] static constexpr StorageType FormatValue(const T& value) {
|
||||
return (static_cast<StorageType>(value) << position) & mask;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,7 +144,7 @@ public:
|
||||
* (such as Value() or operator T), but this can be used to extract a value from a bitfield
|
||||
* union in a constexpr context.
|
||||
*/
|
||||
static constexpr FORCE_INLINE T ExtractValue(const StorageType& storage) {
|
||||
[[nodiscard]] static constexpr T ExtractValue(const StorageType& storage) {
|
||||
if constexpr (std::numeric_limits<UnderlyingType>::is_signed) {
|
||||
std::size_t shift = 8 * sizeof(T) - bits;
|
||||
return static_cast<T>(static_cast<UnderlyingType>(storage << (shift - position)) >>
|
||||
@@ -175,7 +168,7 @@ public:
|
||||
constexpr BitField(BitField&&) noexcept = default;
|
||||
constexpr BitField& operator=(BitField&&) noexcept = default;
|
||||
|
||||
constexpr operator T() const {
|
||||
[[nodiscard]] constexpr operator T() const {
|
||||
return Value();
|
||||
}
|
||||
|
||||
@@ -183,11 +176,11 @@ public:
|
||||
storage = static_cast<StorageType>((storage & ~mask) | FormatValue(value));
|
||||
}
|
||||
|
||||
constexpr T Value() const {
|
||||
[[nodiscard]] constexpr T Value() const {
|
||||
return ExtractValue(storage);
|
||||
}
|
||||
|
||||
constexpr explicit operator bool() const {
|
||||
[[nodiscard]] constexpr explicit operator bool() const {
|
||||
return Value() != 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,12 +17,12 @@ namespace Common {
|
||||
|
||||
/// Gets the size of a specified type T in bits.
|
||||
template <typename T>
|
||||
constexpr std::size_t BitSize() {
|
||||
[[nodiscard]] constexpr std::size_t BitSize() {
|
||||
return sizeof(T) * CHAR_BIT;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
inline u32 CountLeadingZeroes32(u32 value) {
|
||||
[[nodiscard]] inline u32 CountLeadingZeroes32(u32 value) {
|
||||
unsigned long leading_zero = 0;
|
||||
|
||||
if (_BitScanReverse(&leading_zero, value) != 0) {
|
||||
@@ -32,7 +32,7 @@ inline u32 CountLeadingZeroes32(u32 value) {
|
||||
return 32;
|
||||
}
|
||||
|
||||
inline u32 CountLeadingZeroes64(u64 value) {
|
||||
[[nodiscard]] inline u32 CountLeadingZeroes64(u64 value) {
|
||||
unsigned long leading_zero = 0;
|
||||
|
||||
if (_BitScanReverse64(&leading_zero, value) != 0) {
|
||||
@@ -42,7 +42,7 @@ inline u32 CountLeadingZeroes64(u64 value) {
|
||||
return 64;
|
||||
}
|
||||
#else
|
||||
inline u32 CountLeadingZeroes32(u32 value) {
|
||||
[[nodiscard]] inline u32 CountLeadingZeroes32(u32 value) {
|
||||
if (value == 0) {
|
||||
return 32;
|
||||
}
|
||||
@@ -50,7 +50,7 @@ inline u32 CountLeadingZeroes32(u32 value) {
|
||||
return static_cast<u32>(__builtin_clz(value));
|
||||
}
|
||||
|
||||
inline u32 CountLeadingZeroes64(u64 value) {
|
||||
[[nodiscard]] inline u32 CountLeadingZeroes64(u64 value) {
|
||||
if (value == 0) {
|
||||
return 64;
|
||||
}
|
||||
@@ -60,7 +60,7 @@ inline u32 CountLeadingZeroes64(u64 value) {
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
inline u32 CountTrailingZeroes32(u32 value) {
|
||||
[[nodiscard]] inline u32 CountTrailingZeroes32(u32 value) {
|
||||
unsigned long trailing_zero = 0;
|
||||
|
||||
if (_BitScanForward(&trailing_zero, value) != 0) {
|
||||
@@ -70,7 +70,7 @@ inline u32 CountTrailingZeroes32(u32 value) {
|
||||
return 32;
|
||||
}
|
||||
|
||||
inline u32 CountTrailingZeroes64(u64 value) {
|
||||
[[nodiscard]] inline u32 CountTrailingZeroes64(u64 value) {
|
||||
unsigned long trailing_zero = 0;
|
||||
|
||||
if (_BitScanForward64(&trailing_zero, value) != 0) {
|
||||
@@ -80,7 +80,7 @@ inline u32 CountTrailingZeroes64(u64 value) {
|
||||
return 64;
|
||||
}
|
||||
#else
|
||||
inline u32 CountTrailingZeroes32(u32 value) {
|
||||
[[nodiscard]] inline u32 CountTrailingZeroes32(u32 value) {
|
||||
if (value == 0) {
|
||||
return 32;
|
||||
}
|
||||
@@ -88,7 +88,7 @@ inline u32 CountTrailingZeroes32(u32 value) {
|
||||
return static_cast<u32>(__builtin_ctz(value));
|
||||
}
|
||||
|
||||
inline u32 CountTrailingZeroes64(u64 value) {
|
||||
[[nodiscard]] inline u32 CountTrailingZeroes64(u64 value) {
|
||||
if (value == 0) {
|
||||
return 64;
|
||||
}
|
||||
@@ -99,13 +99,13 @@ inline u32 CountTrailingZeroes64(u64 value) {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
inline u32 MostSignificantBit32(const u32 value) {
|
||||
[[nodiscard]] inline u32 MostSignificantBit32(const u32 value) {
|
||||
unsigned long result;
|
||||
_BitScanReverse(&result, value);
|
||||
return static_cast<u32>(result);
|
||||
}
|
||||
|
||||
inline u32 MostSignificantBit64(const u64 value) {
|
||||
[[nodiscard]] inline u32 MostSignificantBit64(const u64 value) {
|
||||
unsigned long result;
|
||||
_BitScanReverse64(&result, value);
|
||||
return static_cast<u32>(result);
|
||||
@@ -113,30 +113,30 @@ inline u32 MostSignificantBit64(const u64 value) {
|
||||
|
||||
#else
|
||||
|
||||
inline u32 MostSignificantBit32(const u32 value) {
|
||||
[[nodiscard]] inline u32 MostSignificantBit32(const u32 value) {
|
||||
return 31U - static_cast<u32>(__builtin_clz(value));
|
||||
}
|
||||
|
||||
inline u32 MostSignificantBit64(const u64 value) {
|
||||
[[nodiscard]] inline u32 MostSignificantBit64(const u64 value) {
|
||||
return 63U - static_cast<u32>(__builtin_clzll(value));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
inline u32 Log2Floor32(const u32 value) {
|
||||
[[nodiscard]] inline u32 Log2Floor32(const u32 value) {
|
||||
return MostSignificantBit32(value);
|
||||
}
|
||||
|
||||
inline u32 Log2Ceil32(const u32 value) {
|
||||
[[nodiscard]] inline u32 Log2Ceil32(const u32 value) {
|
||||
const u32 log2_f = Log2Floor32(value);
|
||||
return log2_f + ((value ^ (1U << log2_f)) != 0U);
|
||||
}
|
||||
|
||||
inline u32 Log2Floor64(const u64 value) {
|
||||
[[nodiscard]] inline u32 Log2Floor64(const u64 value) {
|
||||
return MostSignificantBit64(value);
|
||||
}
|
||||
|
||||
inline u32 Log2Ceil64(const u64 value) {
|
||||
[[nodiscard]] inline u32 Log2Ceil64(const u64 value) {
|
||||
const u64 log2_f = static_cast<u64>(Log2Floor64(value));
|
||||
return static_cast<u32>(log2_f + ((value ^ (1ULL << log2_f)) != 0ULL));
|
||||
}
|
||||
|
||||
@@ -61,42 +61,43 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h> // for std::size_t.
|
||||
|
||||
namespace Common {
|
||||
|
||||
typedef std::pair<uint64_t, uint64_t> uint128;
|
||||
using uint128 = std::pair<uint64_t, uint64_t>;
|
||||
|
||||
inline uint64_t Uint128Low64(const uint128& x) {
|
||||
[[nodiscard]] inline uint64_t Uint128Low64(const uint128& x) {
|
||||
return x.first;
|
||||
}
|
||||
inline uint64_t Uint128High64(const uint128& x) {
|
||||
[[nodiscard]] inline uint64_t Uint128High64(const uint128& x) {
|
||||
return x.second;
|
||||
}
|
||||
|
||||
// Hash function for a byte array.
|
||||
uint64_t CityHash64(const char* buf, std::size_t len);
|
||||
[[nodiscard]] uint64_t CityHash64(const char* buf, std::size_t len);
|
||||
|
||||
// Hash function for a byte array. For convenience, a 64-bit seed is also
|
||||
// hashed into the result.
|
||||
uint64_t CityHash64WithSeed(const char* buf, std::size_t len, uint64_t seed);
|
||||
[[nodiscard]] uint64_t CityHash64WithSeed(const char* buf, std::size_t len, uint64_t seed);
|
||||
|
||||
// Hash function for a byte array. For convenience, two seeds are also
|
||||
// hashed into the result.
|
||||
uint64_t CityHash64WithSeeds(const char* buf, std::size_t len, uint64_t seed0, uint64_t seed1);
|
||||
[[nodiscard]] uint64_t CityHash64WithSeeds(const char* buf, std::size_t len, uint64_t seed0,
|
||||
uint64_t seed1);
|
||||
|
||||
// Hash function for a byte array.
|
||||
uint128 CityHash128(const char* s, std::size_t len);
|
||||
[[nodiscard]] uint128 CityHash128(const char* s, std::size_t len);
|
||||
|
||||
// Hash function for a byte array. For convenience, a 128-bit seed is also
|
||||
// hashed into the result.
|
||||
uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed);
|
||||
[[nodiscard]] uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed);
|
||||
|
||||
// Hash 128 input bits down to 64 bits of output.
|
||||
// This is intended to be a reasonably good hash function.
|
||||
inline uint64_t Hash128to64(const uint128& x) {
|
||||
[[nodiscard]] inline uint64_t Hash128to64(const uint128& x) {
|
||||
// Murmur-inspired hashing.
|
||||
const uint64_t kMul = 0x9ddfea08eb382d69ULL;
|
||||
uint64_t a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul;
|
||||
|
||||
@@ -13,42 +13,42 @@
|
||||
namespace Color {
|
||||
|
||||
/// Convert a 1-bit color component to 8 bit
|
||||
constexpr u8 Convert1To8(u8 value) {
|
||||
[[nodiscard]] constexpr u8 Convert1To8(u8 value) {
|
||||
return value * 255;
|
||||
}
|
||||
|
||||
/// Convert a 4-bit color component to 8 bit
|
||||
constexpr u8 Convert4To8(u8 value) {
|
||||
[[nodiscard]] constexpr u8 Convert4To8(u8 value) {
|
||||
return (value << 4) | value;
|
||||
}
|
||||
|
||||
/// Convert a 5-bit color component to 8 bit
|
||||
constexpr u8 Convert5To8(u8 value) {
|
||||
[[nodiscard]] constexpr u8 Convert5To8(u8 value) {
|
||||
return (value << 3) | (value >> 2);
|
||||
}
|
||||
|
||||
/// Convert a 6-bit color component to 8 bit
|
||||
constexpr u8 Convert6To8(u8 value) {
|
||||
[[nodiscard]] constexpr u8 Convert6To8(u8 value) {
|
||||
return (value << 2) | (value >> 4);
|
||||
}
|
||||
|
||||
/// Convert a 8-bit color component to 1 bit
|
||||
constexpr u8 Convert8To1(u8 value) {
|
||||
[[nodiscard]] constexpr u8 Convert8To1(u8 value) {
|
||||
return value >> 7;
|
||||
}
|
||||
|
||||
/// Convert a 8-bit color component to 4 bit
|
||||
constexpr u8 Convert8To4(u8 value) {
|
||||
[[nodiscard]] constexpr u8 Convert8To4(u8 value) {
|
||||
return value >> 4;
|
||||
}
|
||||
|
||||
/// Convert a 8-bit color component to 5 bit
|
||||
constexpr u8 Convert8To5(u8 value) {
|
||||
[[nodiscard]] constexpr u8 Convert8To5(u8 value) {
|
||||
return value >> 3;
|
||||
}
|
||||
|
||||
/// Convert a 8-bit color component to 6 bit
|
||||
constexpr u8 Convert8To6(u8 value) {
|
||||
[[nodiscard]] constexpr u8 Convert8To6(u8 value) {
|
||||
return value >> 2;
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ constexpr u8 Convert8To6(u8 value) {
|
||||
* @param bytes Pointer to encoded source color
|
||||
* @return Result color decoded as Common::Vec4<u8>
|
||||
*/
|
||||
inline Common::Vec4<u8> DecodeRGBA8(const u8* bytes) {
|
||||
[[nodiscard]] inline Common::Vec4<u8> DecodeRGBA8(const u8* bytes) {
|
||||
return {bytes[3], bytes[2], bytes[1], bytes[0]};
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ inline Common::Vec4<u8> DecodeRGBA8(const u8* bytes) {
|
||||
* @param bytes Pointer to encoded source color
|
||||
* @return Result color decoded as Common::Vec4<u8>
|
||||
*/
|
||||
inline Common::Vec4<u8> DecodeRGB8(const u8* bytes) {
|
||||
[[nodiscard]] inline Common::Vec4<u8> DecodeRGB8(const u8* bytes) {
|
||||
return {bytes[2], bytes[1], bytes[0], 255};
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ inline Common::Vec4<u8> DecodeRGB8(const u8* bytes) {
|
||||
* @param bytes Pointer to encoded source color
|
||||
* @return Result color decoded as Common::Vec4<u8>
|
||||
*/
|
||||
inline Common::Vec4<u8> DecodeRG8(const u8* bytes) {
|
||||
[[nodiscard]] inline Common::Vec4<u8> DecodeRG8(const u8* bytes) {
|
||||
return {bytes[1], bytes[0], 0, 255};
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ inline Common::Vec4<u8> DecodeRG8(const u8* bytes) {
|
||||
* @param bytes Pointer to encoded source color
|
||||
* @return Result color decoded as Common::Vec4<u8>
|
||||
*/
|
||||
inline Common::Vec4<u8> DecodeRGB565(const u8* bytes) {
|
||||
[[nodiscard]] inline Common::Vec4<u8> DecodeRGB565(const u8* bytes) {
|
||||
u16_le pixel;
|
||||
std::memcpy(&pixel, bytes, sizeof(pixel));
|
||||
return {Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F),
|
||||
@@ -96,7 +96,7 @@ inline Common::Vec4<u8> DecodeRGB565(const u8* bytes) {
|
||||
* @param bytes Pointer to encoded source color
|
||||
* @return Result color decoded as Common::Vec4<u8>
|
||||
*/
|
||||
inline Common::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
|
||||
[[nodiscard]] inline Common::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
|
||||
u16_le pixel;
|
||||
std::memcpy(&pixel, bytes, sizeof(pixel));
|
||||
return {Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F),
|
||||
@@ -108,7 +108,7 @@ inline Common::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
|
||||
* @param bytes Pointer to encoded source color
|
||||
* @return Result color decoded as Common::Vec4<u8>
|
||||
*/
|
||||
inline Common::Vec4<u8> DecodeRGBA4(const u8* bytes) {
|
||||
[[nodiscard]] inline Common::Vec4<u8> DecodeRGBA4(const u8* bytes) {
|
||||
u16_le pixel;
|
||||
std::memcpy(&pixel, bytes, sizeof(pixel));
|
||||
return {Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF),
|
||||
@@ -120,7 +120,7 @@ inline Common::Vec4<u8> DecodeRGBA4(const u8* bytes) {
|
||||
* @param bytes Pointer to encoded source value
|
||||
* @return Depth value as an u32
|
||||
*/
|
||||
inline u32 DecodeD16(const u8* bytes) {
|
||||
[[nodiscard]] inline u32 DecodeD16(const u8* bytes) {
|
||||
u16_le data;
|
||||
std::memcpy(&data, bytes, sizeof(data));
|
||||
return data;
|
||||
@@ -131,7 +131,7 @@ inline u32 DecodeD16(const u8* bytes) {
|
||||
* @param bytes Pointer to encoded source value
|
||||
* @return Depth value as an u32
|
||||
*/
|
||||
inline u32 DecodeD24(const u8* bytes) {
|
||||
[[nodiscard]] inline u32 DecodeD24(const u8* bytes) {
|
||||
return (bytes[2] << 16) | (bytes[1] << 8) | bytes[0];
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ inline u32 DecodeD24(const u8* bytes) {
|
||||
* @param bytes Pointer to encoded source values
|
||||
* @return Resulting values stored as a Common::Vec2
|
||||
*/
|
||||
inline Common::Vec2<u32> DecodeD24S8(const u8* bytes) {
|
||||
[[nodiscard]] inline Common::Vec2<u32> DecodeD24S8(const u8* bytes) {
|
||||
return {static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3]};
|
||||
}
|
||||
|
||||
|
||||
@@ -53,14 +53,14 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
|
||||
// Call directly after the command or use the error num.
|
||||
// This function might change the error code.
|
||||
// Defined in Misc.cpp.
|
||||
std::string GetLastErrorMsg();
|
||||
[[nodiscard]] std::string GetLastErrorMsg();
|
||||
|
||||
#define DECLARE_ENUM_FLAG_OPERATORS(type) \
|
||||
constexpr type operator|(type a, type b) noexcept { \
|
||||
[[nodiscard]] constexpr type operator|(type a, type b) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<type>(static_cast<T>(a) | static_cast<T>(b)); \
|
||||
} \
|
||||
constexpr type operator&(type a, type b) noexcept { \
|
||||
[[nodiscard]] constexpr type operator&(type a, type b) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<type>(static_cast<T>(a) & static_cast<T>(b)); \
|
||||
} \
|
||||
@@ -74,22 +74,22 @@ std::string GetLastErrorMsg();
|
||||
a = static_cast<type>(static_cast<T>(a) & static_cast<T>(b)); \
|
||||
return a; \
|
||||
} \
|
||||
constexpr type operator~(type key) noexcept { \
|
||||
[[nodiscard]] constexpr type operator~(type key) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<type>(~static_cast<T>(key)); \
|
||||
} \
|
||||
constexpr bool True(type key) noexcept { \
|
||||
[[nodiscard]] constexpr bool True(type key) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<T>(key) != 0; \
|
||||
} \
|
||||
constexpr bool False(type key) noexcept { \
|
||||
[[nodiscard]] constexpr bool False(type key) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<T>(key) == 0; \
|
||||
}
|
||||
|
||||
namespace Common {
|
||||
|
||||
constexpr u32 MakeMagic(char a, char b, char c, char d) {
|
||||
[[nodiscard]] constexpr u32 MakeMagic(char a, char b, char c, char d) {
|
||||
return u32(a) | u32(b) << 8 | u32(c) << 16 | u32(d) << 24;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Common {
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace Common {
|
||||
|
||||
// Check if type is like an STL container
|
||||
template <typename T>
|
||||
concept IsSTLContainer = requires(T t) {
|
||||
@@ -23,10 +23,12 @@ concept IsSTLContainer = requires(T t) {
|
||||
t.size();
|
||||
};
|
||||
|
||||
// Check if type T is derived from T2
|
||||
template <typename T, typename T2>
|
||||
concept IsBaseOf = requires {
|
||||
std::is_base_of_v<T, T2>;
|
||||
// TODO: Replace with std::derived_from when the <concepts> header
|
||||
// is available on all supported platforms.
|
||||
template <typename Derived, typename Base>
|
||||
concept DerivedFrom = requires {
|
||||
std::is_base_of_v<Base, Derived>;
|
||||
std::is_convertible_v<const volatile Derived*, const volatile Base*>;
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -34,8 +34,7 @@ void DetachedTasks::AddTask(std::function<void()> task) {
|
||||
std::unique_lock lock{instance->mutex};
|
||||
--instance->count;
|
||||
std::notify_all_at_thread_exit(instance->cv, std::move(lock));
|
||||
})
|
||||
.detach();
|
||||
}).detach();
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Common {
|
||||
DynamicLibrary::DynamicLibrary() = default;
|
||||
|
||||
DynamicLibrary::DynamicLibrary(const char* filename) {
|
||||
Open(filename);
|
||||
void(Open(filename));
|
||||
}
|
||||
|
||||
DynamicLibrary::DynamicLibrary(DynamicLibrary&& rhs) noexcept
|
||||
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
~DynamicLibrary();
|
||||
|
||||
/// Returns the specified library name with the platform-specific suffix added.
|
||||
static std::string GetUnprefixedFilename(const char* filename);
|
||||
[[nodiscard]] static std::string GetUnprefixedFilename(const char* filename);
|
||||
|
||||
/// Returns the specified library name in platform-specific format.
|
||||
/// Major/minor versions will not be included if set to -1.
|
||||
@@ -41,28 +41,29 @@ public:
|
||||
/// Windows: LIBNAME-MAJOR-MINOR.dll
|
||||
/// Linux: libLIBNAME.so.MAJOR.MINOR
|
||||
/// Mac: libLIBNAME.MAJOR.MINOR.dylib
|
||||
static std::string GetVersionedFilename(const char* libname, int major = -1, int minor = -1);
|
||||
[[nodiscard]] static std::string GetVersionedFilename(const char* libname, int major = -1,
|
||||
int minor = -1);
|
||||
|
||||
/// Returns true if a module is loaded, otherwise false.
|
||||
bool IsOpen() const {
|
||||
[[nodiscard]] bool IsOpen() const {
|
||||
return handle != nullptr;
|
||||
}
|
||||
|
||||
/// Loads (or replaces) the handle with the specified library file name.
|
||||
/// Returns true if the library was loaded and can be used.
|
||||
bool Open(const char* filename);
|
||||
[[nodiscard]] bool Open(const char* filename);
|
||||
|
||||
/// Unloads the library, any function pointers from this library are no longer valid.
|
||||
void Close();
|
||||
|
||||
/// Returns the address of the specified symbol (function or variable) as an untyped pointer.
|
||||
/// If the specified symbol does not exist in this library, nullptr is returned.
|
||||
void* GetSymbolAddress(const char* name) const;
|
||||
[[nodiscard]] void* GetSymbolAddress(const char* name) const;
|
||||
|
||||
/// Obtains the address of the specified symbol, automatically casting to the correct type.
|
||||
/// Returns true if the symbol was found and assigned, otherwise false.
|
||||
template <typename T>
|
||||
bool GetSymbol(const char* name, T* ptr) const {
|
||||
[[nodiscard]] bool GetSymbol(const char* name, T* ptr) const {
|
||||
*ptr = reinterpret_cast<T>(GetSymbolAddress(name));
|
||||
return *ptr != nullptr;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
/// Yields control from Fiber 'from' to Fiber 'to'
|
||||
/// Fiber 'from' must be the currently running fiber.
|
||||
static void YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to);
|
||||
static std::shared_ptr<Fiber> ThreadToFiber();
|
||||
[[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber();
|
||||
|
||||
void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter);
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
// This namespace has various generic functions related to files and paths.
|
||||
// The code still needs a ton of cleanup.
|
||||
// REMEMBER: strdup considered harmful!
|
||||
namespace FileUtil {
|
||||
namespace Common::FS {
|
||||
|
||||
// Remove any ending forward slashes from directory paths
|
||||
// Modifies argument.
|
||||
@@ -196,7 +196,7 @@ bool CreateFullPath(const std::string& fullPath) {
|
||||
int panicCounter = 100;
|
||||
LOG_TRACE(Common_Filesystem, "path {}", fullPath);
|
||||
|
||||
if (FileUtil::Exists(fullPath)) {
|
||||
if (Exists(fullPath)) {
|
||||
LOG_DEBUG(Common_Filesystem, "path exists {}", fullPath);
|
||||
return true;
|
||||
}
|
||||
@@ -212,7 +212,7 @@ bool CreateFullPath(const std::string& fullPath) {
|
||||
|
||||
// Include the '/' so the first call is CreateDir("/") rather than CreateDir("")
|
||||
std::string const subPath(fullPath.substr(0, position + 1));
|
||||
if (!FileUtil::IsDirectory(subPath) && !FileUtil::CreateDir(subPath)) {
|
||||
if (!IsDirectory(subPath) && !CreateDir(subPath)) {
|
||||
LOG_ERROR(Common, "CreateFullPath: directory creation failed");
|
||||
return false;
|
||||
}
|
||||
@@ -231,7 +231,7 @@ bool DeleteDir(const std::string& filename) {
|
||||
LOG_TRACE(Common_Filesystem, "directory {}", filename);
|
||||
|
||||
// check if a directory
|
||||
if (!FileUtil::IsDirectory(filename)) {
|
||||
if (!IsDirectory(filename)) {
|
||||
LOG_ERROR(Common_Filesystem, "Not a directory {}", filename);
|
||||
return false;
|
||||
}
|
||||
@@ -371,7 +371,7 @@ u64 GetSize(FILE* f) {
|
||||
bool CreateEmptyFile(const std::string& filename) {
|
||||
LOG_TRACE(Common_Filesystem, "{}", filename);
|
||||
|
||||
if (!FileUtil::IOFile(filename, "wb").IsOpen()) {
|
||||
if (!IOFile(filename, "wb").IsOpen()) {
|
||||
LOG_ERROR(Common_Filesystem, "failed {}: {}", filename, GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
@@ -488,29 +488,34 @@ bool DeleteDirRecursively(const std::string& directory, unsigned int recursion)
|
||||
return false;
|
||||
|
||||
// Delete the outermost directory
|
||||
FileUtil::DeleteDir(directory);
|
||||
DeleteDir(directory);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CopyDir(const std::string& source_path, const std::string& dest_path) {
|
||||
#ifndef _WIN32
|
||||
if (source_path == dest_path)
|
||||
if (source_path == dest_path) {
|
||||
return;
|
||||
if (!FileUtil::Exists(source_path))
|
||||
}
|
||||
if (!Exists(source_path)) {
|
||||
return;
|
||||
if (!FileUtil::Exists(dest_path))
|
||||
FileUtil::CreateFullPath(dest_path);
|
||||
}
|
||||
if (!Exists(dest_path)) {
|
||||
CreateFullPath(dest_path);
|
||||
}
|
||||
|
||||
DIR* dirp = opendir(source_path.c_str());
|
||||
if (!dirp)
|
||||
if (!dirp) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (struct dirent* result = readdir(dirp)) {
|
||||
const std::string virtualName(result->d_name);
|
||||
// check for "." and ".."
|
||||
if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
|
||||
((virtualName[0] == '.') && (virtualName[1] == '.') && (virtualName[2] == '\0')))
|
||||
((virtualName[0] == '.') && (virtualName[1] == '.') && (virtualName[2] == '\0'))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string source, dest;
|
||||
source = source_path + virtualName;
|
||||
@@ -518,11 +523,13 @@ void CopyDir(const std::string& source_path, const std::string& dest_path) {
|
||||
if (IsDirectory(source)) {
|
||||
source += '/';
|
||||
dest += '/';
|
||||
if (!FileUtil::Exists(dest))
|
||||
FileUtil::CreateFullPath(dest);
|
||||
if (!Exists(dest)) {
|
||||
CreateFullPath(dest);
|
||||
}
|
||||
CopyDir(source, dest);
|
||||
} else if (!FileUtil::Exists(dest))
|
||||
FileUtil::Copy(source, dest);
|
||||
} else if (!Exists(dest)) {
|
||||
Copy(source, dest);
|
||||
}
|
||||
}
|
||||
closedir(dirp);
|
||||
#endif
|
||||
@@ -538,7 +545,7 @@ std::optional<std::string> GetCurrentDir() {
|
||||
if (!dir) {
|
||||
#endif
|
||||
LOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: {}", GetLastErrorMsg());
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
std::string strDir = Common::UTF16ToUTF8(dir);
|
||||
@@ -546,7 +553,7 @@ std::optional<std::string> GetCurrentDir() {
|
||||
std::string strDir = dir;
|
||||
#endif
|
||||
free(dir);
|
||||
return strDir;
|
||||
return std::move(strDir);
|
||||
}
|
||||
|
||||
bool SetCurrentDir(const std::string& directory) {
|
||||
@@ -668,7 +675,7 @@ const std::string& GetUserPath(UserPath path, const std::string& new_path) {
|
||||
if (user_path.empty()) {
|
||||
#ifdef _WIN32
|
||||
user_path = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
|
||||
if (!FileUtil::IsDirectory(user_path)) {
|
||||
if (!IsDirectory(user_path)) {
|
||||
user_path = AppDataRoamingDirectory() + DIR_SEP EMU_DATA_DIR DIR_SEP;
|
||||
} else {
|
||||
LOG_INFO(Common_Filesystem, "Using the local user directory");
|
||||
@@ -677,7 +684,7 @@ const std::string& GetUserPath(UserPath path, const std::string& new_path) {
|
||||
paths.emplace(UserPath::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
|
||||
paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
|
||||
#else
|
||||
if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) {
|
||||
if (Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) {
|
||||
user_path = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
|
||||
paths.emplace(UserPath::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
|
||||
paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
|
||||
@@ -704,7 +711,7 @@ const std::string& GetUserPath(UserPath path, const std::string& new_path) {
|
||||
}
|
||||
|
||||
if (!new_path.empty()) {
|
||||
if (!FileUtil::IsDirectory(new_path)) {
|
||||
if (!IsDirectory(new_path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Invalid path specified {}", new_path);
|
||||
return paths[path];
|
||||
} else {
|
||||
@@ -902,10 +909,10 @@ std::string SanitizePath(std::string_view path_, DirectorySeparator directory_se
|
||||
return std::string(RemoveTrailingSlash(path));
|
||||
}
|
||||
|
||||
IOFile::IOFile() {}
|
||||
IOFile::IOFile() = default;
|
||||
|
||||
IOFile::IOFile(const std::string& filename, const char openmode[], int flags) {
|
||||
Open(filename, openmode, flags);
|
||||
void(Open(filename, openmode, flags));
|
||||
}
|
||||
|
||||
IOFile::~IOFile() {
|
||||
@@ -946,17 +953,18 @@ bool IOFile::Open(const std::string& filename, const char openmode[], int flags)
|
||||
}
|
||||
|
||||
bool IOFile::Close() {
|
||||
if (!IsOpen() || 0 != std::fclose(m_file))
|
||||
if (!IsOpen() || 0 != std::fclose(m_file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_file = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
u64 IOFile::GetSize() const {
|
||||
if (IsOpen())
|
||||
return FileUtil::GetSize(m_file);
|
||||
|
||||
if (IsOpen()) {
|
||||
return FS::GetSize(m_file);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -965,9 +973,9 @@ bool IOFile::Seek(s64 off, int origin) const {
|
||||
}
|
||||
|
||||
u64 IOFile::Tell() const {
|
||||
if (IsOpen())
|
||||
if (IsOpen()) {
|
||||
return ftello(m_file);
|
||||
|
||||
}
|
||||
return std::numeric_limits<u64>::max();
|
||||
}
|
||||
|
||||
@@ -1016,4 +1024,4 @@ bool IOFile::Resize(u64 size) {
|
||||
;
|
||||
}
|
||||
|
||||
} // namespace FileUtil
|
||||
} // namespace Common::FS
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "common/string_util.h"
|
||||
#endif
|
||||
|
||||
namespace FileUtil {
|
||||
namespace Common::FS {
|
||||
|
||||
// User paths for GetUserPath
|
||||
enum class UserPath {
|
||||
@@ -48,19 +48,19 @@ struct FSTEntry {
|
||||
};
|
||||
|
||||
// Returns true if file filename exists
|
||||
bool Exists(const std::string& filename);
|
||||
[[nodiscard]] bool Exists(const std::string& filename);
|
||||
|
||||
// Returns true if filename is a directory
|
||||
bool IsDirectory(const std::string& filename);
|
||||
[[nodiscard]] bool IsDirectory(const std::string& filename);
|
||||
|
||||
// Returns the size of filename (64bit)
|
||||
u64 GetSize(const std::string& filename);
|
||||
[[nodiscard]] u64 GetSize(const std::string& filename);
|
||||
|
||||
// Overloaded GetSize, accepts file descriptor
|
||||
u64 GetSize(const int fd);
|
||||
[[nodiscard]] u64 GetSize(int fd);
|
||||
|
||||
// Overloaded GetSize, accepts FILE*
|
||||
u64 GetSize(FILE* f);
|
||||
[[nodiscard]] u64 GetSize(FILE* f);
|
||||
|
||||
// Returns true if successful, or path already exists.
|
||||
bool CreateDir(const std::string& filename);
|
||||
@@ -120,7 +120,7 @@ u64 ScanDirectoryTree(const std::string& directory, FSTEntry& parent_entry,
|
||||
bool DeleteDirRecursively(const std::string& directory, unsigned int recursion = 256);
|
||||
|
||||
// Returns the current directory
|
||||
std::optional<std::string> GetCurrentDir();
|
||||
[[nodiscard]] std::optional<std::string> GetCurrentDir();
|
||||
|
||||
// Create directory and copy contents (does not overwrite existing files)
|
||||
void CopyDir(const std::string& source_path, const std::string& dest_path);
|
||||
@@ -132,20 +132,20 @@ bool SetCurrentDir(const std::string& directory);
|
||||
// directory. To be used in "multi-user" mode (that is, installed).
|
||||
const std::string& GetUserPath(UserPath path, const std::string& new_path = "");
|
||||
|
||||
std::string GetHactoolConfigurationPath();
|
||||
[[nodiscard]] std::string GetHactoolConfigurationPath();
|
||||
|
||||
std::string GetNANDRegistrationDir(bool system = false);
|
||||
[[nodiscard]] std::string GetNANDRegistrationDir(bool system = false);
|
||||
|
||||
// Returns the path to where the sys file are
|
||||
std::string GetSysDirectory();
|
||||
[[nodiscard]] std::string GetSysDirectory();
|
||||
|
||||
#ifdef __APPLE__
|
||||
std::string GetBundleDirectory();
|
||||
[[nodiscard]] std::string GetBundleDirectory();
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
const std::string& GetExeDirectory();
|
||||
std::string AppDataRoamingDirectory();
|
||||
[[nodiscard]] const std::string& GetExeDirectory();
|
||||
[[nodiscard]] std::string AppDataRoamingDirectory();
|
||||
#endif
|
||||
|
||||
std::size_t WriteStringToFile(bool text_file, const std::string& filename, std::string_view str);
|
||||
@@ -164,38 +164,55 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
|
||||
|
||||
// Splits the path on '/' or '\' and put the components into a vector
|
||||
// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" }
|
||||
std::vector<std::string> SplitPathComponents(std::string_view filename);
|
||||
[[nodiscard]] std::vector<std::string> SplitPathComponents(std::string_view filename);
|
||||
|
||||
// Gets all of the text up to the last '/' or '\' in the path.
|
||||
std::string_view GetParentPath(std::string_view path);
|
||||
[[nodiscard]] std::string_view GetParentPath(std::string_view path);
|
||||
|
||||
// Gets all of the text after the first '/' or '\' in the path.
|
||||
std::string_view GetPathWithoutTop(std::string_view path);
|
||||
[[nodiscard]] std::string_view GetPathWithoutTop(std::string_view path);
|
||||
|
||||
// Gets the filename of the path
|
||||
std::string_view GetFilename(std::string_view path);
|
||||
[[nodiscard]] std::string_view GetFilename(std::string_view path);
|
||||
|
||||
// Gets the extension of the filename
|
||||
std::string_view GetExtensionFromFilename(std::string_view name);
|
||||
[[nodiscard]] std::string_view GetExtensionFromFilename(std::string_view name);
|
||||
|
||||
// Removes the final '/' or '\' if one exists
|
||||
std::string_view RemoveTrailingSlash(std::string_view path);
|
||||
[[nodiscard]] std::string_view RemoveTrailingSlash(std::string_view path);
|
||||
|
||||
// Creates a new vector containing indices [first, last) from the original.
|
||||
template <typename T>
|
||||
std::vector<T> SliceVector(const std::vector<T>& vector, std::size_t first, std::size_t last) {
|
||||
if (first >= last)
|
||||
[[nodiscard]] std::vector<T> SliceVector(const std::vector<T>& vector, std::size_t first,
|
||||
std::size_t last) {
|
||||
if (first >= last) {
|
||||
return {};
|
||||
}
|
||||
last = std::min<std::size_t>(last, vector.size());
|
||||
return std::vector<T>(vector.begin() + first, vector.begin() + first + last);
|
||||
}
|
||||
|
||||
enum class DirectorySeparator { ForwardSlash, BackwardSlash, PlatformDefault };
|
||||
enum class DirectorySeparator {
|
||||
ForwardSlash,
|
||||
BackwardSlash,
|
||||
PlatformDefault,
|
||||
};
|
||||
|
||||
// Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\'
|
||||
// depending if directory_separator is BackwardSlash or PlatformDefault and running on windows
|
||||
std::string SanitizePath(std::string_view path,
|
||||
DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash);
|
||||
[[nodiscard]] std::string SanitizePath(
|
||||
std::string_view path,
|
||||
DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash);
|
||||
|
||||
// To deal with Windows being dumb at Unicode
|
||||
template <typename T>
|
||||
void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) {
|
||||
#ifdef _MSC_VER
|
||||
fstream.open(Common::UTF8ToUTF16W(filename), openmode);
|
||||
#else
|
||||
fstream.open(filename, openmode);
|
||||
#endif
|
||||
}
|
||||
|
||||
// simple wrapper for cstdlib file functions to
|
||||
// hopefully will make error checking easier
|
||||
@@ -215,7 +232,7 @@ public:
|
||||
|
||||
void Swap(IOFile& other) noexcept;
|
||||
|
||||
bool Open(const std::string& filename, const char openmode[], int flags = 0);
|
||||
[[nodiscard]] bool Open(const std::string& filename, const char openmode[], int flags = 0);
|
||||
bool Close();
|
||||
|
||||
template <typename T>
|
||||
@@ -256,13 +273,13 @@ public:
|
||||
return WriteArray(str.data(), str.length());
|
||||
}
|
||||
|
||||
bool IsOpen() const {
|
||||
[[nodiscard]] bool IsOpen() const {
|
||||
return nullptr != m_file;
|
||||
}
|
||||
|
||||
bool Seek(s64 off, int origin) const;
|
||||
u64 Tell() const;
|
||||
u64 GetSize() const;
|
||||
[[nodiscard]] u64 Tell() const;
|
||||
[[nodiscard]] u64 GetSize() const;
|
||||
bool Resize(u64 size);
|
||||
bool Flush();
|
||||
|
||||
@@ -278,14 +295,4 @@ private:
|
||||
std::FILE* m_file = nullptr;
|
||||
};
|
||||
|
||||
} // namespace FileUtil
|
||||
|
||||
// To deal with Windows being dumb at unicode:
|
||||
template <typename T>
|
||||
void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) {
|
||||
#ifdef _MSC_VER
|
||||
fstream.open(Common::UTF8ToUTF16W(filename), openmode);
|
||||
#else
|
||||
fstream.open(filename, openmode);
|
||||
#endif
|
||||
}
|
||||
} // namespace Common::FS
|
||||
|
||||
@@ -5,36 +5,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include "common/cityhash.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
/**
|
||||
* Computes a 64-bit hash over the specified block of data
|
||||
* @param data Block of data to compute hash over
|
||||
* @param len Length of data (in bytes) to compute hash over
|
||||
* @returns 64-bit hash value that was computed over the data block
|
||||
*/
|
||||
static inline u64 ComputeHash64(const void* data, std::size_t len) {
|
||||
return CityHash64(static_cast<const char*>(data), len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a 64-bit hash of a struct. In addition to being trivially copyable, it is also critical
|
||||
* that either the struct includes no padding, or that any padding is initialized to a known value
|
||||
* by memsetting the struct to 0 before filling it in.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline u64 ComputeStructHash64(const T& data) {
|
||||
static_assert(std::is_trivially_copyable_v<T>,
|
||||
"Type passed to ComputeStructHash64 must be trivially copyable");
|
||||
return ComputeHash64(&data, sizeof(data));
|
||||
}
|
||||
|
||||
struct PairHash {
|
||||
template <class T1, class T2>
|
||||
std::size_t operator()(const std::pair<T1, T2>& pair) const noexcept {
|
||||
|
||||
@@ -3,21 +3,9 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/hex_util.h"
|
||||
#include "common/logging/log.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
u8 ToHexNibble(char c1) {
|
||||
if (c1 >= 65 && c1 <= 70)
|
||||
return c1 - 55;
|
||||
if (c1 >= 97 && c1 <= 102)
|
||||
return c1 - 87;
|
||||
if (c1 >= 48 && c1 <= 57)
|
||||
return c1 - 48;
|
||||
LOG_ERROR(Common, "Invalid hex digit: 0x{:02X}", c1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<u8> HexStringToVector(std::string_view str, bool little_endian) {
|
||||
std::vector<u8> out(str.size() / 2);
|
||||
if (little_endian) {
|
||||
@@ -30,26 +18,4 @@ std::vector<u8> HexStringToVector(std::string_view str, bool little_endian) {
|
||||
return out;
|
||||
}
|
||||
|
||||
std::array<u8, 16> operator""_array16(const char* str, std::size_t len) {
|
||||
if (len != 32) {
|
||||
LOG_ERROR(Common,
|
||||
"Attempting to parse string to array that is not of correct size (expected=32, "
|
||||
"actual={}).",
|
||||
len);
|
||||
return {};
|
||||
}
|
||||
return HexStringToArray<16>(str);
|
||||
}
|
||||
|
||||
std::array<u8, 32> operator""_array32(const char* str, std::size_t len) {
|
||||
if (len != 64) {
|
||||
LOG_ERROR(Common,
|
||||
"Attempting to parse string to array that is not of correct size (expected=64, "
|
||||
"actual={}).",
|
||||
len);
|
||||
return {};
|
||||
}
|
||||
return HexStringToArray<32>(str);
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -14,25 +14,37 @@
|
||||
|
||||
namespace Common {
|
||||
|
||||
u8 ToHexNibble(char c1);
|
||||
[[nodiscard]] constexpr u8 ToHexNibble(char c) {
|
||||
if (c >= 65 && c <= 70) {
|
||||
return c - 55;
|
||||
}
|
||||
|
||||
std::vector<u8> HexStringToVector(std::string_view str, bool little_endian);
|
||||
if (c >= 97 && c <= 102) {
|
||||
return c - 87;
|
||||
}
|
||||
|
||||
return c - 48;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<u8> HexStringToVector(std::string_view str, bool little_endian);
|
||||
|
||||
template <std::size_t Size, bool le = false>
|
||||
std::array<u8, Size> HexStringToArray(std::string_view str) {
|
||||
[[nodiscard]] constexpr std::array<u8, Size> HexStringToArray(std::string_view str) {
|
||||
std::array<u8, Size> out{};
|
||||
if constexpr (le) {
|
||||
for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2)
|
||||
for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) {
|
||||
out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
|
||||
}
|
||||
} else {
|
||||
for (std::size_t i = 0; i < 2 * Size; i += 2)
|
||||
for (std::size_t i = 0; i < 2 * Size; i += 2) {
|
||||
out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename ContiguousContainer>
|
||||
std::string HexToString(const ContiguousContainer& data, bool upper = true) {
|
||||
[[nodiscard]] std::string HexToString(const ContiguousContainer& data, bool upper = true) {
|
||||
static_assert(std::is_same_v<typename ContiguousContainer::value_type, u8>,
|
||||
"Underlying type within the contiguous container must be u8.");
|
||||
|
||||
@@ -48,7 +60,12 @@ std::string HexToString(const ContiguousContainer& data, bool upper = true) {
|
||||
return out;
|
||||
}
|
||||
|
||||
std::array<u8, 0x10> operator"" _array16(const char* str, std::size_t len);
|
||||
std::array<u8, 0x20> operator"" _array32(const char* str, std::size_t len);
|
||||
[[nodiscard]] constexpr std::array<u8, 16> AsArray(const char (&data)[17]) {
|
||||
return HexStringToArray<16>(data);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::array<u8, 32> AsArray(const char (&data)[65]) {
|
||||
return HexStringToArray<32>(data);
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -113,19 +113,19 @@ private:
|
||||
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
|
||||
const char* function, std::string message) const {
|
||||
using std::chrono::duration_cast;
|
||||
using std::chrono::microseconds;
|
||||
using std::chrono::steady_clock;
|
||||
|
||||
Entry entry;
|
||||
entry.timestamp =
|
||||
duration_cast<std::chrono::microseconds>(steady_clock::now() - time_origin);
|
||||
entry.log_class = log_class;
|
||||
entry.log_level = log_level;
|
||||
entry.filename = filename;
|
||||
entry.line_num = line_nr;
|
||||
entry.function = function;
|
||||
entry.message = std::move(message);
|
||||
|
||||
return entry;
|
||||
return {
|
||||
.timestamp = duration_cast<microseconds>(steady_clock::now() - time_origin),
|
||||
.log_class = log_class,
|
||||
.log_level = log_level,
|
||||
.filename = filename,
|
||||
.line_num = line_nr,
|
||||
.function = function,
|
||||
.message = std::move(message),
|
||||
.final_entry = false,
|
||||
};
|
||||
}
|
||||
|
||||
std::mutex writing_mutex;
|
||||
|
||||
@@ -21,19 +21,13 @@ class Filter;
|
||||
*/
|
||||
struct Entry {
|
||||
std::chrono::microseconds timestamp;
|
||||
Class log_class;
|
||||
Level log_level;
|
||||
const char* filename;
|
||||
unsigned int line_num;
|
||||
Class log_class{};
|
||||
Level log_level{};
|
||||
const char* filename = nullptr;
|
||||
unsigned int line_num = 0;
|
||||
std::string function;
|
||||
std::string message;
|
||||
bool final_entry = false;
|
||||
|
||||
Entry() = default;
|
||||
Entry(Entry&& o) = default;
|
||||
|
||||
Entry& operator=(Entry&& o) = default;
|
||||
Entry& operator=(const Entry& o) = default;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -100,7 +94,7 @@ public:
|
||||
void Write(const Entry& entry) override;
|
||||
|
||||
private:
|
||||
FileUtil::IOFile file;
|
||||
Common::FS::IOFile file;
|
||||
std::size_t bytes_written;
|
||||
};
|
||||
|
||||
|
||||
@@ -14,19 +14,19 @@ std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size) {
|
||||
ASSERT_MSG(source_size <= LZ4_MAX_INPUT_SIZE, "Source size exceeds LZ4 maximum input size");
|
||||
|
||||
const auto source_size_int = static_cast<int>(source_size);
|
||||
const int max_compressed_size = LZ4_compressBound(source_size_int);
|
||||
const auto max_compressed_size = static_cast<std::size_t>(LZ4_compressBound(source_size_int));
|
||||
std::vector<u8> compressed(max_compressed_size);
|
||||
|
||||
const int compressed_size = LZ4_compress_default(reinterpret_cast<const char*>(source),
|
||||
reinterpret_cast<char*>(compressed.data()),
|
||||
source_size_int, max_compressed_size);
|
||||
const int compressed_size = LZ4_compress_default(
|
||||
reinterpret_cast<const char*>(source), reinterpret_cast<char*>(compressed.data()),
|
||||
source_size_int, static_cast<int>(max_compressed_size));
|
||||
|
||||
if (compressed_size <= 0) {
|
||||
// Compression failed
|
||||
return {};
|
||||
}
|
||||
|
||||
compressed.resize(compressed_size);
|
||||
compressed.resize(static_cast<std::size_t>(compressed_size));
|
||||
|
||||
return compressed;
|
||||
}
|
||||
@@ -38,19 +38,19 @@ std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size,
|
||||
compression_level = std::clamp(compression_level, LZ4HC_CLEVEL_MIN, LZ4HC_CLEVEL_MAX);
|
||||
|
||||
const auto source_size_int = static_cast<int>(source_size);
|
||||
const int max_compressed_size = LZ4_compressBound(source_size_int);
|
||||
const auto max_compressed_size = static_cast<std::size_t>(LZ4_compressBound(source_size_int));
|
||||
std::vector<u8> compressed(max_compressed_size);
|
||||
|
||||
const int compressed_size = LZ4_compress_HC(
|
||||
reinterpret_cast<const char*>(source), reinterpret_cast<char*>(compressed.data()),
|
||||
source_size_int, max_compressed_size, compression_level);
|
||||
source_size_int, static_cast<int>(max_compressed_size), compression_level);
|
||||
|
||||
if (compressed_size <= 0) {
|
||||
// Compression failed
|
||||
return {};
|
||||
}
|
||||
|
||||
compressed.resize(compressed_size);
|
||||
compressed.resize(static_cast<std::size_t>(compressed_size));
|
||||
|
||||
return compressed;
|
||||
}
|
||||
|
||||
@@ -13,12 +13,12 @@ namespace Common::Compression {
|
||||
/**
|
||||
* Compresses a source memory region with LZ4 and returns the compressed data in a vector.
|
||||
*
|
||||
* @param source the uncompressed source memory region.
|
||||
* @param source_size the size in bytes of the uncompressed source memory region.
|
||||
* @param source The uncompressed source memory region.
|
||||
* @param source_size The size of the uncompressed source memory region.
|
||||
*
|
||||
* @return the compressed data.
|
||||
*/
|
||||
std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size);
|
||||
[[nodiscard]] std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size);
|
||||
|
||||
/**
|
||||
* Utilizes the LZ4 subalgorithm LZ4HC with the specified compression level. Higher compression
|
||||
@@ -26,23 +26,24 @@ std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size);
|
||||
* compression level has almost no impact on decompression speed. Data compressed with LZ4HC can
|
||||
* also be decompressed with the default LZ4 decompression.
|
||||
*
|
||||
* @param source the uncompressed source memory region.
|
||||
* @param source_size the size in bytes of the uncompressed source memory region.
|
||||
* @param compression_level the used compression level. Should be between 3 and 12.
|
||||
* @param source The uncompressed source memory region.
|
||||
* @param source_size The size of the uncompressed source memory region.
|
||||
* @param compression_level The used compression level. Should be between 3 and 12.
|
||||
*
|
||||
* @return the compressed data.
|
||||
*/
|
||||
std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size, s32 compression_level);
|
||||
[[nodiscard]] std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size,
|
||||
s32 compression_level);
|
||||
|
||||
/**
|
||||
* Utilizes the LZ4 subalgorithm LZ4HC with the highest possible compression level.
|
||||
*
|
||||
* @param source the uncompressed source memory region.
|
||||
* @param source_size the size in bytes of the uncompressed source memory region.
|
||||
* @param source The uncompressed source memory region.
|
||||
* @param source_size The size of the uncompressed source memory region
|
||||
*
|
||||
* @return the compressed data.
|
||||
*/
|
||||
std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size);
|
||||
[[nodiscard]] std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size);
|
||||
|
||||
/**
|
||||
* Decompresses a source memory region with LZ4 and returns the uncompressed data in a vector.
|
||||
@@ -52,6 +53,7 @@ std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size);
|
||||
*
|
||||
* @return the decompressed data.
|
||||
*/
|
||||
std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed, std::size_t uncompressed_size);
|
||||
[[nodiscard]] std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed,
|
||||
std::size_t uncompressed_size);
|
||||
|
||||
} // namespace Common::Compression
|
||||
@@ -23,7 +23,7 @@ struct Rectangle {
|
||||
constexpr Rectangle(T left, T top, T right, T bottom)
|
||||
: left(left), top(top), right(right), bottom(bottom) {}
|
||||
|
||||
T GetWidth() const {
|
||||
[[nodiscard]] T GetWidth() const {
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
return std::abs(right - left);
|
||||
} else {
|
||||
@@ -31,7 +31,7 @@ struct Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
T GetHeight() const {
|
||||
[[nodiscard]] T GetHeight() const {
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
return std::abs(bottom - top);
|
||||
} else {
|
||||
@@ -39,21 +39,21 @@ struct Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle<T> TranslateX(const T x) const {
|
||||
[[nodiscard]] Rectangle<T> TranslateX(const T x) const {
|
||||
return Rectangle{left + x, top, right + x, bottom};
|
||||
}
|
||||
|
||||
Rectangle<T> TranslateY(const T y) const {
|
||||
[[nodiscard]] Rectangle<T> TranslateY(const T y) const {
|
||||
return Rectangle{left, top + y, right, bottom + y};
|
||||
}
|
||||
|
||||
Rectangle<T> Scale(const float s) const {
|
||||
[[nodiscard]] Rectangle<T> Scale(const float s) const {
|
||||
return Rectangle{left, top, static_cast<T>(left + GetWidth() * s),
|
||||
static_cast<T>(top + GetHeight() * s)};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
Rectangle(T, T, T, T)->Rectangle<T>;
|
||||
Rectangle(T, T, T, T) -> Rectangle<T>;
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -17,6 +17,6 @@ struct MemoryInfo {
|
||||
* Gets the memory info of the host system
|
||||
* @return Reference to a MemoryInfo struct with the physical and swap memory sizes in bytes
|
||||
*/
|
||||
const MemoryInfo& GetMemInfo();
|
||||
[[nodiscard]] const MemoryInfo& GetMemInfo();
|
||||
|
||||
} // namespace Common
|
||||
@@ -223,15 +223,15 @@ public:
|
||||
ListShiftForward(levels[priority], n);
|
||||
}
|
||||
|
||||
std::size_t depth() const {
|
||||
[[nodiscard]] std::size_t depth() const {
|
||||
return Depth;
|
||||
}
|
||||
|
||||
std::size_t size(u32 priority) const {
|
||||
[[nodiscard]] std::size_t size(u32 priority) const {
|
||||
return levels[priority].size();
|
||||
}
|
||||
|
||||
std::size_t size() const {
|
||||
[[nodiscard]] std::size_t size() const {
|
||||
u64 priorities = used_priorities;
|
||||
std::size_t size = 0;
|
||||
while (priorities != 0) {
|
||||
@@ -242,64 +242,64 @@ public:
|
||||
return size;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
[[nodiscard]] bool empty() const {
|
||||
return used_priorities == 0;
|
||||
}
|
||||
|
||||
bool empty(u32 priority) const {
|
||||
[[nodiscard]] bool empty(u32 priority) const {
|
||||
return (used_priorities & (1ULL << priority)) == 0;
|
||||
}
|
||||
|
||||
u32 highest_priority_set(u32 max_priority = 0) const {
|
||||
[[nodiscard]] u32 highest_priority_set(u32 max_priority = 0) const {
|
||||
const u64 priorities =
|
||||
max_priority == 0 ? used_priorities : (used_priorities & ~((1ULL << max_priority) - 1));
|
||||
return priorities == 0 ? Depth : static_cast<u32>(CountTrailingZeroes64(priorities));
|
||||
}
|
||||
|
||||
u32 lowest_priority_set(u32 min_priority = Depth - 1) const {
|
||||
[[nodiscard]] u32 lowest_priority_set(u32 min_priority = Depth - 1) const {
|
||||
const u64 priorities = min_priority >= Depth - 1
|
||||
? used_priorities
|
||||
: (used_priorities & ((1ULL << (min_priority + 1)) - 1));
|
||||
return priorities == 0 ? Depth : 63 - CountLeadingZeroes64(priorities);
|
||||
}
|
||||
|
||||
const_iterator cbegin(u32 max_prio = 0) const {
|
||||
[[nodiscard]] const_iterator cbegin(u32 max_prio = 0) const {
|
||||
const u32 priority = highest_priority_set(max_prio);
|
||||
return priority == Depth ? cend()
|
||||
: const_iterator{*this, levels[priority].cbegin(), priority};
|
||||
}
|
||||
const_iterator begin(u32 max_prio = 0) const {
|
||||
[[nodiscard]] const_iterator begin(u32 max_prio = 0) const {
|
||||
return cbegin(max_prio);
|
||||
}
|
||||
iterator begin(u32 max_prio = 0) {
|
||||
[[nodiscard]] iterator begin(u32 max_prio = 0) {
|
||||
const u32 priority = highest_priority_set(max_prio);
|
||||
return priority == Depth ? end() : iterator{*this, levels[priority].begin(), priority};
|
||||
}
|
||||
|
||||
const_iterator cend(u32 min_prio = Depth - 1) const {
|
||||
[[nodiscard]] const_iterator cend(u32 min_prio = Depth - 1) const {
|
||||
return min_prio == Depth - 1 ? const_iterator{*this, Depth} : cbegin(min_prio + 1);
|
||||
}
|
||||
const_iterator end(u32 min_prio = Depth - 1) const {
|
||||
[[nodiscard]] const_iterator end(u32 min_prio = Depth - 1) const {
|
||||
return cend(min_prio);
|
||||
}
|
||||
iterator end(u32 min_prio = Depth - 1) {
|
||||
[[nodiscard]] iterator end(u32 min_prio = Depth - 1) {
|
||||
return min_prio == Depth - 1 ? iterator{*this, Depth} : begin(min_prio + 1);
|
||||
}
|
||||
|
||||
T& front(u32 max_priority = 0) {
|
||||
[[nodiscard]] T& front(u32 max_priority = 0) {
|
||||
const u32 priority = highest_priority_set(max_priority);
|
||||
return levels[priority == Depth ? 0 : priority].front();
|
||||
}
|
||||
const T& front(u32 max_priority = 0) const {
|
||||
[[nodiscard]] const T& front(u32 max_priority = 0) const {
|
||||
const u32 priority = highest_priority_set(max_priority);
|
||||
return levels[priority == Depth ? 0 : priority].front();
|
||||
}
|
||||
|
||||
T back(u32 min_priority = Depth - 1) {
|
||||
[[nodiscard]] T& back(u32 min_priority = Depth - 1) {
|
||||
const u32 priority = lowest_priority_set(min_priority); // intended
|
||||
return levels[priority == Depth ? 63 : priority].back();
|
||||
}
|
||||
const T& back(u32 min_priority = Depth - 1) const {
|
||||
[[nodiscard]] const T& back(u32 min_priority = Depth - 1) const {
|
||||
const u32 priority = lowest_priority_set(min_priority); // intended
|
||||
return levels[priority == Depth ? 63 : priority].back();
|
||||
}
|
||||
@@ -329,7 +329,8 @@ private:
|
||||
in_list.splice(position, out_list, element);
|
||||
}
|
||||
|
||||
static const_list_iterator ListIterateTo(const std::list<T>& list, const T& element) {
|
||||
[[nodiscard]] static const_list_iterator ListIterateTo(const std::list<T>& list,
|
||||
const T& element) {
|
||||
auto it = list.cbegin();
|
||||
while (it != list.cend() && *it != element) {
|
||||
++it;
|
||||
|
||||
@@ -36,11 +36,11 @@ struct SpecialRegion {
|
||||
|
||||
MemoryHookPointer handler;
|
||||
|
||||
bool operator<(const SpecialRegion& other) const {
|
||||
[[nodiscard]] bool operator<(const SpecialRegion& other) const {
|
||||
return std::tie(type, handler) < std::tie(other.type, other.handler);
|
||||
}
|
||||
|
||||
bool operator==(const SpecialRegion& other) const {
|
||||
[[nodiscard]] bool operator==(const SpecialRegion& other) const {
|
||||
return std::tie(type, handler) == std::tie(other.type, other.handler);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -24,14 +24,14 @@ public:
|
||||
ParamPackage& operator=(const ParamPackage& other) = default;
|
||||
ParamPackage& operator=(ParamPackage&& other) = default;
|
||||
|
||||
std::string Serialize() const;
|
||||
std::string Get(const std::string& key, const std::string& default_value) const;
|
||||
int Get(const std::string& key, int default_value) const;
|
||||
float Get(const std::string& key, float default_value) const;
|
||||
[[nodiscard]] std::string Serialize() const;
|
||||
[[nodiscard]] std::string Get(const std::string& key, const std::string& default_value) const;
|
||||
[[nodiscard]] int Get(const std::string& key, int default_value) const;
|
||||
[[nodiscard]] float Get(const std::string& key, float default_value) const;
|
||||
void Set(const std::string& key, std::string value);
|
||||
void Set(const std::string& key, int value);
|
||||
void Set(const std::string& key, float value);
|
||||
bool Has(const std::string& key) const;
|
||||
[[nodiscard]] bool Has(const std::string& key) const;
|
||||
void Erase(const std::string& key);
|
||||
void Clear();
|
||||
|
||||
|
||||
@@ -14,35 +14,36 @@ public:
|
||||
Vec3<T> xyz;
|
||||
T w{};
|
||||
|
||||
Quaternion<decltype(-T{})> Inverse() const {
|
||||
[[nodiscard]] Quaternion<decltype(-T{})> Inverse() const {
|
||||
return {-xyz, w};
|
||||
}
|
||||
|
||||
Quaternion<decltype(T{} + T{})> operator+(const Quaternion& other) const {
|
||||
[[nodiscard]] Quaternion<decltype(T{} + T{})> operator+(const Quaternion& other) const {
|
||||
return {xyz + other.xyz, w + other.w};
|
||||
}
|
||||
|
||||
Quaternion<decltype(T{} - T{})> operator-(const Quaternion& other) const {
|
||||
[[nodiscard]] Quaternion<decltype(T{} - T{})> operator-(const Quaternion& other) const {
|
||||
return {xyz - other.xyz, w - other.w};
|
||||
}
|
||||
|
||||
Quaternion<decltype(T{} * T{} - T{} * T{})> operator*(const Quaternion& other) const {
|
||||
[[nodiscard]] Quaternion<decltype(T{} * T{} - T{} * T{})> operator*(
|
||||
const Quaternion& other) const {
|
||||
return {xyz * other.w + other.xyz * w + Cross(xyz, other.xyz),
|
||||
w * other.w - Dot(xyz, other.xyz)};
|
||||
}
|
||||
|
||||
Quaternion<T> Normalized() const {
|
||||
[[nodiscard]] Quaternion<T> Normalized() const {
|
||||
T length = std::sqrt(xyz.Length2() + w * w);
|
||||
return {xyz / length, w / length};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
auto QuaternionRotate(const Quaternion<T>& q, const Vec3<T>& v) {
|
||||
[[nodiscard]] auto QuaternionRotate(const Quaternion<T>& q, const Vec3<T>& v) {
|
||||
return v + 2 * Cross(q.xyz, Cross(q.xyz, v) + v * q.w);
|
||||
}
|
||||
|
||||
inline Quaternion<float> MakeQuaternion(const Vec3<float>& axis, float angle) {
|
||||
[[nodiscard]] inline Quaternion<float> MakeQuaternion(const Vec3<float>& axis, float angle) {
|
||||
return {axis * std::sin(angle / 2), std::cos(angle / 2)};
|
||||
}
|
||||
|
||||
|
||||
@@ -91,12 +91,12 @@ public:
|
||||
}
|
||||
|
||||
/// @returns Number of slots used
|
||||
std::size_t Size() const {
|
||||
[[nodiscard]] std::size_t Size() const {
|
||||
return m_write_index.load() - m_read_index.load();
|
||||
}
|
||||
|
||||
/// @returns Maximum size of ring buffer
|
||||
constexpr std::size_t Capacity() const {
|
||||
[[nodiscard]] constexpr std::size_t Capacity() const {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ class SpinLock {
|
||||
public:
|
||||
void lock();
|
||||
void unlock();
|
||||
bool try_lock();
|
||||
[[nodiscard]] bool try_lock();
|
||||
|
||||
private:
|
||||
std::atomic_flag lck = ATOMIC_FLAG_INIT;
|
||||
|
||||
@@ -12,19 +12,19 @@
|
||||
namespace Common {
|
||||
|
||||
/// Make a string lowercase
|
||||
std::string ToLower(std::string str);
|
||||
[[nodiscard]] std::string ToLower(std::string str);
|
||||
|
||||
/// Make a string uppercase
|
||||
std::string ToUpper(std::string str);
|
||||
[[nodiscard]] std::string ToUpper(std::string str);
|
||||
|
||||
std::string StringFromBuffer(const std::vector<u8>& data);
|
||||
[[nodiscard]] std::string StringFromBuffer(const std::vector<u8>& data);
|
||||
|
||||
std::string StripSpaces(const std::string& s);
|
||||
std::string StripQuotes(const std::string& s);
|
||||
[[nodiscard]] std::string StripSpaces(const std::string& s);
|
||||
[[nodiscard]] std::string StripQuotes(const std::string& s);
|
||||
|
||||
std::string StringFromBool(bool value);
|
||||
[[nodiscard]] std::string StringFromBool(bool value);
|
||||
|
||||
std::string TabsToSpaces(int tab_size, std::string in);
|
||||
[[nodiscard]] std::string TabsToSpaces(int tab_size, std::string in);
|
||||
|
||||
void SplitString(const std::string& str, char delim, std::vector<std::string>& output);
|
||||
|
||||
@@ -34,14 +34,15 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
|
||||
|
||||
void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path,
|
||||
const std::string& _Filename);
|
||||
std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest);
|
||||
[[nodiscard]] std::string ReplaceAll(std::string result, const std::string& src,
|
||||
const std::string& dest);
|
||||
|
||||
std::string UTF16ToUTF8(const std::u16string& input);
|
||||
std::u16string UTF8ToUTF16(const std::string& input);
|
||||
[[nodiscard]] std::string UTF16ToUTF8(const std::u16string& input);
|
||||
[[nodiscard]] std::u16string UTF8ToUTF16(const std::string& input);
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string UTF16ToUTF8(const std::wstring& input);
|
||||
std::wstring UTF8ToUTF16W(const std::string& str);
|
||||
[[nodiscard]] std::string UTF16ToUTF8(const std::wstring& input);
|
||||
[[nodiscard]] std::wstring UTF8ToUTF16W(const std::string& str);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -50,7 +51,7 @@ std::wstring UTF8ToUTF16W(const std::string& str);
|
||||
* `other` for equality.
|
||||
*/
|
||||
template <typename InIt>
|
||||
bool ComparePartialString(InIt begin, InIt end, const char* other) {
|
||||
[[nodiscard]] bool ComparePartialString(InIt begin, InIt end, const char* other) {
|
||||
for (; begin != end && *other != '\0'; ++begin, ++other) {
|
||||
if (*begin != *other) {
|
||||
return false;
|
||||
@@ -64,14 +65,15 @@ bool ComparePartialString(InIt begin, InIt end, const char* other) {
|
||||
* Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't
|
||||
* NUL-terminated then the string ends at max_len characters.
|
||||
*/
|
||||
std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t max_len);
|
||||
[[nodiscard]] std::string StringFromFixedZeroTerminatedBuffer(const char* buffer,
|
||||
std::size_t max_len);
|
||||
|
||||
/**
|
||||
* Creates a UTF-16 std::u16string from a fixed-size NUL-terminated char buffer. If the buffer isn't
|
||||
* null-terminated, then the string ends at the greatest multiple of two less then or equal to
|
||||
* max_len_bytes.
|
||||
*/
|
||||
std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer,
|
||||
std::size_t max_len);
|
||||
[[nodiscard]] std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer,
|
||||
std::size_t max_len);
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "common/x64/cpu_detect.h"
|
||||
#endif
|
||||
|
||||
namespace Telemetry {
|
||||
namespace Common::Telemetry {
|
||||
|
||||
void FieldCollection::Accept(VisitorInterface& visitor) const {
|
||||
for (const auto& field : fields) {
|
||||
@@ -88,4 +88,4 @@ void AppendOSInfo(FieldCollection& fc) {
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Telemetry
|
||||
} // namespace Common::Telemetry
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <string>
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Telemetry {
|
||||
namespace Common::Telemetry {
|
||||
|
||||
/// Field type, used for grouping fields together in the final submitted telemetry log
|
||||
enum class FieldType : u8 {
|
||||
@@ -63,30 +63,30 @@ public:
|
||||
|
||||
void Accept(VisitorInterface& visitor) const override;
|
||||
|
||||
const std::string& GetName() const override {
|
||||
[[nodiscard]] const std::string& GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the field.
|
||||
*/
|
||||
FieldType GetType() const {
|
||||
[[nodiscard]] FieldType GetType() const {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the field.
|
||||
*/
|
||||
const T& GetValue() const {
|
||||
[[nodiscard]] const T& GetValue() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
bool operator==(const Field& other) const {
|
||||
[[nodiscard]] bool operator==(const Field& other) const {
|
||||
return (type == other.type) && (name == other.name) && (value == other.value);
|
||||
}
|
||||
|
||||
bool operator!=(const Field& other) const {
|
||||
return !(*this == other);
|
||||
[[nodiscard]] bool operator!=(const Field& other) const {
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -196,4 +196,4 @@ void AppendCPUInfo(FieldCollection& fc);
|
||||
/// such as platform name, etc.
|
||||
void AppendOSInfo(FieldCollection& fc);
|
||||
|
||||
} // namespace Telemetry
|
||||
} // namespace Common::Telemetry
|
||||
|
||||
@@ -18,14 +18,14 @@ struct ThreadQueueList {
|
||||
using Priority = unsigned int;
|
||||
|
||||
// Number of priority levels. (Valid levels are [0..NUM_QUEUES).)
|
||||
static const Priority NUM_QUEUES = N;
|
||||
static constexpr Priority NUM_QUEUES = N;
|
||||
|
||||
ThreadQueueList() {
|
||||
first = nullptr;
|
||||
}
|
||||
|
||||
// Only for debugging, returns priority level.
|
||||
Priority contains(const T& uid) const {
|
||||
[[nodiscard]] Priority contains(const T& uid) const {
|
||||
for (Priority i = 0; i < NUM_QUEUES; ++i) {
|
||||
const Queue& cur = queues[i];
|
||||
if (std::find(cur.data.cbegin(), cur.data.cend(), uid) != cur.data.cend()) {
|
||||
@@ -36,7 +36,7 @@ struct ThreadQueueList {
|
||||
return -1;
|
||||
}
|
||||
|
||||
T get_first() const {
|
||||
[[nodiscard]] T get_first() const {
|
||||
const Queue* cur = first;
|
||||
while (cur != nullptr) {
|
||||
if (!cur->data.empty()) {
|
||||
@@ -49,7 +49,7 @@ struct ThreadQueueList {
|
||||
}
|
||||
|
||||
template <typename UnaryPredicate>
|
||||
T get_first_filter(UnaryPredicate filter) const {
|
||||
[[nodiscard]] T get_first_filter(UnaryPredicate filter) const {
|
||||
const Queue* cur = first;
|
||||
while (cur != nullptr) {
|
||||
if (!cur->data.empty()) {
|
||||
@@ -129,7 +129,7 @@ struct ThreadQueueList {
|
||||
first = nullptr;
|
||||
}
|
||||
|
||||
bool empty(Priority priority) const {
|
||||
[[nodiscard]] bool empty(Priority priority) const {
|
||||
const Queue* cur = &queues[priority];
|
||||
return cur->data.empty();
|
||||
}
|
||||
|
||||
@@ -25,15 +25,15 @@ public:
|
||||
delete read_ptr;
|
||||
}
|
||||
|
||||
std::size_t Size() const {
|
||||
[[nodiscard]] std::size_t Size() const {
|
||||
return size.load();
|
||||
}
|
||||
|
||||
bool Empty() const {
|
||||
[[nodiscard]] bool Empty() const {
|
||||
return Size() == 0;
|
||||
}
|
||||
|
||||
T& Front() const {
|
||||
[[nodiscard]] T& Front() const {
|
||||
return read_ptr->current;
|
||||
}
|
||||
|
||||
@@ -130,15 +130,15 @@ private:
|
||||
template <typename T>
|
||||
class MPSCQueue {
|
||||
public:
|
||||
std::size_t Size() const {
|
||||
[[nodiscard]] std::size_t Size() const {
|
||||
return spsc_queue.Size();
|
||||
}
|
||||
|
||||
bool Empty() const {
|
||||
[[nodiscard]] bool Empty() const {
|
||||
return spsc_queue.Empty();
|
||||
}
|
||||
|
||||
T& Front() const {
|
||||
[[nodiscard]] T& Front() const {
|
||||
return spsc_queue.Front();
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
namespace Common::TimeZone {
|
||||
|
||||
/// Gets the default timezone, i.e. "GMT"
|
||||
std::string GetDefaultTimeZone();
|
||||
[[nodiscard]] std::string GetDefaultTimeZone();
|
||||
|
||||
/// Gets the offset of the current timezone (from the default), in seconds
|
||||
std::chrono::seconds GetCurrentOffsetSeconds();
|
||||
[[nodiscard]] std::chrono::seconds GetCurrentOffsetSeconds();
|
||||
|
||||
} // namespace Common::TimeZone
|
||||
|
||||
@@ -19,18 +19,18 @@ public:
|
||||
|
||||
// The time difference is always returned in milliseconds, regardless of alternative internal
|
||||
// representation
|
||||
std::chrono::milliseconds GetTimeDifference();
|
||||
[[nodiscard]] std::chrono::milliseconds GetTimeDifference();
|
||||
void AddTimeDifference();
|
||||
|
||||
static std::chrono::seconds GetTimeSinceJan1970();
|
||||
static std::chrono::seconds GetLocalTimeSinceJan1970();
|
||||
static double GetDoubleTime();
|
||||
[[nodiscard]] static std::chrono::seconds GetTimeSinceJan1970();
|
||||
[[nodiscard]] static std::chrono::seconds GetLocalTimeSinceJan1970();
|
||||
[[nodiscard]] static double GetDoubleTime();
|
||||
|
||||
static std::string GetTimeFormatted();
|
||||
std::string GetTimeElapsedFormatted() const;
|
||||
std::chrono::milliseconds GetTimeElapsed();
|
||||
[[nodiscard]] static std::string GetTimeFormatted();
|
||||
[[nodiscard]] std::string GetTimeElapsedFormatted() const;
|
||||
[[nodiscard]] std::chrono::milliseconds GetTimeElapsed();
|
||||
|
||||
static std::chrono::milliseconds GetTimeMs();
|
||||
[[nodiscard]] static std::chrono::milliseconds GetTimeMs();
|
||||
|
||||
private:
|
||||
std::chrono::milliseconds m_LastTime;
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
namespace Common {
|
||||
|
||||
// This function multiplies 2 u64 values and divides it by a u64 value.
|
||||
u64 MultiplyAndDivide64(u64 a, u64 b, u64 d);
|
||||
[[nodiscard]] u64 MultiplyAndDivide64(u64 a, u64 b, u64 d);
|
||||
|
||||
// This function multiplies 2 u64 values and produces a u128 value;
|
||||
u128 Multiply64Into128(u64 a, u64 b);
|
||||
[[nodiscard]] u128 Multiply64Into128(u64 a, u64 b);
|
||||
|
||||
// This function divides a u128 by a u32 value and produces two u64 values:
|
||||
// the result of division and the remainder
|
||||
std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor);
|
||||
[[nodiscard]] std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor);
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -19,21 +19,21 @@ struct UUID {
|
||||
constexpr explicit UUID(const u128& id) : uuid{id} {}
|
||||
constexpr explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {}
|
||||
|
||||
constexpr explicit operator bool() const {
|
||||
[[nodiscard]] constexpr explicit operator bool() const {
|
||||
return uuid[0] != INVALID_UUID[0] && uuid[1] != INVALID_UUID[1];
|
||||
}
|
||||
|
||||
constexpr bool operator==(const UUID& rhs) const {
|
||||
[[nodiscard]] constexpr bool operator==(const UUID& rhs) const {
|
||||
// TODO(DarkLordZach): Replace with uuid == rhs.uuid with C++20
|
||||
return uuid[0] == rhs.uuid[0] && uuid[1] == rhs.uuid[1];
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const UUID& rhs) const {
|
||||
[[nodiscard]] constexpr bool operator!=(const UUID& rhs) const {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
// TODO(ogniK): Properly generate uuids based on RFC-4122
|
||||
static UUID Generate();
|
||||
[[nodiscard]] static UUID Generate();
|
||||
|
||||
// Set the UUID to {0,0} to be considered an invalid user
|
||||
constexpr void Invalidate() {
|
||||
@@ -41,12 +41,12 @@ struct UUID {
|
||||
}
|
||||
|
||||
// TODO(ogniK): Properly generate a Nintendo ID
|
||||
constexpr u64 GetNintendoID() const {
|
||||
[[nodiscard]] constexpr u64 GetNintendoID() const {
|
||||
return uuid[0];
|
||||
}
|
||||
|
||||
std::string Format() const;
|
||||
std::string FormatSwitch() const;
|
||||
[[nodiscard]] std::string Format() const;
|
||||
[[nodiscard]] std::string FormatSwitch() const;
|
||||
};
|
||||
static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
|
||||
|
||||
|
||||
@@ -52,15 +52,15 @@ public:
|
||||
constexpr Vec2(const T& x_, const T& y_) : x(x_), y(y_) {}
|
||||
|
||||
template <typename T2>
|
||||
constexpr Vec2<T2> Cast() const {
|
||||
[[nodiscard]] constexpr Vec2<T2> Cast() const {
|
||||
return Vec2<T2>(static_cast<T2>(x), static_cast<T2>(y));
|
||||
}
|
||||
|
||||
static constexpr Vec2 AssignToAll(const T& f) {
|
||||
[[nodiscard]] static constexpr Vec2 AssignToAll(const T& f) {
|
||||
return Vec2{f, f};
|
||||
}
|
||||
|
||||
constexpr Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const {
|
||||
[[nodiscard]] constexpr Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const {
|
||||
return {x + other.x, y + other.y};
|
||||
}
|
||||
constexpr Vec2& operator+=(const Vec2& other) {
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
y += other.y;
|
||||
return *this;
|
||||
}
|
||||
constexpr Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const {
|
||||
[[nodiscard]] constexpr Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const {
|
||||
return {x - other.x, y - other.y};
|
||||
}
|
||||
constexpr Vec2& operator-=(const Vec2& other) {
|
||||
@@ -78,15 +78,15 @@ public:
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
constexpr Vec2<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
|
||||
[[nodiscard]] constexpr Vec2<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
|
||||
return {-x, -y};
|
||||
}
|
||||
constexpr Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const {
|
||||
[[nodiscard]] constexpr Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const {
|
||||
return {x * other.x, y * other.y};
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const {
|
||||
[[nodiscard]] constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const {
|
||||
return {x * f, y * f};
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const {
|
||||
[[nodiscard]] constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const {
|
||||
return {x / f, y / f};
|
||||
}
|
||||
|
||||
@@ -107,18 +107,18 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr T Length2() const {
|
||||
[[nodiscard]] constexpr T Length2() const {
|
||||
return x * x + y * y;
|
||||
}
|
||||
|
||||
// Only implemented for T=float
|
||||
float Length() const;
|
||||
float Normalize(); // returns the previous length, which is often useful
|
||||
[[nodiscard]] float Length() const;
|
||||
[[nodiscard]] float Normalize(); // returns the previous length, which is often useful
|
||||
|
||||
constexpr T& operator[](std::size_t i) {
|
||||
[[nodiscard]] constexpr T& operator[](std::size_t i) {
|
||||
return *((&x) + i);
|
||||
}
|
||||
constexpr const T& operator[](std::size_t i) const {
|
||||
[[nodiscard]] constexpr const T& operator[](std::size_t i) const {
|
||||
return *((&x) + i);
|
||||
}
|
||||
|
||||
@@ -128,46 +128,46 @@ public:
|
||||
}
|
||||
|
||||
// Common aliases: UV (texel coordinates), ST (texture coordinates)
|
||||
constexpr T& u() {
|
||||
[[nodiscard]] constexpr T& u() {
|
||||
return x;
|
||||
}
|
||||
constexpr T& v() {
|
||||
[[nodiscard]] constexpr T& v() {
|
||||
return y;
|
||||
}
|
||||
constexpr T& s() {
|
||||
[[nodiscard]] constexpr T& s() {
|
||||
return x;
|
||||
}
|
||||
constexpr T& t() {
|
||||
[[nodiscard]] constexpr T& t() {
|
||||
return y;
|
||||
}
|
||||
|
||||
constexpr const T& u() const {
|
||||
[[nodiscard]] constexpr const T& u() const {
|
||||
return x;
|
||||
}
|
||||
constexpr const T& v() const {
|
||||
[[nodiscard]] constexpr const T& v() const {
|
||||
return y;
|
||||
}
|
||||
constexpr const T& s() const {
|
||||
[[nodiscard]] constexpr const T& s() const {
|
||||
return x;
|
||||
}
|
||||
constexpr const T& t() const {
|
||||
[[nodiscard]] constexpr const T& t() const {
|
||||
return y;
|
||||
}
|
||||
|
||||
// swizzlers - create a subvector of specific components
|
||||
constexpr Vec2 yx() const {
|
||||
[[nodiscard]] constexpr Vec2 yx() const {
|
||||
return Vec2(y, x);
|
||||
}
|
||||
constexpr Vec2 vu() const {
|
||||
[[nodiscard]] constexpr Vec2 vu() const {
|
||||
return Vec2(y, x);
|
||||
}
|
||||
constexpr Vec2 ts() const {
|
||||
[[nodiscard]] constexpr Vec2 ts() const {
|
||||
return Vec2(y, x);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename V>
|
||||
constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) {
|
||||
[[nodiscard]] constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) {
|
||||
return Vec2<T>(f * vec.x, f * vec.y);
|
||||
}
|
||||
|
||||
@@ -196,15 +196,15 @@ public:
|
||||
constexpr Vec3(const T& x_, const T& y_, const T& z_) : x(x_), y(y_), z(z_) {}
|
||||
|
||||
template <typename T2>
|
||||
constexpr Vec3<T2> Cast() const {
|
||||
[[nodiscard]] constexpr Vec3<T2> Cast() const {
|
||||
return Vec3<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z));
|
||||
}
|
||||
|
||||
static constexpr Vec3 AssignToAll(const T& f) {
|
||||
[[nodiscard]] static constexpr Vec3 AssignToAll(const T& f) {
|
||||
return Vec3(f, f, f);
|
||||
}
|
||||
|
||||
constexpr Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const {
|
||||
[[nodiscard]] constexpr Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const {
|
||||
return {x + other.x, y + other.y, z + other.z};
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const {
|
||||
[[nodiscard]] constexpr Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const {
|
||||
return {x - other.x, y - other.y, z - other.z};
|
||||
}
|
||||
|
||||
@@ -227,16 +227,16 @@ public:
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
constexpr Vec3<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
|
||||
[[nodiscard]] constexpr Vec3<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
|
||||
return {-x, -y, -z};
|
||||
}
|
||||
|
||||
constexpr Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const {
|
||||
[[nodiscard]] constexpr Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const {
|
||||
return {x * other.x, y * other.y, z * other.z};
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const {
|
||||
[[nodiscard]] constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const {
|
||||
return {x * f, y * f, z * f};
|
||||
}
|
||||
|
||||
@@ -246,7 +246,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
template <typename V>
|
||||
constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const {
|
||||
[[nodiscard]] constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const {
|
||||
return {x / f, y / f, z / f};
|
||||
}
|
||||
|
||||
@@ -256,20 +256,20 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr T Length2() const {
|
||||
[[nodiscard]] constexpr T Length2() const {
|
||||
return x * x + y * y + z * z;
|
||||
}
|
||||
|
||||
// Only implemented for T=float
|
||||
float Length() const;
|
||||
Vec3 Normalized() const;
|
||||
float Normalize(); // returns the previous length, which is often useful
|
||||
[[nodiscard]] float Length() const;
|
||||
[[nodiscard]] Vec3 Normalized() const;
|
||||
[[nodiscard]] float Normalize(); // returns the previous length, which is often useful
|
||||
|
||||
constexpr T& operator[](std::size_t i) {
|
||||
[[nodiscard]] constexpr T& operator[](std::size_t i) {
|
||||
return *((&x) + i);
|
||||
}
|
||||
|
||||
constexpr const T& operator[](std::size_t i) const {
|
||||
[[nodiscard]] constexpr const T& operator[](std::size_t i) const {
|
||||
return *((&x) + i);
|
||||
}
|
||||
|
||||
@@ -280,63 +280,63 @@ public:
|
||||
}
|
||||
|
||||
// Common aliases: UVW (texel coordinates), RGB (colors), STQ (texture coordinates)
|
||||
constexpr T& u() {
|
||||
[[nodiscard]] constexpr T& u() {
|
||||
return x;
|
||||
}
|
||||
constexpr T& v() {
|
||||
[[nodiscard]] constexpr T& v() {
|
||||
return y;
|
||||
}
|
||||
constexpr T& w() {
|
||||
[[nodiscard]] constexpr T& w() {
|
||||
return z;
|
||||
}
|
||||
|
||||
constexpr T& r() {
|
||||
[[nodiscard]] constexpr T& r() {
|
||||
return x;
|
||||
}
|
||||
constexpr T& g() {
|
||||
[[nodiscard]] constexpr T& g() {
|
||||
return y;
|
||||
}
|
||||
constexpr T& b() {
|
||||
[[nodiscard]] constexpr T& b() {
|
||||
return z;
|
||||
}
|
||||
|
||||
constexpr T& s() {
|
||||
[[nodiscard]] constexpr T& s() {
|
||||
return x;
|
||||
}
|
||||
constexpr T& t() {
|
||||
[[nodiscard]] constexpr T& t() {
|
||||
return y;
|
||||
}
|
||||
constexpr T& q() {
|
||||
[[nodiscard]] constexpr T& q() {
|
||||
return z;
|
||||
}
|
||||
|
||||
constexpr const T& u() const {
|
||||
[[nodiscard]] constexpr const T& u() const {
|
||||
return x;
|
||||
}
|
||||
constexpr const T& v() const {
|
||||
[[nodiscard]] constexpr const T& v() const {
|
||||
return y;
|
||||
}
|
||||
constexpr const T& w() const {
|
||||
[[nodiscard]] constexpr const T& w() const {
|
||||
return z;
|
||||
}
|
||||
|
||||
constexpr const T& r() const {
|
||||
[[nodiscard]] constexpr const T& r() const {
|
||||
return x;
|
||||
}
|
||||
constexpr const T& g() const {
|
||||
[[nodiscard]] constexpr const T& g() const {
|
||||
return y;
|
||||
}
|
||||
constexpr const T& b() const {
|
||||
[[nodiscard]] constexpr const T& b() const {
|
||||
return z;
|
||||
}
|
||||
|
||||
constexpr const T& s() const {
|
||||
[[nodiscard]] constexpr const T& s() const {
|
||||
return x;
|
||||
}
|
||||
constexpr const T& t() const {
|
||||
[[nodiscard]] constexpr const T& t() const {
|
||||
return y;
|
||||
}
|
||||
constexpr const T& q() const {
|
||||
[[nodiscard]] constexpr const T& q() const {
|
||||
return z;
|
||||
}
|
||||
|
||||
@@ -345,7 +345,7 @@ public:
|
||||
// _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all
|
||||
// component names (x<->r) and permutations (xy<->yx)
|
||||
#define _DEFINE_SWIZZLER2(a, b, name) \
|
||||
constexpr Vec2<T> name() const { \
|
||||
[[nodiscard]] constexpr Vec2<T> name() const { \
|
||||
return Vec2<T>(a, b); \
|
||||
}
|
||||
#define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \
|
||||
@@ -366,7 +366,7 @@ public:
|
||||
};
|
||||
|
||||
template <typename T, typename V>
|
||||
constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) {
|
||||
[[nodiscard]] constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) {
|
||||
return Vec3<T>(f * vec.x, f * vec.y, f * vec.z);
|
||||
}
|
||||
|
||||
@@ -402,16 +402,16 @@ public:
|
||||
: x(x_), y(y_), z(z_), w(w_) {}
|
||||
|
||||
template <typename T2>
|
||||
constexpr Vec4<T2> Cast() const {
|
||||
[[nodiscard]] constexpr Vec4<T2> Cast() const {
|
||||
return Vec4<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z),
|
||||
static_cast<T2>(w));
|
||||
}
|
||||
|
||||
static constexpr Vec4 AssignToAll(const T& f) {
|
||||
[[nodiscard]] static constexpr Vec4 AssignToAll(const T& f) {
|
||||
return Vec4(f, f, f, f);
|
||||
}
|
||||
|
||||
constexpr Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const {
|
||||
[[nodiscard]] constexpr Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const {
|
||||
return {x + other.x, y + other.y, z + other.z, w + other.w};
|
||||
}
|
||||
|
||||
@@ -423,7 +423,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const {
|
||||
[[nodiscard]] constexpr Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const {
|
||||
return {x - other.x, y - other.y, z - other.z, w - other.w};
|
||||
}
|
||||
|
||||
@@ -436,16 +436,16 @@ public:
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
constexpr Vec4<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
|
||||
[[nodiscard]] constexpr Vec4<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
|
||||
return {-x, -y, -z, -w};
|
||||
}
|
||||
|
||||
constexpr Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const {
|
||||
[[nodiscard]] constexpr Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const {
|
||||
return {x * other.x, y * other.y, z * other.z, w * other.w};
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const {
|
||||
[[nodiscard]] constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const {
|
||||
return {x * f, y * f, z * f, w * f};
|
||||
}
|
||||
|
||||
@@ -456,7 +456,7 @@ public:
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const {
|
||||
[[nodiscard]] constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const {
|
||||
return {x / f, y / f, z / f, w / f};
|
||||
}
|
||||
|
||||
@@ -466,15 +466,15 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr T Length2() const {
|
||||
[[nodiscard]] constexpr T Length2() const {
|
||||
return x * x + y * y + z * z + w * w;
|
||||
}
|
||||
|
||||
constexpr T& operator[](std::size_t i) {
|
||||
[[nodiscard]] constexpr T& operator[](std::size_t i) {
|
||||
return *((&x) + i);
|
||||
}
|
||||
|
||||
constexpr const T& operator[](std::size_t i) const {
|
||||
[[nodiscard]] constexpr const T& operator[](std::size_t i) const {
|
||||
return *((&x) + i);
|
||||
}
|
||||
|
||||
@@ -486,29 +486,29 @@ public:
|
||||
}
|
||||
|
||||
// Common alias: RGBA (colors)
|
||||
constexpr T& r() {
|
||||
[[nodiscard]] constexpr T& r() {
|
||||
return x;
|
||||
}
|
||||
constexpr T& g() {
|
||||
[[nodiscard]] constexpr T& g() {
|
||||
return y;
|
||||
}
|
||||
constexpr T& b() {
|
||||
[[nodiscard]] constexpr T& b() {
|
||||
return z;
|
||||
}
|
||||
constexpr T& a() {
|
||||
[[nodiscard]] constexpr T& a() {
|
||||
return w;
|
||||
}
|
||||
|
||||
constexpr const T& r() const {
|
||||
[[nodiscard]] constexpr const T& r() const {
|
||||
return x;
|
||||
}
|
||||
constexpr const T& g() const {
|
||||
[[nodiscard]] constexpr const T& g() const {
|
||||
return y;
|
||||
}
|
||||
constexpr const T& b() const {
|
||||
[[nodiscard]] constexpr const T& b() const {
|
||||
return z;
|
||||
}
|
||||
constexpr const T& a() const {
|
||||
[[nodiscard]] constexpr const T& a() const {
|
||||
return w;
|
||||
}
|
||||
|
||||
@@ -520,7 +520,7 @@ public:
|
||||
// DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and
|
||||
// permutations (xy<->yx)
|
||||
#define _DEFINE_SWIZZLER2(a, b, name) \
|
||||
constexpr Vec2<T> name() const { \
|
||||
[[nodiscard]] constexpr Vec2<T> name() const { \
|
||||
return Vec2<T>(a, b); \
|
||||
}
|
||||
#define DEFINE_SWIZZLER2_COMP1(a, a2) \
|
||||
@@ -547,7 +547,7 @@ public:
|
||||
#undef _DEFINE_SWIZZLER2
|
||||
|
||||
#define _DEFINE_SWIZZLER3(a, b, c, name) \
|
||||
constexpr Vec3<T> name() const { \
|
||||
[[nodiscard]] constexpr Vec3<T> name() const { \
|
||||
return Vec3<T>(a, b, c); \
|
||||
}
|
||||
#define DEFINE_SWIZZLER3_COMP1(a, a2) \
|
||||
@@ -581,7 +581,7 @@ public:
|
||||
};
|
||||
|
||||
template <typename T, typename V>
|
||||
constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) {
|
||||
[[nodiscard]] constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) {
|
||||
return {f * vec.x, f * vec.y, f * vec.z, f * vec.w};
|
||||
}
|
||||
|
||||
@@ -593,39 +593,41 @@ constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec2<T>& a, const Vec2<T>& b
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) {
|
||||
[[nodiscard]] constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) {
|
||||
return a.x * b.x + a.y * b.y + a.z * b.z;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) {
|
||||
[[nodiscard]] constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) {
|
||||
return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a, const Vec3<T>& b) {
|
||||
[[nodiscard]] constexpr Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a,
|
||||
const Vec3<T>& b) {
|
||||
return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
|
||||
}
|
||||
|
||||
// linear interpolation via float: 0.0=begin, 1.0=end
|
||||
template <typename X>
|
||||
constexpr decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end,
|
||||
const float t) {
|
||||
[[nodiscard]] constexpr decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end,
|
||||
const float t) {
|
||||
return begin * (1.f - t) + end * t;
|
||||
}
|
||||
|
||||
// linear interpolation via int: 0=begin, base=end
|
||||
template <typename X, int base>
|
||||
constexpr decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin, const X& end,
|
||||
const int t) {
|
||||
[[nodiscard]] constexpr decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin,
|
||||
const X& end,
|
||||
const int t) {
|
||||
return (begin * (base - t) + end * t) / base;
|
||||
}
|
||||
|
||||
// bilinear interpolation. s is for interpolating x00-x01 and x10-x11, and t is for the second
|
||||
// interpolation.
|
||||
template <typename X>
|
||||
constexpr auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x11, const float s,
|
||||
const float t) {
|
||||
[[nodiscard]] constexpr auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x11,
|
||||
const float s, const float t) {
|
||||
auto y0 = Lerp(x00, x01, s);
|
||||
auto y1 = Lerp(x10, x11, s);
|
||||
return Lerp(y0, y1, t);
|
||||
@@ -633,42 +635,42 @@ constexpr auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X&
|
||||
|
||||
// Utility vector factories
|
||||
template <typename T>
|
||||
constexpr Vec2<T> MakeVec(const T& x, const T& y) {
|
||||
[[nodiscard]] constexpr Vec2<T> MakeVec(const T& x, const T& y) {
|
||||
return Vec2<T>{x, y};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr Vec3<T> MakeVec(const T& x, const T& y, const T& z) {
|
||||
[[nodiscard]] constexpr Vec3<T> MakeVec(const T& x, const T& y, const T& z) {
|
||||
return Vec3<T>{x, y, z};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) {
|
||||
[[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) {
|
||||
return MakeVec(x, y, zw[0], zw[1]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) {
|
||||
[[nodiscard]] constexpr Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) {
|
||||
return MakeVec(xy[0], xy[1], z);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) {
|
||||
[[nodiscard]] constexpr Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) {
|
||||
return MakeVec(x, yz[0], yz[1]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) {
|
||||
[[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) {
|
||||
return Vec4<T>{x, y, z, w};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) {
|
||||
[[nodiscard]] constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) {
|
||||
return MakeVec(xy[0], xy[1], z, w);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) {
|
||||
[[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) {
|
||||
return MakeVec(x, yz[0], yz[1], w);
|
||||
}
|
||||
|
||||
@@ -676,17 +678,17 @@ constexpr Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) {
|
||||
// Even if someone wanted to use an odd object like Vec2<Vec2<T>>, the compiler would error
|
||||
// out soon enough due to misuse of the returned structure.
|
||||
template <typename T>
|
||||
constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) {
|
||||
[[nodiscard]] constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) {
|
||||
return MakeVec(xy[0], xy[1], zw[0], zw[1]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) {
|
||||
[[nodiscard]] constexpr Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) {
|
||||
return MakeVec(xyz[0], xyz[1], xyz[2], w);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) {
|
||||
[[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) {
|
||||
return MakeVec(x, yzw[0], yzw[1], yzw[2]);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,16 +5,7 @@
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#if defined __APPLE__ || defined __FreeBSD__ || defined __OpenBSD__
|
||||
#include <sys/sysctl.h>
|
||||
#elif defined __HAIKU__
|
||||
#include <OS.h>
|
||||
#else
|
||||
#include <sys/sysinfo.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "common/assert.h"
|
||||
|
||||
@@ -30,23 +30,23 @@ public:
|
||||
base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
|
||||
}
|
||||
|
||||
constexpr const T& operator[](std::size_t index) const {
|
||||
[[nodiscard]] constexpr const T& operator[](std::size_t index) const {
|
||||
return base_ptr[index];
|
||||
}
|
||||
|
||||
constexpr T& operator[](std::size_t index) {
|
||||
[[nodiscard]] constexpr T& operator[](std::size_t index) {
|
||||
return base_ptr[index];
|
||||
}
|
||||
|
||||
constexpr T* data() {
|
||||
[[nodiscard]] constexpr T* data() {
|
||||
return base_ptr;
|
||||
}
|
||||
|
||||
constexpr const T* data() const {
|
||||
[[nodiscard]] constexpr const T* data() const {
|
||||
return base_ptr;
|
||||
}
|
||||
|
||||
constexpr std::size_t size() const {
|
||||
[[nodiscard]] constexpr std::size_t size() const {
|
||||
return alloc_size / sizeof(T);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,24 +14,24 @@ namespace Common {
|
||||
class WallClock {
|
||||
public:
|
||||
/// Returns current wall time in nanoseconds
|
||||
virtual std::chrono::nanoseconds GetTimeNS() = 0;
|
||||
[[nodiscard]] virtual std::chrono::nanoseconds GetTimeNS() = 0;
|
||||
|
||||
/// Returns current wall time in microseconds
|
||||
virtual std::chrono::microseconds GetTimeUS() = 0;
|
||||
[[nodiscard]] virtual std::chrono::microseconds GetTimeUS() = 0;
|
||||
|
||||
/// Returns current wall time in milliseconds
|
||||
virtual std::chrono::milliseconds GetTimeMS() = 0;
|
||||
[[nodiscard]] virtual std::chrono::milliseconds GetTimeMS() = 0;
|
||||
|
||||
/// Returns current wall time in emulated clock cycles
|
||||
virtual u64 GetClockCycles() = 0;
|
||||
[[nodiscard]] virtual u64 GetClockCycles() = 0;
|
||||
|
||||
/// Returns current wall time in emulated cpu cycles
|
||||
virtual u64 GetCPUCycles() = 0;
|
||||
[[nodiscard]] virtual u64 GetCPUCycles() = 0;
|
||||
|
||||
virtual void Pause(bool is_paused) = 0;
|
||||
|
||||
/// Tells if the wall clock, uses the host CPU's hardware clock
|
||||
bool IsNative() const {
|
||||
[[nodiscard]] bool IsNative() const {
|
||||
return is_native;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ private:
|
||||
bool is_native;
|
||||
};
|
||||
|
||||
std::unique_ptr<WallClock> CreateBestMatchingClock(u32 emulated_cpu_frequency,
|
||||
u32 emulated_clock_frequency);
|
||||
[[nodiscard]] std::unique_ptr<WallClock> CreateBestMatchingClock(u32 emulated_cpu_frequency,
|
||||
u32 emulated_clock_frequency);
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <algorithm>
|
||||
#include <zstd.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/zstd_compression.h"
|
||||
|
||||
namespace Common::Compression {
|
||||
|
||||
@@ -13,24 +13,25 @@ namespace Common::Compression {
|
||||
/**
|
||||
* Compresses a source memory region with Zstandard and returns the compressed data in a vector.
|
||||
*
|
||||
* @param source the uncompressed source memory region.
|
||||
* @param source_size the size in bytes of the uncompressed source memory region.
|
||||
* @param compression_level the used compression level. Should be between 1 and 22.
|
||||
* @param source The uncompressed source memory region.
|
||||
* @param source_size The size of the uncompressed source memory region.
|
||||
* @param compression_level The used compression level. Should be between 1 and 22.
|
||||
*
|
||||
* @return the compressed data.
|
||||
*/
|
||||
std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size, s32 compression_level);
|
||||
[[nodiscard]] std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size,
|
||||
s32 compression_level);
|
||||
|
||||
/**
|
||||
* Compresses a source memory region with Zstandard with the default compression level and returns
|
||||
* the compressed data in a vector.
|
||||
*
|
||||
* @param source the uncompressed source memory region.
|
||||
* @param source_size the size in bytes of the uncompressed source memory region.
|
||||
* @param source The uncompressed source memory region.
|
||||
* @param source_size The size of the uncompressed source memory region.
|
||||
*
|
||||
* @return the compressed data.
|
||||
*/
|
||||
std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_size);
|
||||
[[nodiscard]] std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_size);
|
||||
|
||||
/**
|
||||
* Decompresses a source memory region with Zstandard and returns the uncompressed data in a vector.
|
||||
@@ -39,6 +40,6 @@ std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_siz
|
||||
*
|
||||
* @return the decompressed data.
|
||||
*/
|
||||
std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed);
|
||||
[[nodiscard]] std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed);
|
||||
|
||||
} // namespace Common::Compression
|
||||
@@ -143,7 +143,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
|
||||
config.wall_clock_cntpct = uses_wall_clock;
|
||||
|
||||
// Safe optimizations
|
||||
if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) {
|
||||
if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
|
||||
if (!Settings::values.cpuopt_page_tables) {
|
||||
config.page_table = nullptr;
|
||||
}
|
||||
@@ -170,6 +170,17 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe optimizations
|
||||
if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::Unsafe) {
|
||||
config.unsafe_optimizations = true;
|
||||
if (Settings::values.cpuopt_unsafe_unfuse_fma) {
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
|
||||
}
|
||||
if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_unique<Dynarmic::A32::Jit>(config);
|
||||
}
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
|
||||
config.wall_clock_cntpct = uses_wall_clock;
|
||||
|
||||
// Safe optimizations
|
||||
if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) {
|
||||
if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
|
||||
if (!Settings::values.cpuopt_page_tables) {
|
||||
config.page_table = nullptr;
|
||||
}
|
||||
@@ -222,6 +222,17 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe optimizations
|
||||
if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::Unsafe) {
|
||||
config.unsafe_optimizations = true;
|
||||
if (Settings::values.cpuopt_unsafe_unfuse_fma) {
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
|
||||
}
|
||||
if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_shared<Dynarmic::A64::Jit>(config);
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
|
||||
return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(concat, dir->GetName());
|
||||
}
|
||||
|
||||
if (FileUtil::IsDirectory(path))
|
||||
if (Common::FS::IsDirectory(path))
|
||||
return vfs->OpenFile(path + "/" + "main", FileSys::Mode::Read);
|
||||
|
||||
return vfs->OpenFile(path, FileSys::Mode::Read);
|
||||
@@ -269,14 +269,14 @@ struct System::Impl {
|
||||
// Log last frame performance stats if game was loded
|
||||
if (perf_stats) {
|
||||
const auto perf_results = GetAndResetPerfStats();
|
||||
telemetry_session->AddField(Telemetry::FieldType::Performance,
|
||||
"Shutdown_EmulationSpeed",
|
||||
constexpr auto performance = Common::Telemetry::FieldType::Performance;
|
||||
|
||||
telemetry_session->AddField(performance, "Shutdown_EmulationSpeed",
|
||||
perf_results.emulation_speed * 100.0);
|
||||
telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_Framerate",
|
||||
perf_results.game_fps);
|
||||
telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime",
|
||||
telemetry_session->AddField(performance, "Shutdown_Framerate", perf_results.game_fps);
|
||||
telemetry_session->AddField(performance, "Shutdown_Frametime",
|
||||
perf_results.frametime * 1000.0);
|
||||
telemetry_session->AddField(Telemetry::FieldType::Performance, "Mean_Frametime_MS",
|
||||
telemetry_session->AddField(performance, "Mean_Frametime_MS",
|
||||
perf_stats->GetMeanFrametime());
|
||||
}
|
||||
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/core_timing_util.h"
|
||||
#include "core/hardware_properties.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
|
||||
constexpr u64 MAX_SLICE_LENGTH = 4000;
|
||||
constexpr s64 MAX_SLICE_LENGTH = 4000;
|
||||
|
||||
std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
|
||||
return std::make_shared<EventType>(std::move(callback), std::move(name));
|
||||
@@ -37,10 +37,8 @@ struct CoreTiming::Event {
|
||||
}
|
||||
};
|
||||
|
||||
CoreTiming::CoreTiming() {
|
||||
clock =
|
||||
Common::CreateBestMatchingClock(Core::Hardware::BASE_CLOCK_RATE, Core::Hardware::CNTFREQ);
|
||||
}
|
||||
CoreTiming::CoreTiming()
|
||||
: clock{Common::CreateBestMatchingClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)} {}
|
||||
|
||||
CoreTiming::~CoreTiming() = default;
|
||||
|
||||
@@ -136,7 +134,7 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
|
||||
|
||||
void CoreTiming::AddTicks(u64 ticks) {
|
||||
this->ticks += ticks;
|
||||
downcount -= ticks;
|
||||
downcount -= static_cast<s64>(ticks);
|
||||
}
|
||||
|
||||
void CoreTiming::Idle() {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <limits>
|
||||
#include "common/logging/log.h"
|
||||
#include "common/uint128.h"
|
||||
#include "core/hardware_properties.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include <chrono>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hardware_properties.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <array>
|
||||
#include <mbedtls/cipher.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
@@ -10,8 +11,10 @@
|
||||
|
||||
namespace Core::Crypto {
|
||||
namespace {
|
||||
std::vector<u8> CalculateNintendoTweak(std::size_t sector_id) {
|
||||
std::vector<u8> out(0x10);
|
||||
using NintendoTweak = std::array<u8, 16>;
|
||||
|
||||
NintendoTweak CalculateNintendoTweak(std::size_t sector_id) {
|
||||
NintendoTweak out{};
|
||||
for (std::size_t i = 0xF; i <= 0xF; --i) {
|
||||
out[i] = sector_id & 0xFF;
|
||||
sector_id >>= 8;
|
||||
@@ -63,13 +66,6 @@ AESCipher<Key, KeySize>::~AESCipher() {
|
||||
mbedtls_cipher_free(&ctx->decryption_context);
|
||||
}
|
||||
|
||||
template <typename Key, std::size_t KeySize>
|
||||
void AESCipher<Key, KeySize>::SetIV(std::vector<u8> iv) {
|
||||
ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, iv.data(), iv.size()) ||
|
||||
mbedtls_cipher_set_iv(&ctx->decryption_context, iv.data(), iv.size())) == 0,
|
||||
"Failed to set IV on mbedtls ciphers.");
|
||||
}
|
||||
|
||||
template <typename Key, std::size_t KeySize>
|
||||
void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* dest, Op op) const {
|
||||
auto* const context = op == Op::Encrypt ? &ctx->encryption_context : &ctx->decryption_context;
|
||||
@@ -120,10 +116,17 @@ void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, std::size_t size, u8*
|
||||
|
||||
for (std::size_t i = 0; i < size; i += sector_size) {
|
||||
SetIV(CalculateNintendoTweak(sector_id++));
|
||||
Transcode<u8, u8>(src + i, sector_size, dest + i, op);
|
||||
Transcode(src + i, sector_size, dest + i, op);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Key, std::size_t KeySize>
|
||||
void AESCipher<Key, KeySize>::SetIVImpl(const u8* data, std::size_t size) {
|
||||
ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, data, size) ||
|
||||
mbedtls_cipher_set_iv(&ctx->decryption_context, data, size)) == 0,
|
||||
"Failed to set IV on mbedtls ciphers.");
|
||||
}
|
||||
|
||||
template class AESCipher<Key128>;
|
||||
template class AESCipher<Key256>;
|
||||
} // namespace Core::Crypto
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
|
||||
@@ -32,10 +31,12 @@ class AESCipher {
|
||||
|
||||
public:
|
||||
AESCipher(Key key, Mode mode);
|
||||
|
||||
~AESCipher();
|
||||
|
||||
void SetIV(std::vector<u8> iv);
|
||||
template <typename ContiguousContainer>
|
||||
void SetIV(const ContiguousContainer& container) {
|
||||
SetIVImpl(std::data(container), std::size(container));
|
||||
}
|
||||
|
||||
template <typename Source, typename Dest>
|
||||
void Transcode(const Source* src, std::size_t size, Dest* dest, Op op) const {
|
||||
@@ -59,6 +60,8 @@ public:
|
||||
std::size_t sector_size, Op op);
|
||||
|
||||
private:
|
||||
void SetIVImpl(const u8* data, std::size_t size);
|
||||
|
||||
std::unique_ptr<CipherContext> ctx;
|
||||
};
|
||||
} // namespace Core::Crypto
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include "common/assert.h"
|
||||
#include "core/crypto/ctr_encryption_layer.h"
|
||||
@@ -10,8 +11,7 @@ namespace Core::Crypto {
|
||||
|
||||
CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_,
|
||||
std::size_t base_offset)
|
||||
: EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR),
|
||||
iv(16, 0) {}
|
||||
: EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR) {}
|
||||
|
||||
std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const {
|
||||
if (length == 0)
|
||||
@@ -39,9 +39,8 @@ std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t o
|
||||
return read + Read(data + read, length - read, offset + read);
|
||||
}
|
||||
|
||||
void CTREncryptionLayer::SetIV(const std::vector<u8>& iv_) {
|
||||
const auto length = std::min(iv_.size(), iv.size());
|
||||
iv.assign(iv_.cbegin(), iv_.cbegin() + length);
|
||||
void CTREncryptionLayer::SetIV(const IVData& iv_) {
|
||||
iv = iv_;
|
||||
}
|
||||
|
||||
void CTREncryptionLayer::UpdateIV(std::size_t offset) const {
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
#include "core/crypto/aes_util.h"
|
||||
#include "core/crypto/encryption_layer.h"
|
||||
#include "core/crypto/key_manager.h"
|
||||
@@ -14,18 +15,20 @@ namespace Core::Crypto {
|
||||
// Sits on top of a VirtualFile and provides CTR-mode AES decription.
|
||||
class CTREncryptionLayer : public EncryptionLayer {
|
||||
public:
|
||||
using IVData = std::array<u8, 16>;
|
||||
|
||||
CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, std::size_t base_offset);
|
||||
|
||||
std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
|
||||
|
||||
void SetIV(const std::vector<u8>& iv);
|
||||
void SetIV(const IVData& iv);
|
||||
|
||||
private:
|
||||
std::size_t base_offset;
|
||||
|
||||
// Must be mutable as operations modify cipher contexts.
|
||||
mutable AESCipher<Key128> cipher;
|
||||
mutable std::vector<u8> iv;
|
||||
mutable IVData iv{};
|
||||
|
||||
void UpdateIV(std::size_t offset) const;
|
||||
};
|
||||
|
||||
@@ -36,18 +36,86 @@
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Core::Crypto {
|
||||
namespace {
|
||||
|
||||
constexpr u64 CURRENT_CRYPTO_REVISION = 0x5;
|
||||
constexpr u64 FULL_TICKET_SIZE = 0x400;
|
||||
|
||||
using namespace Common;
|
||||
using Common::AsArray;
|
||||
|
||||
const std::array<SHA256Hash, 2> eticket_source_hashes{
|
||||
"B71DB271DC338DF380AA2C4335EF8873B1AFD408E80B3582D8719FC81C5E511C"_array32, // eticket_rsa_kek_source
|
||||
"E8965A187D30E57869F562D04383C996DE487BBA5761363D2D4D32391866A85C"_array32, // eticket_rsa_kekek_source
|
||||
// clang-format off
|
||||
constexpr std::array eticket_source_hashes{
|
||||
AsArray("B71DB271DC338DF380AA2C4335EF8873B1AFD408E80B3582D8719FC81C5E511C"), // eticket_rsa_kek_source
|
||||
AsArray("E8965A187D30E57869F562D04383C996DE487BBA5761363D2D4D32391866A85C"), // eticket_rsa_kekek_source
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
const std::map<std::pair<S128KeyType, u64>, std::string> KEYS_VARIABLE_LENGTH{
|
||||
constexpr std::array<std::pair<std::string_view, KeyIndex<S128KeyType>>, 30> s128_file_id{{
|
||||
{"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}},
|
||||
{"eticket_rsa_kek_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKek), 0}},
|
||||
{"eticket_rsa_kekek_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKekek), 0}},
|
||||
{"rsa_kek_mask_0", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Mask0), 0}},
|
||||
{"rsa_kek_seed_3", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Seed3), 0}},
|
||||
{"rsa_oaep_kek_generation_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::RSAOaepKekGeneration), 0}},
|
||||
{"sd_card_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek), 0}},
|
||||
{"aes_kek_generation_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration), 0}},
|
||||
{"aes_key_generation_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration), 0}},
|
||||
{"package2_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Package2), 0}},
|
||||
{"master_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Master), 0}},
|
||||
{"header_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::HeaderKek), 0}},
|
||||
{"key_area_key_application_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
|
||||
static_cast<u64>(KeyAreaKeyType::Application)}},
|
||||
{"key_area_key_ocean_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
|
||||
static_cast<u64>(KeyAreaKeyType::Ocean)}},
|
||||
{"key_area_key_system_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
|
||||
static_cast<u64>(KeyAreaKeyType::System)}},
|
||||
{"titlekek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Titlekek), 0}},
|
||||
{"keyblob_mac_key_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC), 0}},
|
||||
{"tsec_key", {S128KeyType::TSEC, 0, 0}},
|
||||
{"secure_boot_key", {S128KeyType::SecureBoot, 0, 0}},
|
||||
{"sd_seed", {S128KeyType::SDSeed, 0, 0}},
|
||||
{"bis_key_0_crypt", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Crypto)}},
|
||||
{"bis_key_0_tweak", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Tweak)}},
|
||||
{"bis_key_1_crypt", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Crypto)}},
|
||||
{"bis_key_1_tweak", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Tweak)}},
|
||||
{"bis_key_2_crypt", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Crypto)}},
|
||||
{"bis_key_2_tweak", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Tweak)}},
|
||||
{"bis_key_3_crypt", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Crypto)}},
|
||||
{"bis_key_3_tweak", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Tweak)}},
|
||||
{"header_kek", {S128KeyType::HeaderKek, 0, 0}},
|
||||
{"sd_card_kek", {S128KeyType::SDKek, 0, 0}},
|
||||
}};
|
||||
|
||||
auto Find128ByName(std::string_view name) {
|
||||
return std::find_if(s128_file_id.begin(), s128_file_id.end(),
|
||||
[&name](const auto& pair) { return pair.first == name; });
|
||||
}
|
||||
|
||||
constexpr std::array<std::pair<std::string_view, KeyIndex<S256KeyType>>, 6> s256_file_id{{
|
||||
{"header_key", {S256KeyType::Header, 0, 0}},
|
||||
{"sd_card_save_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save), 0}},
|
||||
{"sd_card_nca_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::NCA), 0}},
|
||||
{"header_key_source", {S256KeyType::HeaderSource, 0, 0}},
|
||||
{"sd_card_save_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::Save), 0}},
|
||||
{"sd_card_nca_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::NCA), 0}},
|
||||
}};
|
||||
|
||||
auto Find256ByName(std::string_view name) {
|
||||
return std::find_if(s256_file_id.begin(), s256_file_id.end(),
|
||||
[&name](const auto& pair) { return pair.first == name; });
|
||||
}
|
||||
|
||||
using KeyArray = std::array<std::pair<std::pair<S128KeyType, u64>, std::string_view>, 7>;
|
||||
constexpr KeyArray KEYS_VARIABLE_LENGTH{{
|
||||
{{S128KeyType::Master, 0}, "master_key_"},
|
||||
{{S128KeyType::Package1, 0}, "package1_key_"},
|
||||
{{S128KeyType::Package2, 0}, "package2_key_"},
|
||||
@@ -55,14 +123,13 @@ const std::map<std::pair<S128KeyType, u64>, std::string> KEYS_VARIABLE_LENGTH{
|
||||
{{S128KeyType::Source, static_cast<u64>(SourceKeyType::Keyblob)}, "keyblob_key_source_"},
|
||||
{{S128KeyType::Keyblob, 0}, "keyblob_key_"},
|
||||
{{S128KeyType::KeyblobMAC, 0}, "keyblob_mac_key_"},
|
||||
};
|
||||
}};
|
||||
|
||||
namespace {
|
||||
template <std::size_t Size>
|
||||
bool IsAllZeroArray(const std::array<u8, Size>& array) {
|
||||
return std::all_of(array.begin(), array.end(), [](const auto& elem) { return elem == 0; });
|
||||
}
|
||||
} // namespace
|
||||
} // Anonymous namespace
|
||||
|
||||
u64 GetSignatureTypeDataSize(SignatureType type) {
|
||||
switch (type) {
|
||||
@@ -94,13 +161,13 @@ u64 GetSignatureTypePaddingSize(SignatureType type) {
|
||||
}
|
||||
|
||||
SignatureType Ticket::GetSignatureType() const {
|
||||
if (auto ticket = std::get_if<RSA4096Ticket>(&data)) {
|
||||
if (const auto* ticket = std::get_if<RSA4096Ticket>(&data)) {
|
||||
return ticket->sig_type;
|
||||
}
|
||||
if (auto ticket = std::get_if<RSA2048Ticket>(&data)) {
|
||||
if (const auto* ticket = std::get_if<RSA2048Ticket>(&data)) {
|
||||
return ticket->sig_type;
|
||||
}
|
||||
if (auto ticket = std::get_if<ECDSATicket>(&data)) {
|
||||
if (const auto* ticket = std::get_if<ECDSATicket>(&data)) {
|
||||
return ticket->sig_type;
|
||||
}
|
||||
|
||||
@@ -108,13 +175,13 @@ SignatureType Ticket::GetSignatureType() const {
|
||||
}
|
||||
|
||||
TicketData& Ticket::GetData() {
|
||||
if (auto ticket = std::get_if<RSA4096Ticket>(&data)) {
|
||||
if (auto* ticket = std::get_if<RSA4096Ticket>(&data)) {
|
||||
return ticket->data;
|
||||
}
|
||||
if (auto ticket = std::get_if<RSA2048Ticket>(&data)) {
|
||||
if (auto* ticket = std::get_if<RSA2048Ticket>(&data)) {
|
||||
return ticket->data;
|
||||
}
|
||||
if (auto ticket = std::get_if<ECDSATicket>(&data)) {
|
||||
if (auto* ticket = std::get_if<ECDSATicket>(&data)) {
|
||||
return ticket->data;
|
||||
}
|
||||
|
||||
@@ -122,13 +189,13 @@ TicketData& Ticket::GetData() {
|
||||
}
|
||||
|
||||
const TicketData& Ticket::GetData() const {
|
||||
if (auto ticket = std::get_if<RSA4096Ticket>(&data)) {
|
||||
if (const auto* ticket = std::get_if<RSA4096Ticket>(&data)) {
|
||||
return ticket->data;
|
||||
}
|
||||
if (auto ticket = std::get_if<RSA2048Ticket>(&data)) {
|
||||
if (const auto* ticket = std::get_if<RSA2048Ticket>(&data)) {
|
||||
return ticket->data;
|
||||
}
|
||||
if (auto ticket = std::get_if<ECDSATicket>(&data)) {
|
||||
if (const auto* ticket = std::get_if<ECDSATicket>(&data)) {
|
||||
return ticket->data;
|
||||
}
|
||||
|
||||
@@ -231,8 +298,9 @@ void KeyManager::DeriveGeneralPurposeKeys(std::size_t crypto_revision) {
|
||||
}
|
||||
|
||||
RSAKeyPair<2048> KeyManager::GetETicketRSAKey() const {
|
||||
if (IsAllZeroArray(eticket_extended_kek) || !HasKey(S128KeyType::ETicketRSAKek))
|
||||
if (IsAllZeroArray(eticket_extended_kek) || !HasKey(S128KeyType::ETicketRSAKek)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto eticket_final = GetKey(S128KeyType::ETicketRSAKek);
|
||||
|
||||
@@ -259,27 +327,30 @@ Key128 DeriveKeyblobMACKey(const Key128& keyblob_key, const Key128& mac_source)
|
||||
}
|
||||
|
||||
std::optional<Key128> DeriveSDSeed() {
|
||||
const FileUtil::IOFile save_43(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
|
||||
"/system/save/8000000000000043",
|
||||
"rb+");
|
||||
if (!save_43.IsOpen())
|
||||
return {};
|
||||
const Common::FS::IOFile save_43(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) +
|
||||
"/system/save/8000000000000043",
|
||||
"rb+");
|
||||
if (!save_43.IsOpen()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const FileUtil::IOFile sd_private(
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) + "/Nintendo/Contents/private", "rb+");
|
||||
if (!sd_private.IsOpen())
|
||||
return {};
|
||||
const Common::FS::IOFile sd_private(Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir) +
|
||||
"/Nintendo/Contents/private",
|
||||
"rb+");
|
||||
if (!sd_private.IsOpen()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::array<u8, 0x10> private_seed{};
|
||||
if (sd_private.ReadBytes(private_seed.data(), private_seed.size()) != private_seed.size()) {
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::array<u8, 0x10> buffer{};
|
||||
std::size_t offset = 0;
|
||||
for (; offset + 0x10 < save_43.GetSize(); ++offset) {
|
||||
if (!save_43.Seek(offset, SEEK_SET)) {
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
save_43.ReadBytes(buffer.data(), buffer.size());
|
||||
@@ -289,23 +360,26 @@ std::optional<Key128> DeriveSDSeed() {
|
||||
}
|
||||
|
||||
if (!save_43.Seek(offset + 0x10, SEEK_SET)) {
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
Key128 seed{};
|
||||
if (save_43.ReadBytes(seed.data(), seed.size()) != seed.size()) {
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
return seed;
|
||||
}
|
||||
|
||||
Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& keys) {
|
||||
if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek)))
|
||||
if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek))) {
|
||||
return Loader::ResultStatus::ErrorMissingSDKEKSource;
|
||||
if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration)))
|
||||
}
|
||||
if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration))) {
|
||||
return Loader::ResultStatus::ErrorMissingAESKEKGenerationSource;
|
||||
if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration)))
|
||||
}
|
||||
if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration))) {
|
||||
return Loader::ResultStatus::ErrorMissingAESKeyGenerationSource;
|
||||
}
|
||||
|
||||
const auto sd_kek_source =
|
||||
keys.GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek));
|
||||
@@ -318,14 +392,17 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& ke
|
||||
GenerateKeyEncryptionKey(sd_kek_source, master_00, aes_kek_gen, aes_key_gen);
|
||||
keys.SetKey(S128KeyType::SDKek, sd_kek);
|
||||
|
||||
if (!keys.HasKey(S128KeyType::SDSeed))
|
||||
if (!keys.HasKey(S128KeyType::SDSeed)) {
|
||||
return Loader::ResultStatus::ErrorMissingSDSeed;
|
||||
}
|
||||
const auto sd_seed = keys.GetKey(S128KeyType::SDSeed);
|
||||
|
||||
if (!keys.HasKey(S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save)))
|
||||
if (!keys.HasKey(S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save))) {
|
||||
return Loader::ResultStatus::ErrorMissingSDSaveKeySource;
|
||||
if (!keys.HasKey(S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::NCA)))
|
||||
}
|
||||
if (!keys.HasKey(S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::NCA))) {
|
||||
return Loader::ResultStatus::ErrorMissingSDNCAKeySource;
|
||||
}
|
||||
|
||||
std::array<Key256, 2> sd_key_sources{
|
||||
keys.GetKey(S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save)),
|
||||
@@ -334,8 +411,9 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& ke
|
||||
|
||||
// Combine sources and seed
|
||||
for (auto& source : sd_key_sources) {
|
||||
for (std::size_t i = 0; i < source.size(); ++i)
|
||||
for (std::size_t i = 0; i < source.size(); ++i) {
|
||||
source[i] ^= sd_seed[i & 0xF];
|
||||
}
|
||||
}
|
||||
|
||||
AESCipher<Key128> cipher(sd_kek, Mode::ECB);
|
||||
@@ -353,9 +431,10 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& ke
|
||||
return Loader::ResultStatus::Success;
|
||||
}
|
||||
|
||||
std::vector<Ticket> GetTicketblob(const FileUtil::IOFile& ticket_save) {
|
||||
if (!ticket_save.IsOpen())
|
||||
std::vector<Ticket> GetTicketblob(const Common::FS::IOFile& ticket_save) {
|
||||
if (!ticket_save.IsOpen()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<u8> buffer(ticket_save.GetSize());
|
||||
if (ticket_save.ReadBytes(buffer.data(), buffer.size()) != buffer.size()) {
|
||||
@@ -415,7 +494,7 @@ static std::optional<u64> FindTicketOffset(const std::array<u8, size>& data) {
|
||||
offset = i + 1;
|
||||
break;
|
||||
} else if (data[i] != 0x0) {
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,16 +504,18 @@ static std::optional<u64> FindTicketOffset(const std::array<u8, size>& data) {
|
||||
std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket,
|
||||
const RSAKeyPair<2048>& key) {
|
||||
const auto issuer = ticket.GetData().issuer;
|
||||
if (IsAllZeroArray(issuer))
|
||||
return {};
|
||||
if (IsAllZeroArray(issuer)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (issuer[0] != 'R' || issuer[1] != 'o' || issuer[2] != 'o' || issuer[3] != 't') {
|
||||
LOG_INFO(Crypto, "Attempting to parse ticket with non-standard certificate authority.");
|
||||
}
|
||||
|
||||
Key128 rights_id = ticket.GetData().rights_id;
|
||||
|
||||
if (rights_id == Key128{})
|
||||
return {};
|
||||
if (rights_id == Key128{}) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!std::any_of(ticket.GetData().title_key_common_pad.begin(),
|
||||
ticket.GetData().title_key_common_pad.end(), [](u8 b) { return b != 0; })) {
|
||||
@@ -466,15 +547,17 @@ std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket,
|
||||
std::array<u8, 0xDF> m_2;
|
||||
std::memcpy(m_2.data(), rsa_step.data() + 0x21, m_2.size());
|
||||
|
||||
if (m_0 != 0)
|
||||
return {};
|
||||
if (m_0 != 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
m_1 = m_1 ^ MGF1<0x20>(m_2);
|
||||
m_2 = m_2 ^ MGF1<0xDF>(m_1);
|
||||
|
||||
const auto offset = FindTicketOffset(m_2);
|
||||
if (!offset)
|
||||
return {};
|
||||
if (!offset) {
|
||||
return std::nullopt;
|
||||
}
|
||||
ASSERT(*offset > 0);
|
||||
|
||||
Key128 key_temp{};
|
||||
@@ -485,8 +568,8 @@ std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket,
|
||||
|
||||
KeyManager::KeyManager() {
|
||||
// Initialize keys
|
||||
const std::string hactool_keys_dir = FileUtil::GetHactoolConfigurationPath();
|
||||
const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir);
|
||||
const std::string hactool_keys_dir = Common::FS::GetHactoolConfigurationPath();
|
||||
const std::string yuzu_keys_dir = Common::FS::GetUserPath(Common::FS::UserPath::KeysDir);
|
||||
if (Settings::values.use_dev_keys) {
|
||||
dev_mode = true;
|
||||
AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "dev.keys", false);
|
||||
@@ -504,34 +587,39 @@ KeyManager::KeyManager() {
|
||||
}
|
||||
|
||||
static bool ValidCryptoRevisionString(std::string_view base, size_t begin, size_t length) {
|
||||
if (base.size() < begin + length)
|
||||
if (base.size() < begin + length) {
|
||||
return false;
|
||||
}
|
||||
return std::all_of(base.begin() + begin, base.begin() + begin + length,
|
||||
[](u8 c) { return std::isxdigit(c); });
|
||||
}
|
||||
|
||||
void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
|
||||
std::ifstream file;
|
||||
OpenFStream(file, filename, std::ios_base::in);
|
||||
if (!file.is_open())
|
||||
Common::FS::OpenFStream(file, filename, std::ios_base::in);
|
||||
if (!file.is_open()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
std::vector<std::string> out;
|
||||
std::stringstream stream(line);
|
||||
std::string item;
|
||||
while (std::getline(stream, item, '='))
|
||||
while (std::getline(stream, item, '=')) {
|
||||
out.push_back(std::move(item));
|
||||
}
|
||||
|
||||
if (out.size() != 2)
|
||||
if (out.size() != 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
out[0].erase(std::remove(out[0].begin(), out[0].end(), ' '), out[0].end());
|
||||
out[1].erase(std::remove(out[1].begin(), out[1].end(), ' '), out[1].end());
|
||||
|
||||
if (out[0].compare(0, 1, "#") == 0)
|
||||
if (out[0].compare(0, 1, "#") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_title_keys) {
|
||||
auto rights_id_raw = Common::HexStringToArray<16>(out[0]);
|
||||
@@ -541,24 +629,26 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
|
||||
s128_keys[{S128KeyType::Titlekey, rights_id[1], rights_id[0]}] = key;
|
||||
} else {
|
||||
out[0] = Common::ToLower(out[0]);
|
||||
if (s128_file_id.find(out[0]) != s128_file_id.end()) {
|
||||
const auto index = s128_file_id.at(out[0]);
|
||||
Key128 key = Common::HexStringToArray<16>(out[1]);
|
||||
if (const auto iter128 = Find128ByName(out[0]); iter128 != s128_file_id.end()) {
|
||||
const auto& index = iter128->second;
|
||||
const Key128 key = Common::HexStringToArray<16>(out[1]);
|
||||
s128_keys[{index.type, index.field1, index.field2}] = key;
|
||||
} else if (s256_file_id.find(out[0]) != s256_file_id.end()) {
|
||||
const auto index = s256_file_id.at(out[0]);
|
||||
Key256 key = Common::HexStringToArray<32>(out[1]);
|
||||
} else if (const auto iter256 = Find256ByName(out[0]); iter256 != s256_file_id.end()) {
|
||||
const auto& index = iter256->second;
|
||||
const Key256 key = Common::HexStringToArray<32>(out[1]);
|
||||
s256_keys[{index.type, index.field1, index.field2}] = key;
|
||||
} else if (out[0].compare(0, 8, "keyblob_") == 0 &&
|
||||
out[0].compare(0, 9, "keyblob_k") != 0) {
|
||||
if (!ValidCryptoRevisionString(out[0], 8, 2))
|
||||
if (!ValidCryptoRevisionString(out[0], 8, 2)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto index = std::stoul(out[0].substr(8, 2), nullptr, 16);
|
||||
keyblobs[index] = Common::HexStringToArray<0x90>(out[1]);
|
||||
} else if (out[0].compare(0, 18, "encrypted_keyblob_") == 0) {
|
||||
if (!ValidCryptoRevisionString(out[0], 18, 2))
|
||||
if (!ValidCryptoRevisionString(out[0], 18, 2)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto index = std::stoul(out[0].substr(18, 2), nullptr, 16);
|
||||
encrypted_keyblobs[index] = Common::HexStringToArray<0xB0>(out[1]);
|
||||
@@ -566,8 +656,9 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
|
||||
eticket_extended_kek = Common::HexStringToArray<576>(out[1]);
|
||||
} else {
|
||||
for (const auto& kv : KEYS_VARIABLE_LENGTH) {
|
||||
if (!ValidCryptoRevisionString(out[0], kv.second.size(), 2))
|
||||
if (!ValidCryptoRevisionString(out[0], kv.second.size(), 2)) {
|
||||
continue;
|
||||
}
|
||||
if (out[0].compare(0, kv.second.size(), kv.second) == 0) {
|
||||
const auto index =
|
||||
std::stoul(out[0].substr(kv.second.size(), 2), nullptr, 16);
|
||||
@@ -602,10 +693,11 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
|
||||
|
||||
void KeyManager::AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2,
|
||||
const std::string& filename, bool title) {
|
||||
if (FileUtil::Exists(dir1 + DIR_SEP + filename))
|
||||
if (Common::FS::Exists(dir1 + DIR_SEP + filename)) {
|
||||
LoadFromFile(dir1 + DIR_SEP + filename, title);
|
||||
else if (FileUtil::Exists(dir2 + DIR_SEP + filename))
|
||||
} else if (Common::FS::Exists(dir2 + DIR_SEP + filename)) {
|
||||
LoadFromFile(dir2 + DIR_SEP + filename, title);
|
||||
}
|
||||
}
|
||||
|
||||
bool KeyManager::BaseDeriveNecessary() const {
|
||||
@@ -613,8 +705,9 @@ bool KeyManager::BaseDeriveNecessary() const {
|
||||
return !HasKey(key_type, index1, index2);
|
||||
};
|
||||
|
||||
if (check_key_existence(S256KeyType::Header))
|
||||
if (check_key_existence(S256KeyType::Header)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < CURRENT_CRYPTO_REVISION; ++i) {
|
||||
if (check_key_existence(S128KeyType::Master, i) ||
|
||||
@@ -639,14 +732,16 @@ bool KeyManager::HasKey(S256KeyType id, u64 field1, u64 field2) const {
|
||||
}
|
||||
|
||||
Key128 KeyManager::GetKey(S128KeyType id, u64 field1, u64 field2) const {
|
||||
if (!HasKey(id, field1, field2))
|
||||
if (!HasKey(id, field1, field2)) {
|
||||
return {};
|
||||
}
|
||||
return s128_keys.at({id, field1, field2});
|
||||
}
|
||||
|
||||
Key256 KeyManager::GetKey(S256KeyType id, u64 field1, u64 field2) const {
|
||||
if (!HasKey(id, field1, field2))
|
||||
if (!HasKey(id, field1, field2)) {
|
||||
return {};
|
||||
}
|
||||
return s256_keys.at({id, field1, field2});
|
||||
}
|
||||
|
||||
@@ -668,7 +763,7 @@ Key256 KeyManager::GetBISKey(u8 partition_id) const {
|
||||
template <size_t Size>
|
||||
void KeyManager::WriteKeyToFile(KeyCategory category, std::string_view keyname,
|
||||
const std::array<u8, Size>& key) {
|
||||
const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir);
|
||||
const std::string yuzu_keys_dir = Common::FS::GetUserPath(Common::FS::UserPath::KeysDir);
|
||||
std::string filename = "title.keys_autogenerated";
|
||||
if (category == KeyCategory::Standard) {
|
||||
filename = dev_mode ? "dev.keys_autogenerated" : "prod.keys_autogenerated";
|
||||
@@ -677,9 +772,9 @@ void KeyManager::WriteKeyToFile(KeyCategory category, std::string_view keyname,
|
||||
}
|
||||
|
||||
const auto path = yuzu_keys_dir + DIR_SEP + filename;
|
||||
const auto add_info_text = !FileUtil::Exists(path);
|
||||
FileUtil::CreateFullPath(path);
|
||||
FileUtil::IOFile file{path, "a"};
|
||||
const auto add_info_text = !Common::FS::Exists(path);
|
||||
Common::FS::CreateFullPath(path);
|
||||
Common::FS::IOFile file{path, "a"};
|
||||
if (!file.IsOpen()) {
|
||||
return;
|
||||
}
|
||||
@@ -712,8 +807,7 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
|
||||
}
|
||||
|
||||
const auto iter2 = std::find_if(
|
||||
s128_file_id.begin(), s128_file_id.end(),
|
||||
[&id, &field1, &field2](const std::pair<std::string, KeyIndex<S128KeyType>> elem) {
|
||||
s128_file_id.begin(), s128_file_id.end(), [&id, &field1, &field2](const auto& elem) {
|
||||
return std::tie(elem.second.type, elem.second.field1, elem.second.field2) ==
|
||||
std::tie(id, field1, field2);
|
||||
});
|
||||
@@ -723,9 +817,11 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
|
||||
|
||||
// Variable cases
|
||||
if (id == S128KeyType::KeyArea) {
|
||||
static constexpr std::array<const char*, 3> kak_names = {"key_area_key_application_{:02X}",
|
||||
"key_area_key_ocean_{:02X}",
|
||||
"key_area_key_system_{:02X}"};
|
||||
static constexpr std::array<const char*, 3> kak_names = {
|
||||
"key_area_key_application_{:02X}",
|
||||
"key_area_key_ocean_{:02X}",
|
||||
"key_area_key_system_{:02X}",
|
||||
};
|
||||
WriteKeyToFile(category, fmt::format(kak_names.at(field2), field1), key);
|
||||
} else if (id == S128KeyType::Master) {
|
||||
WriteKeyToFile(category, fmt::format("master_key_{:02X}", field1), key);
|
||||
@@ -751,8 +847,7 @@ void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) {
|
||||
return;
|
||||
}
|
||||
const auto iter = std::find_if(
|
||||
s256_file_id.begin(), s256_file_id.end(),
|
||||
[&id, &field1, &field2](const std::pair<std::string, KeyIndex<S256KeyType>> elem) {
|
||||
s256_file_id.begin(), s256_file_id.end(), [&id, &field1, &field2](const auto& elem) {
|
||||
return std::tie(elem.second.type, elem.second.field1, elem.second.field2) ==
|
||||
std::tie(id, field1, field2);
|
||||
});
|
||||
@@ -763,29 +858,31 @@ void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) {
|
||||
}
|
||||
|
||||
bool KeyManager::KeyFileExists(bool title) {
|
||||
const std::string hactool_keys_dir = FileUtil::GetHactoolConfigurationPath();
|
||||
const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir);
|
||||
const std::string hactool_keys_dir = Common::FS::GetHactoolConfigurationPath();
|
||||
const std::string yuzu_keys_dir = Common::FS::GetUserPath(Common::FS::UserPath::KeysDir);
|
||||
if (title) {
|
||||
return FileUtil::Exists(hactool_keys_dir + DIR_SEP + "title.keys") ||
|
||||
FileUtil::Exists(yuzu_keys_dir + DIR_SEP + "title.keys");
|
||||
return Common::FS::Exists(hactool_keys_dir + DIR_SEP + "title.keys") ||
|
||||
Common::FS::Exists(yuzu_keys_dir + DIR_SEP + "title.keys");
|
||||
}
|
||||
|
||||
if (Settings::values.use_dev_keys) {
|
||||
return FileUtil::Exists(hactool_keys_dir + DIR_SEP + "dev.keys") ||
|
||||
FileUtil::Exists(yuzu_keys_dir + DIR_SEP + "dev.keys");
|
||||
return Common::FS::Exists(hactool_keys_dir + DIR_SEP + "dev.keys") ||
|
||||
Common::FS::Exists(yuzu_keys_dir + DIR_SEP + "dev.keys");
|
||||
}
|
||||
|
||||
return FileUtil::Exists(hactool_keys_dir + DIR_SEP + "prod.keys") ||
|
||||
FileUtil::Exists(yuzu_keys_dir + DIR_SEP + "prod.keys");
|
||||
return Common::FS::Exists(hactool_keys_dir + DIR_SEP + "prod.keys") ||
|
||||
Common::FS::Exists(yuzu_keys_dir + DIR_SEP + "prod.keys");
|
||||
}
|
||||
|
||||
void KeyManager::DeriveSDSeedLazy() {
|
||||
if (HasKey(S128KeyType::SDSeed))
|
||||
if (HasKey(S128KeyType::SDSeed)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto res = DeriveSDSeed();
|
||||
if (res)
|
||||
if (res) {
|
||||
SetKey(S128KeyType::SDSeed, *res);
|
||||
}
|
||||
}
|
||||
|
||||
static Key128 CalculateCMAC(const u8* source, size_t size, const Key128& key) {
|
||||
@@ -797,11 +894,13 @@ static Key128 CalculateCMAC(const u8* source, size_t size, const Key128& key) {
|
||||
}
|
||||
|
||||
void KeyManager::DeriveBase() {
|
||||
if (!BaseDeriveNecessary())
|
||||
if (!BaseDeriveNecessary()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!HasKey(S128KeyType::SecureBoot) || !HasKey(S128KeyType::TSEC))
|
||||
if (!HasKey(S128KeyType::SecureBoot) || !HasKey(S128KeyType::TSEC)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto has_bis = [this](u64 id) {
|
||||
return HasKey(S128KeyType::BIS, id, static_cast<u64>(BISKeyType::Crypto)) &&
|
||||
@@ -818,10 +917,11 @@ void KeyManager::DeriveBase() {
|
||||
static_cast<u64>(BISKeyType::Tweak));
|
||||
};
|
||||
|
||||
if (has_bis(2) && !has_bis(3))
|
||||
if (has_bis(2) && !has_bis(3)) {
|
||||
copy_bis(2, 3);
|
||||
else if (has_bis(3) && !has_bis(2))
|
||||
} else if (has_bis(3) && !has_bis(2)) {
|
||||
copy_bis(3, 2);
|
||||
}
|
||||
|
||||
std::bitset<32> revisions(0xFFFFFFFF);
|
||||
for (size_t i = 0; i < revisions.size(); ++i) {
|
||||
@@ -831,15 +931,17 @@ void KeyManager::DeriveBase() {
|
||||
}
|
||||
}
|
||||
|
||||
if (!revisions.any())
|
||||
if (!revisions.any()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto sbk = GetKey(S128KeyType::SecureBoot);
|
||||
const auto tsec = GetKey(S128KeyType::TSEC);
|
||||
|
||||
for (size_t i = 0; i < revisions.size(); ++i) {
|
||||
if (!revisions[i])
|
||||
if (!revisions[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Derive keyblob key
|
||||
const auto key = DeriveKeyblobKey(
|
||||
@@ -848,16 +950,18 @@ void KeyManager::DeriveBase() {
|
||||
SetKey(S128KeyType::Keyblob, key, i);
|
||||
|
||||
// Derive keyblob MAC key
|
||||
if (!HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC)))
|
||||
if (!HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto mac_key = DeriveKeyblobMACKey(
|
||||
key, GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC)));
|
||||
SetKey(S128KeyType::KeyblobMAC, mac_key, i);
|
||||
|
||||
Key128 cmac = CalculateCMAC(encrypted_keyblobs[i].data() + 0x10, 0xA0, mac_key);
|
||||
if (std::memcmp(cmac.data(), encrypted_keyblobs[i].data(), cmac.size()) != 0)
|
||||
if (std::memcmp(cmac.data(), encrypted_keyblobs[i].data(), cmac.size()) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Decrypt keyblob
|
||||
if (keyblobs[i] == std::array<u8, 0x90>{}) {
|
||||
@@ -881,16 +985,19 @@ void KeyManager::DeriveBase() {
|
||||
|
||||
revisions.set();
|
||||
for (size_t i = 0; i < revisions.size(); ++i) {
|
||||
if (!HasKey(S128KeyType::Master, i))
|
||||
if (!HasKey(S128KeyType::Master, i)) {
|
||||
revisions.reset(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (!revisions.any())
|
||||
if (!revisions.any()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < revisions.size(); ++i) {
|
||||
if (!revisions[i])
|
||||
if (!revisions[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Derive general purpose keys
|
||||
DeriveGeneralPurposeKeys(i);
|
||||
@@ -920,16 +1027,19 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) {
|
||||
const auto es = Core::System::GetInstance().GetContentProvider().GetEntry(
|
||||
0x0100000000000033, FileSys::ContentRecordType::Program);
|
||||
|
||||
if (es == nullptr)
|
||||
if (es == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto exefs = es->GetExeFS();
|
||||
if (exefs == nullptr)
|
||||
if (exefs == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto main = exefs->GetFile("main");
|
||||
if (main == nullptr)
|
||||
if (main == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto bytes = main->ReadAllBytes();
|
||||
|
||||
@@ -939,16 +1049,19 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) {
|
||||
const auto seed3 = data.GetRSAKekSeed3();
|
||||
const auto mask0 = data.GetRSAKekMask0();
|
||||
|
||||
if (eticket_kek != Key128{})
|
||||
if (eticket_kek != Key128{}) {
|
||||
SetKey(S128KeyType::Source, eticket_kek, static_cast<size_t>(SourceKeyType::ETicketKek));
|
||||
}
|
||||
if (eticket_kekek != Key128{}) {
|
||||
SetKey(S128KeyType::Source, eticket_kekek,
|
||||
static_cast<size_t>(SourceKeyType::ETicketKekek));
|
||||
}
|
||||
if (seed3 != Key128{})
|
||||
if (seed3 != Key128{}) {
|
||||
SetKey(S128KeyType::RSAKek, seed3, static_cast<size_t>(RSAKekType::Seed3));
|
||||
if (mask0 != Key128{})
|
||||
}
|
||||
if (mask0 != Key128{}) {
|
||||
SetKey(S128KeyType::RSAKek, mask0, static_cast<size_t>(RSAKekType::Mask0));
|
||||
}
|
||||
if (eticket_kek == Key128{} || eticket_kekek == Key128{} || seed3 == Key128{} ||
|
||||
mask0 == Key128{}) {
|
||||
return;
|
||||
@@ -974,8 +1087,9 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) {
|
||||
AESCipher<Key128> es_kek(temp_kekek, Mode::ECB);
|
||||
es_kek.Transcode(eticket_kek.data(), eticket_kek.size(), eticket_final.data(), Op::Decrypt);
|
||||
|
||||
if (eticket_final == Key128{})
|
||||
if (eticket_final == Key128{}) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetKey(S128KeyType::ETicketRSAKek, eticket_final);
|
||||
|
||||
@@ -990,18 +1104,20 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) {
|
||||
void KeyManager::PopulateTickets() {
|
||||
const auto rsa_key = GetETicketRSAKey();
|
||||
|
||||
if (rsa_key == RSAKeyPair<2048>{})
|
||||
if (rsa_key == RSAKeyPair<2048>{}) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!common_tickets.empty() && !personal_tickets.empty())
|
||||
if (!common_tickets.empty() && !personal_tickets.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const FileUtil::IOFile save1(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
|
||||
"/system/save/80000000000000e1",
|
||||
"rb+");
|
||||
const FileUtil::IOFile save2(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
|
||||
"/system/save/80000000000000e2",
|
||||
"rb+");
|
||||
const Common::FS::IOFile save1(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) +
|
||||
"/system/save/80000000000000e1",
|
||||
"rb+");
|
||||
const Common::FS::IOFile save2(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) +
|
||||
"/system/save/80000000000000e2",
|
||||
"rb+");
|
||||
|
||||
const auto blob2 = GetTicketblob(save2);
|
||||
auto res = GetTicketblob(save1);
|
||||
@@ -1011,8 +1127,10 @@ void KeyManager::PopulateTickets() {
|
||||
for (std::size_t i = 0; i < res.size(); ++i) {
|
||||
const auto common = i < idx;
|
||||
const auto pair = ParseTicket(res[i], rsa_key);
|
||||
if (!pair)
|
||||
if (!pair) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& [rid, key] = *pair;
|
||||
u128 rights_id;
|
||||
std::memcpy(rights_id.data(), rid.data(), rid.size());
|
||||
@@ -1041,27 +1159,33 @@ void KeyManager::SynthesizeTickets() {
|
||||
}
|
||||
|
||||
void KeyManager::SetKeyWrapped(S128KeyType id, Key128 key, u64 field1, u64 field2) {
|
||||
if (key == Key128{})
|
||||
if (key == Key128{}) {
|
||||
return;
|
||||
}
|
||||
SetKey(id, key, field1, field2);
|
||||
}
|
||||
|
||||
void KeyManager::SetKeyWrapped(S256KeyType id, Key256 key, u64 field1, u64 field2) {
|
||||
if (key == Key256{})
|
||||
if (key == Key256{}) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetKey(id, key, field1, field2);
|
||||
}
|
||||
|
||||
void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) {
|
||||
if (!BaseDeriveNecessary())
|
||||
if (!BaseDeriveNecessary()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.HasBoot0())
|
||||
if (!data.HasBoot0()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < encrypted_keyblobs.size(); ++i) {
|
||||
if (encrypted_keyblobs[i] != std::array<u8, 0xB0>{})
|
||||
if (encrypted_keyblobs[i] != std::array<u8, 0xB0>{}) {
|
||||
continue;
|
||||
}
|
||||
encrypted_keyblobs[i] = data.GetEncryptedKeyblob(i);
|
||||
WriteKeyToFile<0xB0>(KeyCategory::Console, fmt::format("encrypted_keyblob_{:02X}", i),
|
||||
encrypted_keyblobs[i]);
|
||||
@@ -1083,8 +1207,9 @@ void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) {
|
||||
static_cast<u64>(SourceKeyType::Keyblob), i);
|
||||
}
|
||||
|
||||
if (data.HasFuses())
|
||||
if (data.HasFuses()) {
|
||||
SetKeyWrapped(S128KeyType::SecureBoot, data.GetSecureBootKey());
|
||||
}
|
||||
|
||||
DeriveBase();
|
||||
|
||||
@@ -1098,8 +1223,9 @@ void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) {
|
||||
|
||||
const auto masters = data.GetTZMasterKeys(latest_master);
|
||||
for (size_t i = 0; i < masters.size(); ++i) {
|
||||
if (masters[i] != Key128{} && !HasKey(S128KeyType::Master, i))
|
||||
if (masters[i] != Key128{} && !HasKey(S128KeyType::Master, i)) {
|
||||
SetKey(S128KeyType::Master, masters[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
DeriveBase();
|
||||
@@ -1109,8 +1235,9 @@ void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) {
|
||||
|
||||
std::array<Key128, 0x20> package2_keys{};
|
||||
for (size_t i = 0; i < package2_keys.size(); ++i) {
|
||||
if (HasKey(S128KeyType::Package2, i))
|
||||
if (HasKey(S128KeyType::Package2, i)) {
|
||||
package2_keys[i] = GetKey(S128KeyType::Package2, i);
|
||||
}
|
||||
}
|
||||
data.DecryptPackage2(package2_keys, Package2Type::NormalMain);
|
||||
|
||||
@@ -1148,12 +1275,15 @@ const std::map<u128, Ticket>& KeyManager::GetPersonalizedTickets() const {
|
||||
|
||||
bool KeyManager::AddTicketCommon(Ticket raw) {
|
||||
const auto rsa_key = GetETicketRSAKey();
|
||||
if (rsa_key == RSAKeyPair<2048>{})
|
||||
if (rsa_key == RSAKeyPair<2048>{}) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto pair = ParseTicket(raw, rsa_key);
|
||||
if (!pair)
|
||||
if (!pair) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& [rid, key] = *pair;
|
||||
u128 rights_id;
|
||||
std::memcpy(rights_id.data(), rid.data(), rid.size());
|
||||
@@ -1164,12 +1294,15 @@ bool KeyManager::AddTicketCommon(Ticket raw) {
|
||||
|
||||
bool KeyManager::AddTicketPersonalized(Ticket raw) {
|
||||
const auto rsa_key = GetETicketRSAKey();
|
||||
if (rsa_key == RSAKeyPair<2048>{})
|
||||
if (rsa_key == RSAKeyPair<2048>{}) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto pair = ParseTicket(raw, rsa_key);
|
||||
if (!pair)
|
||||
if (!pair) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& [rid, key] = *pair;
|
||||
u128 rights_id;
|
||||
std::memcpy(rights_id.data(), rid.data(), rid.size());
|
||||
@@ -1177,58 +1310,4 @@ bool KeyManager::AddTicketPersonalized(Ticket raw) {
|
||||
SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = {
|
||||
{"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}},
|
||||
{"eticket_rsa_kek_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKek), 0}},
|
||||
{"eticket_rsa_kekek_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKekek), 0}},
|
||||
{"rsa_kek_mask_0", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Mask0), 0}},
|
||||
{"rsa_kek_seed_3", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Seed3), 0}},
|
||||
{"rsa_oaep_kek_generation_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::RSAOaepKekGeneration), 0}},
|
||||
{"sd_card_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek), 0}},
|
||||
{"aes_kek_generation_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration), 0}},
|
||||
{"aes_key_generation_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration), 0}},
|
||||
{"package2_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Package2), 0}},
|
||||
{"master_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Master), 0}},
|
||||
{"header_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::HeaderKek), 0}},
|
||||
{"key_area_key_application_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
|
||||
static_cast<u64>(KeyAreaKeyType::Application)}},
|
||||
{"key_area_key_ocean_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
|
||||
static_cast<u64>(KeyAreaKeyType::Ocean)}},
|
||||
{"key_area_key_system_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
|
||||
static_cast<u64>(KeyAreaKeyType::System)}},
|
||||
{"titlekek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Titlekek), 0}},
|
||||
{"keyblob_mac_key_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC), 0}},
|
||||
{"tsec_key", {S128KeyType::TSEC, 0, 0}},
|
||||
{"secure_boot_key", {S128KeyType::SecureBoot, 0, 0}},
|
||||
{"sd_seed", {S128KeyType::SDSeed, 0, 0}},
|
||||
{"bis_key_0_crypt", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Crypto)}},
|
||||
{"bis_key_0_tweak", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Tweak)}},
|
||||
{"bis_key_1_crypt", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Crypto)}},
|
||||
{"bis_key_1_tweak", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Tweak)}},
|
||||
{"bis_key_2_crypt", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Crypto)}},
|
||||
{"bis_key_2_tweak", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Tweak)}},
|
||||
{"bis_key_3_crypt", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Crypto)}},
|
||||
{"bis_key_3_tweak", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Tweak)}},
|
||||
{"header_kek", {S128KeyType::HeaderKek, 0, 0}},
|
||||
{"sd_card_kek", {S128KeyType::SDKek, 0, 0}},
|
||||
};
|
||||
|
||||
const boost::container::flat_map<std::string, KeyIndex<S256KeyType>> KeyManager::s256_file_id = {
|
||||
{"header_key", {S256KeyType::Header, 0, 0}},
|
||||
{"sd_card_save_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save), 0}},
|
||||
{"sd_card_nca_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::NCA), 0}},
|
||||
{"header_key_source", {S256KeyType::HeaderSource, 0, 0}},
|
||||
{"sd_card_save_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::Save), 0}},
|
||||
{"sd_card_nca_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::NCA), 0}},
|
||||
};
|
||||
} // namespace Core::Crypto
|
||||
|
||||
@@ -10,14 +10,13 @@
|
||||
#include <string>
|
||||
|
||||
#include <variant>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <fmt/format.h>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/crypto/partition_data_manager.h"
|
||||
#include "core/file_sys/vfs_types.h"
|
||||
|
||||
namespace FileUtil {
|
||||
namespace Common::FS {
|
||||
class IOFile;
|
||||
}
|
||||
|
||||
@@ -293,9 +292,6 @@ private:
|
||||
|
||||
void SetKeyWrapped(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0);
|
||||
void SetKeyWrapped(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0);
|
||||
|
||||
static const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> s128_file_id;
|
||||
static const boost::container::flat_map<std::string, KeyIndex<S256KeyType>> s256_file_id;
|
||||
};
|
||||
|
||||
Key128 GenerateKeyEncryptionKey(Key128 source, Key128 master, Key128 kek_seed, Key128 key_seed);
|
||||
@@ -308,7 +304,7 @@ std::array<u8, 0x90> DecryptKeyblob(const std::array<u8, 0xB0>& encrypted_keyblo
|
||||
std::optional<Key128> DeriveSDSeed();
|
||||
Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& keys);
|
||||
|
||||
std::vector<Ticket> GetTicketblob(const FileUtil::IOFile& ticket_save);
|
||||
std::vector<Ticket> GetTicketblob(const Common::FS::IOFile& ticket_save);
|
||||
|
||||
// Returns a pair of {rights_id, titlekey}. Fails if the ticket has no certificate authority
|
||||
// (offset 0x140-0x144 is zero)
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "core/file_sys/vfs_offset.h"
|
||||
#include "core/file_sys/vfs_vector.h"
|
||||
|
||||
using namespace Common;
|
||||
using Common::AsArray;
|
||||
|
||||
namespace Core::Crypto {
|
||||
|
||||
@@ -47,105 +47,123 @@ struct Package2Header {
|
||||
};
|
||||
static_assert(sizeof(Package2Header) == 0x200, "Package2Header has incorrect size.");
|
||||
|
||||
const std::array<SHA256Hash, 0x10> source_hashes{
|
||||
"B24BD293259DBC7AC5D63F88E60C59792498E6FC5443402C7FFE87EE8B61A3F0"_array32, // keyblob_mac_key_source
|
||||
"7944862A3A5C31C6720595EFD302245ABD1B54CCDCF33000557681E65C5664A4"_array32, // master_key_source
|
||||
"21E2DF100FC9E094DB51B47B9B1D6E94ED379DB8B547955BEF8FE08D8DD35603"_array32, // package2_key_source
|
||||
"FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"_array32, // aes_kek_generation_source
|
||||
"FBD10056999EDC7ACDB96098E47E2C3606230270D23281E671F0F389FC5BC585"_array32, // aes_key_generation_source
|
||||
"C48B619827986C7F4E3081D59DB2B460C84312650E9A8E6B458E53E8CBCA4E87"_array32, // titlekek_source
|
||||
"04AD66143C726B2A139FB6B21128B46F56C553B2B3887110304298D8D0092D9E"_array32, // key_area_key_application_source
|
||||
"FD434000C8FF2B26F8E9A9D2D2C12F6BE5773CBB9DC86300E1BD99F8EA33A417"_array32, // key_area_key_ocean_source
|
||||
"1F17B1FD51AD1C2379B58F152CA4912EC2106441E51722F38700D5937A1162F7"_array32, // key_area_key_system_source
|
||||
"6B2ED877C2C52334AC51E59ABFA7EC457F4A7D01E46291E9F2EAA45F011D24B7"_array32, // sd_card_kek_source
|
||||
"D482743563D3EA5DCDC3B74E97C9AC8A342164FA041A1DC80F17F6D31E4BC01C"_array32, // sd_card_save_key_source
|
||||
"2E751CECF7D93A2B957BD5FFCB082FD038CC2853219DD3092C6DAB9838F5A7CC"_array32, // sd_card_nca_key_source
|
||||
"1888CAED5551B3EDE01499E87CE0D86827F80820EFB275921055AA4E2ABDFFC2"_array32, // header_kek_source
|
||||
"8F783E46852DF6BE0BA4E19273C4ADBAEE16380043E1B8C418C4089A8BD64AA6"_array32, // header_key_source
|
||||
"D1757E52F1AE55FA882EC690BC6F954AC46A83DC22F277F8806BD55577C6EED7"_array32, // rsa_kek_seed3
|
||||
"FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"_array32, // rsa_kek_mask0
|
||||
// clang-format off
|
||||
constexpr std::array source_hashes{
|
||||
AsArray("B24BD293259DBC7AC5D63F88E60C59792498E6FC5443402C7FFE87EE8B61A3F0"), // keyblob_mac_key_source
|
||||
AsArray("7944862A3A5C31C6720595EFD302245ABD1B54CCDCF33000557681E65C5664A4"), // master_key_source
|
||||
AsArray("21E2DF100FC9E094DB51B47B9B1D6E94ED379DB8B547955BEF8FE08D8DD35603"), // package2_key_source
|
||||
AsArray("FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"), // aes_kek_generation_source
|
||||
AsArray("FBD10056999EDC7ACDB96098E47E2C3606230270D23281E671F0F389FC5BC585"), // aes_key_generation_source
|
||||
AsArray("C48B619827986C7F4E3081D59DB2B460C84312650E9A8E6B458E53E8CBCA4E87"), // titlekek_source
|
||||
AsArray("04AD66143C726B2A139FB6B21128B46F56C553B2B3887110304298D8D0092D9E"), // key_area_key_application_source
|
||||
AsArray("FD434000C8FF2B26F8E9A9D2D2C12F6BE5773CBB9DC86300E1BD99F8EA33A417"), // key_area_key_ocean_source
|
||||
AsArray("1F17B1FD51AD1C2379B58F152CA4912EC2106441E51722F38700D5937A1162F7"), // key_area_key_system_source
|
||||
AsArray("6B2ED877C2C52334AC51E59ABFA7EC457F4A7D01E46291E9F2EAA45F011D24B7"), // sd_card_kek_source
|
||||
AsArray("D482743563D3EA5DCDC3B74E97C9AC8A342164FA041A1DC80F17F6D31E4BC01C"), // sd_card_save_key_source
|
||||
AsArray("2E751CECF7D93A2B957BD5FFCB082FD038CC2853219DD3092C6DAB9838F5A7CC"), // sd_card_nca_key_source
|
||||
AsArray("1888CAED5551B3EDE01499E87CE0D86827F80820EFB275921055AA4E2ABDFFC2"), // header_kek_source
|
||||
AsArray("8F783E46852DF6BE0BA4E19273C4ADBAEE16380043E1B8C418C4089A8BD64AA6"), // header_key_source
|
||||
AsArray("D1757E52F1AE55FA882EC690BC6F954AC46A83DC22F277F8806BD55577C6EED7"), // rsa_kek_seed3
|
||||
AsArray("FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"), // rsa_kek_mask0
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
const std::array<SHA256Hash, 0x20> keyblob_source_hashes{
|
||||
"8A06FE274AC491436791FDB388BCDD3AB9943BD4DEF8094418CDAC150FD73786"_array32, // keyblob_key_source_00
|
||||
"2D5CAEB2521FEF70B47E17D6D0F11F8CE2C1E442A979AD8035832C4E9FBCCC4B"_array32, // keyblob_key_source_01
|
||||
"61C5005E713BAE780641683AF43E5F5C0E03671117F702F401282847D2FC6064"_array32, // keyblob_key_source_02
|
||||
"8E9795928E1C4428E1B78F0BE724D7294D6934689C11B190943923B9D5B85903"_array32, // keyblob_key_source_03
|
||||
"95FA33AF95AFF9D9B61D164655B32710ED8D615D46C7D6CC3CC70481B686B402"_array32, // keyblob_key_source_04
|
||||
"3F5BE7B3C8B1ABD8C10B4B703D44766BA08730562C172A4FE0D6B866B3E2DB3E"_array32, // keyblob_key_source_05
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_06
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_07
|
||||
// clang-format off
|
||||
constexpr std::array keyblob_source_hashes{
|
||||
AsArray("8A06FE274AC491436791FDB388BCDD3AB9943BD4DEF8094418CDAC150FD73786"), // keyblob_key_source_00
|
||||
AsArray("2D5CAEB2521FEF70B47E17D6D0F11F8CE2C1E442A979AD8035832C4E9FBCCC4B"), // keyblob_key_source_01
|
||||
AsArray("61C5005E713BAE780641683AF43E5F5C0E03671117F702F401282847D2FC6064"), // keyblob_key_source_02
|
||||
AsArray("8E9795928E1C4428E1B78F0BE724D7294D6934689C11B190943923B9D5B85903"), // keyblob_key_source_03
|
||||
AsArray("95FA33AF95AFF9D9B61D164655B32710ED8D615D46C7D6CC3CC70481B686B402"), // keyblob_key_source_04
|
||||
AsArray("3F5BE7B3C8B1ABD8C10B4B703D44766BA08730562C172A4FE0D6B866B3E2DB3E"), // keyblob_key_source_05
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_06
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_07
|
||||
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_08
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_09
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0A
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0B
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0C
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0D
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0E
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0F
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_08
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_09
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0A
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0B
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0C
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0D
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0E
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0F
|
||||
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_10
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_11
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_12
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_13
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_14
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_15
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_16
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_17
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_10
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_11
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_12
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_13
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_14
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_15
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_16
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_17
|
||||
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_18
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_19
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1A
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1B
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1C
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1D
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1E
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1F
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_18
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_19
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1A
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1B
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1C
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1D
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1E
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1F
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
const std::array<SHA256Hash, 0x20> master_key_hashes{
|
||||
"0EE359BE3C864BB0782E1D70A718A0342C551EED28C369754F9C4F691BECF7CA"_array32, // master_key_00
|
||||
"4FE707B7E4ABDAF727C894AAF13B1351BFE2AC90D875F73B2E20FA94B9CC661E"_array32, // master_key_01
|
||||
"79277C0237A2252EC3DFAC1F7C359C2B3D121E9DB15BB9AB4C2B4408D2F3AE09"_array32, // master_key_02
|
||||
"4F36C565D13325F65EE134073C6A578FFCB0008E02D69400836844EAB7432754"_array32, // master_key_03
|
||||
"75FF1D95D26113550EE6FCC20ACB58E97EDEB3A2FF52543ED5AEC63BDCC3DA50"_array32, // master_key_04
|
||||
"EBE2BCD6704673EC0F88A187BB2AD9F1CC82B718C389425941BDC194DC46B0DD"_array32, // master_key_05
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_06
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_07
|
||||
// clang-format off
|
||||
constexpr std::array master_key_hashes{
|
||||
AsArray("0EE359BE3C864BB0782E1D70A718A0342C551EED28C369754F9C4F691BECF7CA"), // master_key_00
|
||||
AsArray("4FE707B7E4ABDAF727C894AAF13B1351BFE2AC90D875F73B2E20FA94B9CC661E"), // master_key_01
|
||||
AsArray("79277C0237A2252EC3DFAC1F7C359C2B3D121E9DB15BB9AB4C2B4408D2F3AE09"), // master_key_02
|
||||
AsArray("4F36C565D13325F65EE134073C6A578FFCB0008E02D69400836844EAB7432754"), // master_key_03
|
||||
AsArray("75FF1D95D26113550EE6FCC20ACB58E97EDEB3A2FF52543ED5AEC63BDCC3DA50"), // master_key_04
|
||||
AsArray("EBE2BCD6704673EC0F88A187BB2AD9F1CC82B718C389425941BDC194DC46B0DD"), // master_key_05
|
||||
AsArray("9497E6779F5D840F2BBA1DE4E95BA1D6F21EFC94717D5AE5CA37D7EC5BD37A19"), // master_key_06
|
||||
AsArray("4EC96B8CB01B8DCE382149443430B2B6EBCB2983348AFA04A25E53609DABEDF6"), // master_key_07
|
||||
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_08
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_09
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0A
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0B
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0C
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0D
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0E
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0F
|
||||
AsArray("2998E2E23609BC2675FF062A2D64AF5B1B78DFF463B24119D64A1B64F01B2D51"), // master_key_08
|
||||
AsArray("9D486A98067C44B37CF173D3BF577891EB6081FF6B4A166347D9DBBF7025076B"), // master_key_09
|
||||
AsArray("4EC5A237A75A083A9C5F6CF615601522A7F822D06BD4BA32612C9CEBBB29BD45"), // master_key_0A
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0B
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0C
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0D
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0E
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0F
|
||||
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_10
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_11
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_12
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_13
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_14
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_15
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_16
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_17
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_10
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_11
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_12
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_13
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_14
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_15
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_16
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_17
|
||||
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_18
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_19
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1A
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1B
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1C
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1D
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1E
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1F
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_18
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_19
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1A
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1B
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1C
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1D
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1E
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1F
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
static constexpr u8 CalculateMaxKeyblobSourceHash() {
|
||||
const auto is_zero = [](const auto& data) {
|
||||
// TODO: Replace with std::all_of whenever mingw decides to update their
|
||||
// libraries to include the constexpr variant of it.
|
||||
for (const auto element : data) {
|
||||
if (element != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
static u8 CalculateMaxKeyblobSourceHash() {
|
||||
for (s8 i = 0x1F; i >= 0; --i) {
|
||||
if (keyblob_source_hashes[i] != SHA256Hash{})
|
||||
if (!is_zero(keyblob_source_hashes[i])) {
|
||||
return static_cast<u8>(i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -346,12 +364,11 @@ FileSys::VirtualFile PartitionDataManager::GetPackage2Raw(Package2Type type) con
|
||||
}
|
||||
|
||||
static bool AttemptDecrypt(const std::array<u8, 16>& key, Package2Header& header) {
|
||||
const std::vector<u8> iv(header.header_ctr.begin(), header.header_ctr.end());
|
||||
Package2Header temp = header;
|
||||
AESCipher<Key128> cipher(key, Mode::CTR);
|
||||
cipher.SetIV(iv);
|
||||
cipher.Transcode(&temp.header_ctr, sizeof(Package2Header) - 0x100, &temp.header_ctr,
|
||||
Op::Decrypt);
|
||||
cipher.SetIV(header.header_ctr);
|
||||
cipher.Transcode(&temp.header_ctr, sizeof(Package2Header) - sizeof(Package2Header::signature),
|
||||
&temp.header_ctr, Op::Decrypt);
|
||||
if (temp.magic == Common::MakeMagic('P', 'K', '2', '1')) {
|
||||
header = temp;
|
||||
return true;
|
||||
@@ -388,7 +405,7 @@ void PartitionDataManager::DecryptPackage2(const std::array<Key128, 0x20>& packa
|
||||
auto c = a->ReadAllBytes();
|
||||
|
||||
AESCipher<Key128> cipher(package2_keys[revision], Mode::CTR);
|
||||
cipher.SetIV({header.section_ctr[1].begin(), header.section_ctr[1].end()});
|
||||
cipher.SetIV(header.section_ctr[1]);
|
||||
cipher.Transcode(c.data(), c.size(), c.data(), Op::Decrypt);
|
||||
|
||||
const auto ini_file = std::make_shared<FileSys::VectorVfsFile>(c);
|
||||
|
||||
@@ -86,7 +86,7 @@ VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id) const {
|
||||
auto& keys = Core::Crypto::KeyManager::Instance();
|
||||
Core::Crypto::PartitionDataManager pdm{
|
||||
Core::System::GetInstance().GetFilesystem()->OpenDirectory(
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir), Mode::Read)};
|
||||
Common::FS::GetUserPath(Common::FS::UserPath::SysDataDir), Mode::Read)};
|
||||
keys.PopulateFromPartitionData(pdm);
|
||||
|
||||
switch (id) {
|
||||
|
||||
@@ -495,9 +495,10 @@ VirtualFile NCA::Decrypt(const NCASectionHeader& s_header, VirtualFile in, u64 s
|
||||
|
||||
auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>(std::move(in), *key,
|
||||
starting_offset);
|
||||
std::vector<u8> iv(16);
|
||||
for (u8 i = 0; i < 8; ++i)
|
||||
iv[i] = s_header.raw.section_ctr[0x8 - i - 1];
|
||||
Core::Crypto::CTREncryptionLayer::IVData iv{};
|
||||
for (std::size_t i = 0; i < 8; ++i) {
|
||||
iv[i] = s_header.raw.section_ctr[8 - i - 1];
|
||||
}
|
||||
out->SetIV(iv);
|
||||
return std::static_pointer_cast<VfsFile>(out);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
|
||||
@@ -66,7 +67,7 @@ std::size_t BKTR::Read(u8* data, std::size_t length, std::size_t offset) const {
|
||||
Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(key, Core::Crypto::Mode::CTR);
|
||||
|
||||
// Calculate AES IV
|
||||
std::vector<u8> iv(16);
|
||||
std::array<u8, 16> iv{};
|
||||
auto subsection_ctr = subsection.ctr;
|
||||
auto offset_iv = section_offset + base_offset;
|
||||
for (std::size_t i = 0; i < section_ctr.size(); ++i)
|
||||
|
||||
@@ -728,7 +728,7 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti
|
||||
LOG_WARNING(Loader, "Overwriting existing NCA...");
|
||||
VirtualDir c_dir;
|
||||
{ c_dir = dir->GetFileRelative(path)->GetContainingDirectory(); }
|
||||
c_dir->DeleteFile(FileUtil::GetFilename(path));
|
||||
c_dir->DeleteFile(Common::FS::GetFilename(path));
|
||||
}
|
||||
|
||||
auto out = dir->CreateFileRelative(path);
|
||||
|
||||
@@ -133,9 +133,9 @@ public:
|
||||
// Parsing function defines the conversion from raw file to NCA. If there are other steps
|
||||
// besides creating the NCA from the file (e.g. NAX0 on SD Card), that should go in a custom
|
||||
// parsing function.
|
||||
explicit RegisteredCache(VirtualDir dir,
|
||||
ContentProviderParsingFunction parsing_function =
|
||||
[](const VirtualFile& file, const NcaID& id) { return file; });
|
||||
explicit RegisteredCache(
|
||||
VirtualDir dir, ContentProviderParsingFunction parsing_function =
|
||||
[](const VirtualFile& file, const NcaID& id) { return file; });
|
||||
~RegisteredCache() override;
|
||||
|
||||
void Refresh() override;
|
||||
|
||||
@@ -27,18 +27,12 @@ VirtualDir MiiModel() {
|
||||
auto out = std::make_shared<VectorVfsDirectory>(std::vector<VirtualFile>{},
|
||||
std::vector<VirtualDir>{}, "data");
|
||||
|
||||
out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_LOW_LINEAR.size()>>(
|
||||
MiiModelData::TEXTURE_LOW_LINEAR, "NXTextureLowLinear.dat"));
|
||||
out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_LOW_SRGB.size()>>(
|
||||
MiiModelData::TEXTURE_LOW_SRGB, "NXTextureLowSRGB.dat"));
|
||||
out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_MID_LINEAR.size()>>(
|
||||
MiiModelData::TEXTURE_MID_LINEAR, "NXTextureMidLinear.dat"));
|
||||
out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_MID_SRGB.size()>>(
|
||||
MiiModelData::TEXTURE_MID_SRGB, "NXTextureMidSRGB.dat"));
|
||||
out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::SHAPE_HIGH.size()>>(
|
||||
MiiModelData::SHAPE_HIGH, "ShapeHigh.dat"));
|
||||
out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::SHAPE_MID.size()>>(
|
||||
MiiModelData::SHAPE_MID, "ShapeMid.dat"));
|
||||
out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_LOW_LINEAR, "NXTextureLowLinear.dat"));
|
||||
out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_LOW_SRGB, "NXTextureLowSRGB.dat"));
|
||||
out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_MID_LINEAR, "NXTextureMidLinear.dat"));
|
||||
out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_MID_SRGB, "NXTextureMidSRGB.dat"));
|
||||
out->AddFile(MakeArrayFile(MiiModelData::SHAPE_HIGH, "ShapeHigh.dat"));
|
||||
out->AddFile(MakeArrayFile(MiiModelData::SHAPE_MID, "ShapeMid.dat"));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -24,19 +24,18 @@ constexpr std::array<u8, 30> WORD_TXT{
|
||||
} // namespace NgWord1Data
|
||||
|
||||
VirtualDir NgWord1() {
|
||||
std::vector<VirtualFile> files(NgWord1Data::NUMBER_WORD_TXT_FILES);
|
||||
std::vector<VirtualFile> files;
|
||||
files.reserve(NgWord1Data::NUMBER_WORD_TXT_FILES);
|
||||
|
||||
for (std::size_t i = 0; i < files.size(); ++i) {
|
||||
files[i] = std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>(
|
||||
NgWord1Data::WORD_TXT, fmt::format("{}.txt", i));
|
||||
files.push_back(MakeArrayFile(NgWord1Data::WORD_TXT, fmt::format("{}.txt", i)));
|
||||
}
|
||||
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>(
|
||||
NgWord1Data::WORD_TXT, "common.txt"));
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::VERSION_DAT.size()>>(
|
||||
NgWord1Data::VERSION_DAT, "version.dat"));
|
||||
files.push_back(MakeArrayFile(NgWord1Data::WORD_TXT, "common.txt"));
|
||||
files.push_back(MakeArrayFile(NgWord1Data::VERSION_DAT, "version.dat"));
|
||||
|
||||
return std::make_shared<VectorVfsDirectory>(files, std::vector<VirtualDir>{}, "data");
|
||||
return std::make_shared<VectorVfsDirectory>(std::move(files), std::vector<VirtualDir>{},
|
||||
"data");
|
||||
}
|
||||
|
||||
namespace NgWord2Data {
|
||||
@@ -55,27 +54,22 @@ constexpr std::array<u8, 0x2C> AC_NX_DATA{
|
||||
} // namespace NgWord2Data
|
||||
|
||||
VirtualDir NgWord2() {
|
||||
std::vector<VirtualFile> files(NgWord2Data::NUMBER_AC_NX_FILES * 3);
|
||||
std::vector<VirtualFile> files;
|
||||
files.reserve(NgWord2Data::NUMBER_AC_NX_FILES * 3);
|
||||
|
||||
for (std::size_t i = 0; i < NgWord2Data::NUMBER_AC_NX_FILES; ++i) {
|
||||
files[3 * i] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b1_nx", i));
|
||||
files[3 * i + 1] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b2_nx", i));
|
||||
files[3 * i + 2] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_not_b_nx", i));
|
||||
files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b1_nx", i)));
|
||||
files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b2_nx", i)));
|
||||
files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_not_b_nx", i)));
|
||||
}
|
||||
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, "ac_common_b1_nx"));
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, "ac_common_b2_nx"));
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, "ac_common_not_b_nx"));
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::VERSION_DAT.size()>>(
|
||||
NgWord2Data::VERSION_DAT, "version.dat"));
|
||||
files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, "ac_common_b1_nx"));
|
||||
files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, "ac_common_b2_nx"));
|
||||
files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, "ac_common_not_b_nx"));
|
||||
files.push_back(MakeArrayFile(NgWord2Data::VERSION_DAT, "version.dat"));
|
||||
|
||||
return std::make_shared<VectorVfsDirectory>(files, std::vector<VirtualDir>{}, "data");
|
||||
return std::make_shared<VectorVfsDirectory>(std::move(files), std::vector<VirtualDir>{},
|
||||
"data");
|
||||
}
|
||||
|
||||
} // namespace FileSys::SystemArchive
|
||||
|
||||
@@ -654,12 +654,13 @@ static VirtualFile GenerateDefaultTimeZoneFile() {
|
||||
}
|
||||
|
||||
VirtualDir TimeZoneBinary() {
|
||||
const std::vector<VirtualDir> root_dirs{std::make_shared<VectorVfsDirectory>(
|
||||
std::vector<VirtualDir> root_dirs{std::make_shared<VectorVfsDirectory>(
|
||||
std::vector<VirtualFile>{GenerateDefaultTimeZoneFile()}, std::vector<VirtualDir>{},
|
||||
"zoneinfo")};
|
||||
const std::vector<VirtualFile> root_files{
|
||||
std::make_shared<ArrayVfsFile<LOCATION_NAMES.size()>>(LOCATION_NAMES, "binaryList.txt")};
|
||||
return std::make_shared<VectorVfsDirectory>(root_files, root_dirs, "data");
|
||||
std::vector<VirtualFile> root_files{MakeArrayFile(LOCATION_NAMES, "binaryList.txt")};
|
||||
|
||||
return std::make_shared<VectorVfsDirectory>(std::move(root_files), std::move(root_dirs),
|
||||
"data");
|
||||
}
|
||||
|
||||
} // namespace FileSys::SystemArchive
|
||||
|
||||
@@ -30,7 +30,7 @@ bool VfsFilesystem::IsWritable() const {
|
||||
}
|
||||
|
||||
VfsEntryType VfsFilesystem::GetEntryType(std::string_view path_) const {
|
||||
const auto path = FileUtil::SanitizePath(path_);
|
||||
const auto path = Common::FS::SanitizePath(path_);
|
||||
if (root->GetFileRelative(path) != nullptr)
|
||||
return VfsEntryType::File;
|
||||
if (root->GetDirectoryRelative(path) != nullptr)
|
||||
@@ -40,22 +40,22 @@ VfsEntryType VfsFilesystem::GetEntryType(std::string_view path_) const {
|
||||
}
|
||||
|
||||
VirtualFile VfsFilesystem::OpenFile(std::string_view path_, Mode perms) {
|
||||
const auto path = FileUtil::SanitizePath(path_);
|
||||
const auto path = Common::FS::SanitizePath(path_);
|
||||
return root->GetFileRelative(path);
|
||||
}
|
||||
|
||||
VirtualFile VfsFilesystem::CreateFile(std::string_view path_, Mode perms) {
|
||||
const auto path = FileUtil::SanitizePath(path_);
|
||||
const auto path = Common::FS::SanitizePath(path_);
|
||||
return root->CreateFileRelative(path);
|
||||
}
|
||||
|
||||
VirtualFile VfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) {
|
||||
const auto old_path = FileUtil::SanitizePath(old_path_);
|
||||
const auto new_path = FileUtil::SanitizePath(new_path_);
|
||||
const auto old_path = Common::FS::SanitizePath(old_path_);
|
||||
const auto new_path = Common::FS::SanitizePath(new_path_);
|
||||
|
||||
// VfsDirectory impls are only required to implement copy across the current directory.
|
||||
if (FileUtil::GetParentPath(old_path) == FileUtil::GetParentPath(new_path)) {
|
||||
if (!root->Copy(FileUtil::GetFilename(old_path), FileUtil::GetFilename(new_path)))
|
||||
if (Common::FS::GetParentPath(old_path) == Common::FS::GetParentPath(new_path)) {
|
||||
if (!root->Copy(Common::FS::GetFilename(old_path), Common::FS::GetFilename(new_path)))
|
||||
return nullptr;
|
||||
return OpenFile(new_path, Mode::ReadWrite);
|
||||
}
|
||||
@@ -76,8 +76,8 @@ VirtualFile VfsFilesystem::CopyFile(std::string_view old_path_, std::string_view
|
||||
}
|
||||
|
||||
VirtualFile VfsFilesystem::MoveFile(std::string_view old_path, std::string_view new_path) {
|
||||
const auto sanitized_old_path = FileUtil::SanitizePath(old_path);
|
||||
const auto sanitized_new_path = FileUtil::SanitizePath(new_path);
|
||||
const auto sanitized_old_path = Common::FS::SanitizePath(old_path);
|
||||
const auto sanitized_new_path = Common::FS::SanitizePath(new_path);
|
||||
|
||||
// Again, non-default impls are highly encouraged to provide a more optimized version of this.
|
||||
auto out = CopyFile(sanitized_old_path, sanitized_new_path);
|
||||
@@ -89,26 +89,26 @@ VirtualFile VfsFilesystem::MoveFile(std::string_view old_path, std::string_view
|
||||
}
|
||||
|
||||
bool VfsFilesystem::DeleteFile(std::string_view path_) {
|
||||
const auto path = FileUtil::SanitizePath(path_);
|
||||
auto parent = OpenDirectory(FileUtil::GetParentPath(path), Mode::Write);
|
||||
const auto path = Common::FS::SanitizePath(path_);
|
||||
auto parent = OpenDirectory(Common::FS::GetParentPath(path), Mode::Write);
|
||||
if (parent == nullptr)
|
||||
return false;
|
||||
return parent->DeleteFile(FileUtil::GetFilename(path));
|
||||
return parent->DeleteFile(Common::FS::GetFilename(path));
|
||||
}
|
||||
|
||||
VirtualDir VfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) {
|
||||
const auto path = FileUtil::SanitizePath(path_);
|
||||
const auto path = Common::FS::SanitizePath(path_);
|
||||
return root->GetDirectoryRelative(path);
|
||||
}
|
||||
|
||||
VirtualDir VfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) {
|
||||
const auto path = FileUtil::SanitizePath(path_);
|
||||
const auto path = Common::FS::SanitizePath(path_);
|
||||
return root->CreateDirectoryRelative(path);
|
||||
}
|
||||
|
||||
VirtualDir VfsFilesystem::CopyDirectory(std::string_view old_path_, std::string_view new_path_) {
|
||||
const auto old_path = FileUtil::SanitizePath(old_path_);
|
||||
const auto new_path = FileUtil::SanitizePath(new_path_);
|
||||
const auto old_path = Common::FS::SanitizePath(old_path_);
|
||||
const auto new_path = Common::FS::SanitizePath(new_path_);
|
||||
|
||||
// Non-default impls are highly encouraged to provide a more optimized version of this.
|
||||
auto old_dir = OpenDirectory(old_path, Mode::Read);
|
||||
@@ -139,8 +139,8 @@ VirtualDir VfsFilesystem::CopyDirectory(std::string_view old_path_, std::string_
|
||||
}
|
||||
|
||||
VirtualDir VfsFilesystem::MoveDirectory(std::string_view old_path, std::string_view new_path) {
|
||||
const auto sanitized_old_path = FileUtil::SanitizePath(old_path);
|
||||
const auto sanitized_new_path = FileUtil::SanitizePath(new_path);
|
||||
const auto sanitized_old_path = Common::FS::SanitizePath(old_path);
|
||||
const auto sanitized_new_path = Common::FS::SanitizePath(new_path);
|
||||
|
||||
// Non-default impls are highly encouraged to provide a more optimized version of this.
|
||||
auto out = CopyDirectory(sanitized_old_path, sanitized_new_path);
|
||||
@@ -152,17 +152,17 @@ VirtualDir VfsFilesystem::MoveDirectory(std::string_view old_path, std::string_v
|
||||
}
|
||||
|
||||
bool VfsFilesystem::DeleteDirectory(std::string_view path_) {
|
||||
const auto path = FileUtil::SanitizePath(path_);
|
||||
auto parent = OpenDirectory(FileUtil::GetParentPath(path), Mode::Write);
|
||||
const auto path = Common::FS::SanitizePath(path_);
|
||||
auto parent = OpenDirectory(Common::FS::GetParentPath(path), Mode::Write);
|
||||
if (parent == nullptr)
|
||||
return false;
|
||||
return parent->DeleteSubdirectoryRecursive(FileUtil::GetFilename(path));
|
||||
return parent->DeleteSubdirectoryRecursive(Common::FS::GetFilename(path));
|
||||
}
|
||||
|
||||
VfsFile::~VfsFile() = default;
|
||||
|
||||
std::string VfsFile::GetExtension() const {
|
||||
return std::string(FileUtil::GetExtensionFromFilename(GetName()));
|
||||
return std::string(Common::FS::GetExtensionFromFilename(GetName()));
|
||||
}
|
||||
|
||||
VfsDirectory::~VfsDirectory() = default;
|
||||
@@ -203,7 +203,7 @@ std::string VfsFile::GetFullPath() const {
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(std::string_view path) const {
|
||||
auto vec = FileUtil::SplitPathComponents(path);
|
||||
auto vec = Common::FS::SplitPathComponents(path);
|
||||
vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
|
||||
vec.end());
|
||||
if (vec.empty()) {
|
||||
@@ -239,7 +239,7 @@ std::shared_ptr<VfsFile> VfsDirectory::GetFileAbsolute(std::string_view path) co
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryRelative(std::string_view path) const {
|
||||
auto vec = FileUtil::SplitPathComponents(path);
|
||||
auto vec = Common::FS::SplitPathComponents(path);
|
||||
vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
|
||||
vec.end());
|
||||
if (vec.empty()) {
|
||||
@@ -301,7 +301,7 @@ std::size_t VfsDirectory::GetSize() const {
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsFile> VfsDirectory::CreateFileRelative(std::string_view path) {
|
||||
auto vec = FileUtil::SplitPathComponents(path);
|
||||
auto vec = Common::FS::SplitPathComponents(path);
|
||||
vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
|
||||
vec.end());
|
||||
if (vec.empty()) {
|
||||
@@ -320,7 +320,7 @@ std::shared_ptr<VfsFile> VfsDirectory::CreateFileRelative(std::string_view path)
|
||||
}
|
||||
}
|
||||
|
||||
return dir->CreateFileRelative(FileUtil::GetPathWithoutTop(path));
|
||||
return dir->CreateFileRelative(Common::FS::GetPathWithoutTop(path));
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsFile> VfsDirectory::CreateFileAbsolute(std::string_view path) {
|
||||
@@ -332,7 +332,7 @@ std::shared_ptr<VfsFile> VfsDirectory::CreateFileAbsolute(std::string_view path)
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryRelative(std::string_view path) {
|
||||
auto vec = FileUtil::SplitPathComponents(path);
|
||||
auto vec = Common::FS::SplitPathComponents(path);
|
||||
vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
|
||||
vec.end());
|
||||
if (vec.empty()) {
|
||||
@@ -351,7 +351,7 @@ std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryRelative(std::string_
|
||||
}
|
||||
}
|
||||
|
||||
return dir->CreateDirectoryRelative(FileUtil::GetPathWithoutTop(path));
|
||||
return dir->CreateDirectoryRelative(Common::FS::GetPathWithoutTop(path));
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryAbsolute(std::string_view path) {
|
||||
|
||||
@@ -49,7 +49,7 @@ VirtualDir ExtractZIP(VirtualFile file) {
|
||||
if (zip_fread(file2.get(), buf.data(), buf.size()) != s64(buf.size()))
|
||||
return nullptr;
|
||||
|
||||
const auto parts = FileUtil::SplitPathComponents(stat.name);
|
||||
const auto parts = Common::FS::SplitPathComponents(stat.name);
|
||||
const auto new_file = std::make_shared<VectorVfsFile>(buf, parts.back());
|
||||
|
||||
std::shared_ptr<VectorVfsDirectory> dtrv = out;
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
namespace FS = Common::FS;
|
||||
|
||||
static std::string ModeFlagsToString(Mode mode) {
|
||||
std::string mode_str;
|
||||
|
||||
@@ -57,79 +59,82 @@ bool RealVfsFilesystem::IsWritable() const {
|
||||
}
|
||||
|
||||
VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const {
|
||||
const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
if (!FileUtil::Exists(path))
|
||||
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
|
||||
if (!FS::Exists(path)) {
|
||||
return VfsEntryType::None;
|
||||
if (FileUtil::IsDirectory(path))
|
||||
}
|
||||
if (FS::IsDirectory(path)) {
|
||||
return VfsEntryType::Directory;
|
||||
}
|
||||
|
||||
return VfsEntryType::File;
|
||||
}
|
||||
|
||||
VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) {
|
||||
const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
if (cache.find(path) != cache.end()) {
|
||||
auto weak = cache[path];
|
||||
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
|
||||
|
||||
if (const auto weak_iter = cache.find(path); weak_iter != cache.cend()) {
|
||||
const auto& weak = weak_iter->second;
|
||||
|
||||
if (!weak.expired()) {
|
||||
return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, weak.lock(), path, perms));
|
||||
}
|
||||
}
|
||||
|
||||
if (!FileUtil::Exists(path) && True(perms & Mode::WriteAppend)) {
|
||||
FileUtil::CreateEmptyFile(path);
|
||||
if (!FS::Exists(path) && True(perms & Mode::WriteAppend)) {
|
||||
FS::CreateEmptyFile(path);
|
||||
}
|
||||
|
||||
auto backing = std::make_shared<FileUtil::IOFile>(path, ModeFlagsToString(perms).c_str());
|
||||
cache[path] = backing;
|
||||
auto backing = std::make_shared<FS::IOFile>(path, ModeFlagsToString(perms).c_str());
|
||||
cache.insert_or_assign(path, backing);
|
||||
|
||||
// Cannot use make_shared as RealVfsFile constructor is private
|
||||
return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, backing, path, perms));
|
||||
}
|
||||
|
||||
VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) {
|
||||
const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
const auto path_fwd = FileUtil::SanitizePath(path, FileUtil::DirectorySeparator::ForwardSlash);
|
||||
if (!FileUtil::Exists(path)) {
|
||||
FileUtil::CreateFullPath(path_fwd);
|
||||
if (!FileUtil::CreateEmptyFile(path))
|
||||
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
|
||||
const auto path_fwd = FS::SanitizePath(path, FS::DirectorySeparator::ForwardSlash);
|
||||
if (!FS::Exists(path)) {
|
||||
FS::CreateFullPath(path_fwd);
|
||||
if (!FS::CreateEmptyFile(path)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return OpenFile(path, perms);
|
||||
}
|
||||
|
||||
VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) {
|
||||
const auto old_path =
|
||||
FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
const auto new_path =
|
||||
FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault);
|
||||
const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault);
|
||||
|
||||
if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
|
||||
FileUtil::IsDirectory(old_path) || !FileUtil::Copy(old_path, new_path))
|
||||
if (!FS::Exists(old_path) || FS::Exists(new_path) || FS::IsDirectory(old_path) ||
|
||||
!FS::Copy(old_path, new_path)) {
|
||||
return nullptr;
|
||||
}
|
||||
return OpenFile(new_path, Mode::ReadWrite);
|
||||
}
|
||||
|
||||
VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) {
|
||||
const auto old_path =
|
||||
FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
const auto new_path =
|
||||
FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault);
|
||||
const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault);
|
||||
const auto cached_file_iter = cache.find(old_path);
|
||||
|
||||
if (cache.find(old_path) != cache.end()) {
|
||||
auto file = cache[old_path].lock();
|
||||
if (cached_file_iter != cache.cend()) {
|
||||
auto file = cached_file_iter->second.lock();
|
||||
|
||||
if (!cache[old_path].expired()) {
|
||||
if (!cached_file_iter->second.expired()) {
|
||||
file->Close();
|
||||
}
|
||||
|
||||
if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
|
||||
FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path)) {
|
||||
if (!FS::Exists(old_path) || FS::Exists(new_path) || FS::IsDirectory(old_path) ||
|
||||
!FS::Rename(old_path, new_path)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cache.erase(old_path);
|
||||
file->Open(new_path, "r+b");
|
||||
cache[new_path] = file;
|
||||
cache.insert_or_assign(new_path, std::move(file));
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
return nullptr;
|
||||
@@ -139,28 +144,33 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_
|
||||
}
|
||||
|
||||
bool RealVfsFilesystem::DeleteFile(std::string_view path_) {
|
||||
const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
if (cache.find(path) != cache.end()) {
|
||||
if (!cache[path].expired())
|
||||
cache[path].lock()->Close();
|
||||
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
|
||||
const auto cached_iter = cache.find(path);
|
||||
|
||||
if (cached_iter != cache.cend()) {
|
||||
if (!cached_iter->second.expired()) {
|
||||
cached_iter->second.lock()->Close();
|
||||
}
|
||||
cache.erase(path);
|
||||
}
|
||||
return FileUtil::Delete(path);
|
||||
|
||||
return FS::Delete(path);
|
||||
}
|
||||
|
||||
VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) {
|
||||
const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
|
||||
// Cannot use make_shared as RealVfsDirectory constructor is private
|
||||
return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms));
|
||||
}
|
||||
|
||||
VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) {
|
||||
const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
const auto path_fwd = FileUtil::SanitizePath(path, FileUtil::DirectorySeparator::ForwardSlash);
|
||||
if (!FileUtil::Exists(path)) {
|
||||
FileUtil::CreateFullPath(path_fwd);
|
||||
if (!FileUtil::CreateDir(path))
|
||||
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
|
||||
const auto path_fwd = FS::SanitizePath(path, FS::DirectorySeparator::ForwardSlash);
|
||||
if (!FS::Exists(path)) {
|
||||
FS::CreateFullPath(path_fwd);
|
||||
if (!FS::CreateDir(path)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
// Cannot use make_shared as RealVfsDirectory constructor is private
|
||||
return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms));
|
||||
@@ -168,67 +178,75 @@ VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms
|
||||
|
||||
VirtualDir RealVfsFilesystem::CopyDirectory(std::string_view old_path_,
|
||||
std::string_view new_path_) {
|
||||
const auto old_path =
|
||||
FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
const auto new_path =
|
||||
FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
|
||||
!FileUtil::IsDirectory(old_path))
|
||||
const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault);
|
||||
const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault);
|
||||
if (!FS::Exists(old_path) || FS::Exists(new_path) || !FS::IsDirectory(old_path)) {
|
||||
return nullptr;
|
||||
FileUtil::CopyDir(old_path, new_path);
|
||||
}
|
||||
FS::CopyDir(old_path, new_path);
|
||||
return OpenDirectory(new_path, Mode::ReadWrite);
|
||||
}
|
||||
|
||||
VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_,
|
||||
std::string_view new_path_) {
|
||||
const auto old_path =
|
||||
FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
const auto new_path =
|
||||
FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
|
||||
FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path))
|
||||
const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault);
|
||||
const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault);
|
||||
|
||||
if (!FS::Exists(old_path) || FS::Exists(new_path) || FS::IsDirectory(old_path) ||
|
||||
!FS::Rename(old_path, new_path)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (auto& kv : cache) {
|
||||
// Path in cache starts with old_path
|
||||
if (kv.first.rfind(old_path, 0) == 0) {
|
||||
const auto file_old_path =
|
||||
FileUtil::SanitizePath(kv.first, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
const auto file_new_path =
|
||||
FileUtil::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()),
|
||||
FileUtil::DirectorySeparator::PlatformDefault);
|
||||
auto cached = cache[file_old_path];
|
||||
if (!cached.expired()) {
|
||||
auto file = cached.lock();
|
||||
file->Open(file_new_path, "r+b");
|
||||
cache.erase(file_old_path);
|
||||
cache[file_new_path] = file;
|
||||
}
|
||||
// If the path in the cache doesn't start with old_path, then bail on this file.
|
||||
if (kv.first.rfind(old_path, 0) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto file_old_path =
|
||||
FS::SanitizePath(kv.first, FS::DirectorySeparator::PlatformDefault);
|
||||
auto file_new_path = FS::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()),
|
||||
FS::DirectorySeparator::PlatformDefault);
|
||||
const auto& cached = cache[file_old_path];
|
||||
|
||||
if (cached.expired()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto file = cached.lock();
|
||||
file->Open(file_new_path, "r+b");
|
||||
cache.erase(file_old_path);
|
||||
cache.insert_or_assign(std::move(file_new_path), std::move(file));
|
||||
}
|
||||
|
||||
return OpenDirectory(new_path, Mode::ReadWrite);
|
||||
}
|
||||
|
||||
bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) {
|
||||
const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
|
||||
|
||||
for (auto& kv : cache) {
|
||||
// Path in cache starts with old_path
|
||||
if (kv.first.rfind(path, 0) == 0) {
|
||||
if (!cache[kv.first].expired())
|
||||
cache[kv.first].lock()->Close();
|
||||
cache.erase(kv.first);
|
||||
// If the path in the cache doesn't start with path, then bail on this file.
|
||||
if (kv.first.rfind(path, 0) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& entry = cache[kv.first];
|
||||
if (!entry.expired()) {
|
||||
entry.lock()->Close();
|
||||
}
|
||||
|
||||
cache.erase(kv.first);
|
||||
}
|
||||
return FileUtil::DeleteDirRecursively(path);
|
||||
|
||||
return FS::DeleteDirRecursively(path);
|
||||
}
|
||||
|
||||
RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::shared_ptr<FileUtil::IOFile> backing_,
|
||||
RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::shared_ptr<FS::IOFile> backing_,
|
||||
const std::string& path_, Mode perms_)
|
||||
: base(base_), backing(std::move(backing_)), path(path_),
|
||||
parent_path(FileUtil::GetParentPath(path_)),
|
||||
path_components(FileUtil::SplitPathComponents(path_)),
|
||||
parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)),
|
||||
: base(base_), backing(std::move(backing_)), path(path_), parent_path(FS::GetParentPath(path_)),
|
||||
path_components(FS::SplitPathComponents(path_)),
|
||||
parent_components(FS::SliceVector(path_components, 0, path_components.size() - 1)),
|
||||
perms(perms_) {}
|
||||
|
||||
RealVfsFile::~RealVfsFile() = default;
|
||||
@@ -258,14 +276,16 @@ bool RealVfsFile::IsReadable() const {
|
||||
}
|
||||
|
||||
std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const {
|
||||
if (!backing->Seek(offset, SEEK_SET))
|
||||
if (!backing->Seek(static_cast<s64>(offset), SEEK_SET)) {
|
||||
return 0;
|
||||
}
|
||||
return backing->ReadBytes(data, length);
|
||||
}
|
||||
|
||||
std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) {
|
||||
if (!backing->Seek(offset, SEEK_SET))
|
||||
if (!backing->Seek(static_cast<s64>(offset), SEEK_SET)) {
|
||||
return 0;
|
||||
}
|
||||
return backing->WriteBytes(data, length);
|
||||
}
|
||||
|
||||
@@ -282,16 +302,18 @@ bool RealVfsFile::Close() {
|
||||
|
||||
template <>
|
||||
std::vector<VirtualFile> RealVfsDirectory::IterateEntries<RealVfsFile, VfsFile>() const {
|
||||
if (perms == Mode::Append)
|
||||
if (perms == Mode::Append) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<VirtualFile> out;
|
||||
FileUtil::ForeachDirectoryEntry(
|
||||
FS::ForeachDirectoryEntry(
|
||||
nullptr, path,
|
||||
[&out, this](u64* entries_out, const std::string& directory, const std::string& filename) {
|
||||
const std::string full_path = directory + DIR_SEP + filename;
|
||||
if (!FileUtil::IsDirectory(full_path))
|
||||
if (!FS::IsDirectory(full_path)) {
|
||||
out.emplace_back(base.OpenFile(full_path, perms));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -300,16 +322,18 @@ std::vector<VirtualFile> RealVfsDirectory::IterateEntries<RealVfsFile, VfsFile>(
|
||||
|
||||
template <>
|
||||
std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDirectory>() const {
|
||||
if (perms == Mode::Append)
|
||||
if (perms == Mode::Append) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<VirtualDir> out;
|
||||
FileUtil::ForeachDirectoryEntry(
|
||||
FS::ForeachDirectoryEntry(
|
||||
nullptr, path,
|
||||
[&out, this](u64* entries_out, const std::string& directory, const std::string& filename) {
|
||||
const std::string full_path = directory + DIR_SEP + filename;
|
||||
if (FileUtil::IsDirectory(full_path))
|
||||
if (FS::IsDirectory(full_path)) {
|
||||
out.emplace_back(base.OpenDirectory(full_path, perms));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -317,29 +341,30 @@ std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDi
|
||||
}
|
||||
|
||||
RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string& path_, Mode perms_)
|
||||
: base(base_), path(FileUtil::RemoveTrailingSlash(path_)),
|
||||
parent_path(FileUtil::GetParentPath(path)),
|
||||
path_components(FileUtil::SplitPathComponents(path)),
|
||||
parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)),
|
||||
: base(base_), path(FS::RemoveTrailingSlash(path_)), parent_path(FS::GetParentPath(path)),
|
||||
path_components(FS::SplitPathComponents(path)),
|
||||
parent_components(FS::SliceVector(path_components, 0, path_components.size() - 1)),
|
||||
perms(perms_) {
|
||||
if (!FileUtil::Exists(path) && True(perms & Mode::WriteAppend)) {
|
||||
FileUtil::CreateDir(path);
|
||||
if (!FS::Exists(path) && True(perms & Mode::WriteAppend)) {
|
||||
FS::CreateDir(path);
|
||||
}
|
||||
}
|
||||
|
||||
RealVfsDirectory::~RealVfsDirectory() = default;
|
||||
|
||||
std::shared_ptr<VfsFile> RealVfsDirectory::GetFileRelative(std::string_view path) const {
|
||||
const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||
if (!FileUtil::Exists(full_path) || FileUtil::IsDirectory(full_path))
|
||||
const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||
if (!FS::Exists(full_path) || FS::IsDirectory(full_path)) {
|
||||
return nullptr;
|
||||
}
|
||||
return base.OpenFile(full_path, perms);
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsDirectory> RealVfsDirectory::GetDirectoryRelative(std::string_view path) const {
|
||||
const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||
if (!FileUtil::Exists(full_path) || !FileUtil::IsDirectory(full_path))
|
||||
const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||
if (!FS::Exists(full_path) || !FS::IsDirectory(full_path)) {
|
||||
return nullptr;
|
||||
}
|
||||
return base.OpenDirectory(full_path, perms);
|
||||
}
|
||||
|
||||
@@ -352,17 +377,17 @@ std::shared_ptr<VfsDirectory> RealVfsDirectory::GetSubdirectory(std::string_view
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsFile> RealVfsDirectory::CreateFileRelative(std::string_view path) {
|
||||
const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||
const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||
return base.CreateFile(full_path, perms);
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateDirectoryRelative(std::string_view path) {
|
||||
const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||
const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||
return base.CreateDirectory(full_path, perms);
|
||||
}
|
||||
|
||||
bool RealVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
|
||||
auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(name));
|
||||
const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(name));
|
||||
return base.DeleteDirectory(full_path);
|
||||
}
|
||||
|
||||
@@ -387,8 +412,9 @@ std::string RealVfsDirectory::GetName() const {
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsDirectory> RealVfsDirectory::GetParentDirectory() const {
|
||||
if (path_components.size() <= 1)
|
||||
if (path_components.size() <= 1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return base.OpenDirectory(parent_path, perms);
|
||||
}
|
||||
@@ -425,16 +451,17 @@ std::string RealVfsDirectory::GetFullPath() const {
|
||||
}
|
||||
|
||||
std::map<std::string, VfsEntryType, std::less<>> RealVfsDirectory::GetEntries() const {
|
||||
if (perms == Mode::Append)
|
||||
if (perms == Mode::Append) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::map<std::string, VfsEntryType, std::less<>> out;
|
||||
FileUtil::ForeachDirectoryEntry(
|
||||
FS::ForeachDirectoryEntry(
|
||||
nullptr, path,
|
||||
[&out](u64* entries_out, const std::string& directory, const std::string& filename) {
|
||||
const std::string full_path = directory + DIR_SEP + filename;
|
||||
out.emplace(filename, FileUtil::IsDirectory(full_path) ? VfsEntryType::Directory
|
||||
: VfsEntryType::File);
|
||||
out.emplace(filename,
|
||||
FS::IsDirectory(full_path) ? VfsEntryType::Directory : VfsEntryType::File);
|
||||
return true;
|
||||
});
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "core/file_sys/mode.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
|
||||
namespace FileUtil {
|
||||
namespace Common::FS {
|
||||
class IOFile;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
bool DeleteDirectory(std::string_view path) override;
|
||||
|
||||
private:
|
||||
boost::container::flat_map<std::string, std::weak_ptr<FileUtil::IOFile>> cache;
|
||||
boost::container::flat_map<std::string, std::weak_ptr<Common::FS::IOFile>> cache;
|
||||
};
|
||||
|
||||
// An implmentation of VfsFile that represents a file on the user's computer.
|
||||
@@ -58,13 +58,13 @@ public:
|
||||
bool Rename(std::string_view name) override;
|
||||
|
||||
private:
|
||||
RealVfsFile(RealVfsFilesystem& base, std::shared_ptr<FileUtil::IOFile> backing,
|
||||
RealVfsFile(RealVfsFilesystem& base, std::shared_ptr<Common::FS::IOFile> backing,
|
||||
const std::string& path, Mode perms = Mode::Read);
|
||||
|
||||
bool Close();
|
||||
|
||||
RealVfsFilesystem& base;
|
||||
std::shared_ptr<FileUtil::IOFile> backing;
|
||||
std::shared_ptr<Common::FS::IOFile> backing;
|
||||
std::string path;
|
||||
std::string parent_path;
|
||||
std::vector<std::string> path_components;
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "core/file_sys/vfs.h"
|
||||
|
||||
namespace FileSys {
|
||||
@@ -13,7 +17,8 @@ namespace FileSys {
|
||||
template <std::size_t size>
|
||||
class ArrayVfsFile : public VfsFile {
|
||||
public:
|
||||
ArrayVfsFile(std::array<u8, size> data, std::string name = "", VirtualDir parent = nullptr)
|
||||
explicit ArrayVfsFile(const std::array<u8, size>& data, std::string name = "",
|
||||
VirtualDir parent = nullptr)
|
||||
: data(data), name(std::move(name)), parent(std::move(parent)) {}
|
||||
|
||||
std::string GetName() const override {
|
||||
@@ -61,6 +66,12 @@ private:
|
||||
VirtualDir parent;
|
||||
};
|
||||
|
||||
template <std::size_t Size, typename... Args>
|
||||
std::shared_ptr<ArrayVfsFile<Size>> MakeArrayFile(const std::array<u8, Size>& data,
|
||||
Args&&... args) {
|
||||
return std::make_shared<ArrayVfsFile<Size>>(data, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// An implementation of VfsFile that is backed by a vector optionally supplied upon construction
|
||||
class VectorVfsFile : public VfsFile {
|
||||
public:
|
||||
|
||||
@@ -44,7 +44,7 @@ static bool CalculateHMAC256(Destination* out, const SourceKey* key, std::size_t
|
||||
}
|
||||
|
||||
NAX::NAX(VirtualFile file_) : header(std::make_unique<NAXHeader>()), file(std::move(file_)) {
|
||||
std::string path = FileUtil::SanitizePath(file->GetFullPath());
|
||||
std::string path = Common::FS::SanitizePath(file->GetFullPath());
|
||||
static const std::regex nax_path_regex("/registered/(000000[0-9A-F]{2})/([0-9A-F]{32})\\.nca",
|
||||
std::regex_constants::ECMAScript |
|
||||
std::regex_constants::icase);
|
||||
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
|
||||
class Scoped {
|
||||
public:
|
||||
explicit Scoped(GraphicsContext& context_) : context(context_) {
|
||||
[[nodiscard]] explicit Scoped(GraphicsContext& context_) : context(context_) {
|
||||
context.MakeCurrent();
|
||||
}
|
||||
~Scoped() {
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
|
||||
/// Calls MakeCurrent on the context and calls DoneCurrent when the scope for the returned value
|
||||
/// ends
|
||||
Scoped Acquire() {
|
||||
[[nodiscard]] Scoped Acquire() {
|
||||
return Scoped{*this};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -229,6 +229,8 @@ inline void ResponseBuilder::Push(u32 value) {
|
||||
|
||||
template <typename T>
|
||||
void ResponseBuilder::PushRaw(const T& value) {
|
||||
static_assert(std::is_trivially_copyable_v<T>,
|
||||
"It's undefined behavior to use memcpy with non-trivially copyable objects");
|
||||
std::memcpy(cmdbuf + index, &value, sizeof(T));
|
||||
index += (sizeof(T) + 3) / 4; // round up to word length
|
||||
}
|
||||
@@ -384,6 +386,8 @@ inline s32 RequestParser::Pop() {
|
||||
|
||||
template <typename T>
|
||||
void RequestParser::PopRaw(T& value) {
|
||||
static_assert(std::is_trivially_copyable_v<T>,
|
||||
"It's undefined behavior to use memcpy with non-trivially copyable objects");
|
||||
std::memcpy(&value, cmdbuf + index, sizeof(T));
|
||||
index += (sizeof(T) + 3) / 4; // round up to word length
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32
|
||||
do {
|
||||
current_value = monitor.ExclusiveRead32(current_core, address);
|
||||
|
||||
if (current_value != value) {
|
||||
if (current_value != static_cast<u32>(value)) {
|
||||
return ERR_INVALID_STATE;
|
||||
}
|
||||
current_value++;
|
||||
|
||||
@@ -293,13 +293,15 @@ std::vector<u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
|
||||
BufferDescriptorA()[buffer_index].Size()};
|
||||
|
||||
if (is_buffer_a) {
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorA().size() > buffer_index, { return buffer; },
|
||||
"BufferDescriptorA invalid buffer_index {}", buffer_index);
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
BufferDescriptorA().size() > buffer_index, { return buffer; },
|
||||
"BufferDescriptorA invalid buffer_index {}", buffer_index);
|
||||
buffer.resize(BufferDescriptorA()[buffer_index].Size());
|
||||
memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size());
|
||||
} else {
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorX().size() > buffer_index, { return buffer; },
|
||||
"BufferDescriptorX invalid buffer_index {}", buffer_index);
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
BufferDescriptorX().size() > buffer_index, { return buffer; },
|
||||
"BufferDescriptorX invalid buffer_index {}", buffer_index);
|
||||
buffer.resize(BufferDescriptorX()[buffer_index].Size());
|
||||
memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size());
|
||||
}
|
||||
@@ -324,16 +326,16 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
|
||||
}
|
||||
|
||||
if (is_buffer_b) {
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorB().size() > buffer_index &&
|
||||
BufferDescriptorB()[buffer_index].Size() >= size,
|
||||
{ return 0; }, "BufferDescriptorB is invalid, index={}, size={}",
|
||||
buffer_index, size);
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
BufferDescriptorB().size() > buffer_index &&
|
||||
BufferDescriptorB()[buffer_index].Size() >= size,
|
||||
{ return 0; }, "BufferDescriptorB is invalid, index={}, size={}", buffer_index, size);
|
||||
memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size);
|
||||
} else {
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorC().size() > buffer_index &&
|
||||
BufferDescriptorC()[buffer_index].Size() >= size,
|
||||
{ return 0; }, "BufferDescriptorC is invalid, index={}, size={}",
|
||||
buffer_index, size);
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
BufferDescriptorC().size() > buffer_index &&
|
||||
BufferDescriptorC()[buffer_index].Size() >= size,
|
||||
{ return 0; }, "BufferDescriptorC is invalid, index={}, size={}", buffer_index, size);
|
||||
memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size);
|
||||
}
|
||||
|
||||
@@ -344,12 +346,14 @@ std::size_t HLERequestContext::GetReadBufferSize(std::size_t buffer_index) const
|
||||
const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
|
||||
BufferDescriptorA()[buffer_index].Size()};
|
||||
if (is_buffer_a) {
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorA().size() > buffer_index, { return 0; },
|
||||
"BufferDescriptorA invalid buffer_index {}", buffer_index);
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
BufferDescriptorA().size() > buffer_index, { return 0; },
|
||||
"BufferDescriptorA invalid buffer_index {}", buffer_index);
|
||||
return BufferDescriptorA()[buffer_index].Size();
|
||||
} else {
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorX().size() > buffer_index, { return 0; },
|
||||
"BufferDescriptorX invalid buffer_index {}", buffer_index);
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
BufferDescriptorX().size() > buffer_index, { return 0; },
|
||||
"BufferDescriptorX invalid buffer_index {}", buffer_index);
|
||||
return BufferDescriptorX()[buffer_index].Size();
|
||||
}
|
||||
}
|
||||
@@ -358,12 +362,14 @@ std::size_t HLERequestContext::GetWriteBufferSize(std::size_t buffer_index) cons
|
||||
const bool is_buffer_b{BufferDescriptorB().size() > buffer_index &&
|
||||
BufferDescriptorB()[buffer_index].Size()};
|
||||
if (is_buffer_b) {
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorB().size() > buffer_index, { return 0; },
|
||||
"BufferDescriptorB invalid buffer_index {}", buffer_index);
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
BufferDescriptorB().size() > buffer_index, { return 0; },
|
||||
"BufferDescriptorB invalid buffer_index {}", buffer_index);
|
||||
return BufferDescriptorB()[buffer_index].Size();
|
||||
} else {
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorC().size() > buffer_index, { return 0; },
|
||||
"BufferDescriptorC invalid buffer_index {}", buffer_index);
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
BufferDescriptorC().size() > buffer_index, { return 0; },
|
||||
"BufferDescriptorC invalid buffer_index {}", buffer_index);
|
||||
return BufferDescriptorC()[buffer_index].Size();
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -604,7 +604,6 @@ ResultCode PageTable::MapPages(VAddr addr, const PageLinkedList& page_linked_lis
|
||||
if (const auto result{
|
||||
Operate(cur_addr, node.GetNumPages(), perm, OperationType::Map, node.GetAddress())};
|
||||
result.IsError()) {
|
||||
const MemoryInfo info{block_manager->FindBlock(cur_addr).GetMemoryInfo()};
|
||||
const std::size_t num_pages{(addr - cur_addr) / PageSize};
|
||||
|
||||
ASSERT(
|
||||
@@ -852,11 +851,12 @@ ResultCode PageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
|
||||
return result;
|
||||
}
|
||||
|
||||
block_manager->UpdateLock(addr, size / PageSize,
|
||||
[](MemoryBlockManager::iterator block, MemoryPermission perm) {
|
||||
block->ShareToDevice(perm);
|
||||
},
|
||||
perm);
|
||||
block_manager->UpdateLock(
|
||||
addr, size / PageSize,
|
||||
[](MemoryBlockManager::iterator block, MemoryPermission perm) {
|
||||
block->ShareToDevice(perm);
|
||||
},
|
||||
perm);
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
@@ -874,11 +874,12 @@ ResultCode PageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size)
|
||||
return result;
|
||||
}
|
||||
|
||||
block_manager->UpdateLock(addr, size / PageSize,
|
||||
[](MemoryBlockManager::iterator block, MemoryPermission perm) {
|
||||
block->UnshareToDevice(perm);
|
||||
},
|
||||
perm);
|
||||
block_manager->UpdateLock(
|
||||
addr, size / PageSize,
|
||||
[](MemoryBlockManager::iterator block, MemoryPermission perm) {
|
||||
block->UnshareToDevice(perm);
|
||||
},
|
||||
perm);
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -7,22 +7,15 @@
|
||||
#include "core/hle/kernel/memory/system_control.h"
|
||||
|
||||
namespace Kernel::Memory::SystemControl {
|
||||
|
||||
u64 GenerateRandomU64ForInit() {
|
||||
static std::random_device device;
|
||||
static std::mt19937 gen(device());
|
||||
static std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
|
||||
return distribution(gen);
|
||||
}
|
||||
|
||||
namespace {
|
||||
template <typename F>
|
||||
u64 GenerateUniformRange(u64 min, u64 max, F f) {
|
||||
/* Handle the case where the difference is too large to represent. */
|
||||
// Handle the case where the difference is too large to represent.
|
||||
if (max == std::numeric_limits<u64>::max() && min == std::numeric_limits<u64>::min()) {
|
||||
return f();
|
||||
}
|
||||
|
||||
/* Iterate until we get a value in range. */
|
||||
// Iterate until we get a value in range.
|
||||
const u64 range_size = ((max + 1) - min);
|
||||
const u64 effective_max = (std::numeric_limits<u64>::max() / range_size) * range_size;
|
||||
while (true) {
|
||||
@@ -32,6 +25,14 @@ u64 GenerateUniformRange(u64 min, u64 max, F f) {
|
||||
}
|
||||
}
|
||||
|
||||
u64 GenerateRandomU64ForInit() {
|
||||
static std::random_device device;
|
||||
static std::mt19937 gen(device());
|
||||
static std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
|
||||
return distribution(gen);
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
u64 GenerateRandomRange(u64 min, u64 max) {
|
||||
return GenerateUniformRange(min, max, GenerateRandomU64ForInit);
|
||||
}
|
||||
|
||||
@@ -8,11 +8,6 @@
|
||||
|
||||
namespace Kernel::Memory::SystemControl {
|
||||
|
||||
u64 GenerateRandomU64ForInit();
|
||||
|
||||
template <typename F>
|
||||
u64 GenerateUniformRange(u64 min, u64 max, F f);
|
||||
|
||||
u64 GenerateRandomRange(u64 min, u64 max);
|
||||
|
||||
} // namespace Kernel::Memory::SystemControl
|
||||
|
||||
@@ -131,7 +131,8 @@ u32 GlobalScheduler::SelectThreads() {
|
||||
u32 cores_needing_context_switch{};
|
||||
for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
|
||||
Scheduler& sched = kernel.Scheduler(core);
|
||||
ASSERT(top_threads[core] == nullptr || top_threads[core]->GetProcessorID() == core);
|
||||
ASSERT(top_threads[core] == nullptr ||
|
||||
static_cast<u32>(top_threads[core]->GetProcessorID()) == core);
|
||||
if (update_thread(top_threads[core], sched)) {
|
||||
cores_needing_context_switch |= (1ul << core);
|
||||
}
|
||||
@@ -663,32 +664,26 @@ void Scheduler::Reload() {
|
||||
}
|
||||
|
||||
void Scheduler::SwitchContextStep2() {
|
||||
Thread* previous_thread = current_thread_prev.get();
|
||||
Thread* new_thread = selected_thread.get();
|
||||
|
||||
// Load context of new thread
|
||||
Process* const previous_process =
|
||||
previous_thread != nullptr ? previous_thread->GetOwnerProcess() : nullptr;
|
||||
|
||||
if (new_thread) {
|
||||
ASSERT_MSG(new_thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable,
|
||||
if (selected_thread) {
|
||||
ASSERT_MSG(selected_thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable,
|
||||
"Thread must be runnable.");
|
||||
|
||||
// Cancel any outstanding wakeup events for this thread
|
||||
new_thread->SetIsRunning(true);
|
||||
new_thread->last_running_ticks = system.CoreTiming().GetCPUTicks();
|
||||
new_thread->SetWasRunning(false);
|
||||
selected_thread->SetIsRunning(true);
|
||||
selected_thread->last_running_ticks = system.CoreTiming().GetCPUTicks();
|
||||
selected_thread->SetWasRunning(false);
|
||||
|
||||
auto* const thread_owner_process = current_thread->GetOwnerProcess();
|
||||
if (thread_owner_process != nullptr) {
|
||||
system.Kernel().MakeCurrentProcess(thread_owner_process);
|
||||
}
|
||||
if (!new_thread->IsHLEThread()) {
|
||||
Core::ARM_Interface& cpu_core = new_thread->ArmInterface();
|
||||
cpu_core.LoadContext(new_thread->GetContext32());
|
||||
cpu_core.LoadContext(new_thread->GetContext64());
|
||||
cpu_core.SetTlsAddress(new_thread->GetTLSAddress());
|
||||
cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0());
|
||||
if (!selected_thread->IsHLEThread()) {
|
||||
Core::ARM_Interface& cpu_core = selected_thread->ArmInterface();
|
||||
cpu_core.LoadContext(selected_thread->GetContext32());
|
||||
cpu_core.LoadContext(selected_thread->GetContext64());
|
||||
cpu_core.SetTlsAddress(selected_thread->GetTLSAddress());
|
||||
cpu_core.SetTPIDR_EL0(selected_thread->GetTPIDR_EL0());
|
||||
cpu_core.ChangeProcessorID(this->core_id);
|
||||
cpu_core.ClearExclusiveState();
|
||||
}
|
||||
|
||||
@@ -289,7 +289,7 @@ private:
|
||||
|
||||
class SchedulerLock {
|
||||
public:
|
||||
explicit SchedulerLock(KernelCore& kernel);
|
||||
[[nodiscard]] explicit SchedulerLock(KernelCore& kernel);
|
||||
~SchedulerLock();
|
||||
|
||||
protected:
|
||||
|
||||
@@ -342,8 +342,9 @@ ResultVal<std::remove_reference_t<Arg>> MakeResult(Arg&& arg) {
|
||||
*/
|
||||
#define CASCADE_RESULT(target, source) \
|
||||
auto CONCAT2(check_result_L, __LINE__) = source; \
|
||||
if (CONCAT2(check_result_L, __LINE__).Failed()) \
|
||||
if (CONCAT2(check_result_L, __LINE__).Failed()) { \
|
||||
return CONCAT2(check_result_L, __LINE__).Code(); \
|
||||
} \
|
||||
target = std::move(*CONCAT2(check_result_L, __LINE__))
|
||||
|
||||
/**
|
||||
@@ -351,6 +352,9 @@ ResultVal<std::remove_reference_t<Arg>> MakeResult(Arg&& arg) {
|
||||
* non-success, or discarded otherwise.
|
||||
*/
|
||||
#define CASCADE_CODE(source) \
|
||||
auto CONCAT2(check_result_L, __LINE__) = source; \
|
||||
if (CONCAT2(check_result_L, __LINE__).IsError()) \
|
||||
return CONCAT2(check_result_L, __LINE__);
|
||||
do { \
|
||||
auto CONCAT2(check_result_L, __LINE__) = source; \
|
||||
if (CONCAT2(check_result_L, __LINE__).IsError()) { \
|
||||
return CONCAT2(check_result_L, __LINE__); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
@@ -35,7 +35,7 @@ constexpr ResultCode ERR_INVALID_BUFFER_SIZE{ErrorModule::Account, 30};
|
||||
constexpr ResultCode ERR_FAILED_SAVE_DATA{ErrorModule::Account, 100};
|
||||
|
||||
static std::string GetImagePath(Common::UUID uuid) {
|
||||
return FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
|
||||
return Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) +
|
||||
"/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg";
|
||||
}
|
||||
|
||||
@@ -318,7 +318,7 @@ protected:
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
const FileUtil::IOFile image(GetImagePath(user_id), "rb");
|
||||
const Common::FS::IOFile image(GetImagePath(user_id), "rb");
|
||||
if (!image.IsOpen()) {
|
||||
LOG_WARNING(Service_ACC,
|
||||
"Failed to load user provided image! Falling back to built-in backup...");
|
||||
@@ -340,7 +340,7 @@ protected:
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
const FileUtil::IOFile image(GetImagePath(user_id), "rb");
|
||||
const Common::FS::IOFile image(GetImagePath(user_id), "rb");
|
||||
|
||||
if (!image.IsOpen()) {
|
||||
LOG_WARNING(Service_ACC,
|
||||
@@ -405,7 +405,7 @@ protected:
|
||||
ProfileData data;
|
||||
std::memcpy(&data, user_data.data(), sizeof(ProfileData));
|
||||
|
||||
FileUtil::IOFile image(GetImagePath(user_id), "wb");
|
||||
Common::FS::IOFile image(GetImagePath(user_id), "wb");
|
||||
|
||||
if (!image.IsOpen() || !image.Resize(image_data.size()) ||
|
||||
image.WriteBytes(image_data.data(), image_data.size()) != image_data.size() ||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
namespace Service::Account {
|
||||
|
||||
namespace FS = Common::FS;
|
||||
using Common::UUID;
|
||||
|
||||
struct UserRaw {
|
||||
@@ -318,9 +319,8 @@ bool ProfileManager::SetProfileBaseAndData(Common::UUID uuid, const ProfileBase&
|
||||
}
|
||||
|
||||
void ProfileManager::ParseUserSaveFile() {
|
||||
FileUtil::IOFile save(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
|
||||
ACC_SAVE_AVATORS_BASE_PATH + "profiles.dat",
|
||||
"rb");
|
||||
const FS::IOFile save(
|
||||
FS::GetUserPath(FS::UserPath::NANDDir) + ACC_SAVE_AVATORS_BASE_PATH + "profiles.dat", "rb");
|
||||
|
||||
if (!save.IsOpen()) {
|
||||
LOG_WARNING(Service_ACC, "Failed to load profile data from save data... Generating new "
|
||||
@@ -366,22 +366,22 @@ void ProfileManager::WriteUserSaveFile() {
|
||||
};
|
||||
}
|
||||
|
||||
const auto raw_path =
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + "/system/save/8000000000000010";
|
||||
if (FileUtil::Exists(raw_path) && !FileUtil::IsDirectory(raw_path))
|
||||
FileUtil::Delete(raw_path);
|
||||
const auto raw_path = FS::GetUserPath(FS::UserPath::NANDDir) + "/system/save/8000000000000010";
|
||||
if (FS::Exists(raw_path) && !FS::IsDirectory(raw_path)) {
|
||||
FS::Delete(raw_path);
|
||||
}
|
||||
|
||||
const auto path = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
|
||||
ACC_SAVE_AVATORS_BASE_PATH + "profiles.dat";
|
||||
const auto path =
|
||||
FS::GetUserPath(FS::UserPath::NANDDir) + ACC_SAVE_AVATORS_BASE_PATH + "profiles.dat";
|
||||
|
||||
if (!FileUtil::CreateFullPath(path)) {
|
||||
if (!FS::CreateFullPath(path)) {
|
||||
LOG_WARNING(Service_ACC, "Failed to create full path of profiles.dat. Create the directory "
|
||||
"nand/system/save/8000000000000010/su/avators to mitigate this "
|
||||
"issue.");
|
||||
return;
|
||||
}
|
||||
|
||||
FileUtil::IOFile save(path, "wb");
|
||||
FS::IOFile save(path, "wb");
|
||||
|
||||
if (!save.IsOpen()) {
|
||||
LOG_WARNING(Service_ACC, "Failed to write save data to file... No changes to user data "
|
||||
|
||||
@@ -378,7 +378,11 @@ void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext&
|
||||
}
|
||||
|
||||
void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto permission = rp.PopEnum<ScreenshotPermission>();
|
||||
LOG_DEBUG(Service_AM, "called, permission={}", permission);
|
||||
|
||||
screenshot_permission = permission;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
@@ -149,6 +149,12 @@ private:
|
||||
void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx);
|
||||
void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx);
|
||||
|
||||
enum class ScreenshotPermission : u32 {
|
||||
Inherit = 0,
|
||||
Enable = 1,
|
||||
Disable = 2,
|
||||
};
|
||||
|
||||
Core::System& system;
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
Kernel::EventPair launchable_event;
|
||||
@@ -157,6 +163,7 @@ private:
|
||||
u32 idle_time_detection_extension = 0;
|
||||
u64 num_fatal_sections_entered = 0;
|
||||
bool is_auto_sleep_disabled = false;
|
||||
ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit;
|
||||
};
|
||||
|
||||
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
|
||||
|
||||
@@ -122,8 +122,7 @@ void SoftwareKeyboard::ExecuteInteractive() {
|
||||
|
||||
switch (request) {
|
||||
case Request::Calc: {
|
||||
broker.PushNormalDataFromApplet(
|
||||
std::make_shared<IStorage>(std::move(std::vector<u8>{1})));
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>{1}));
|
||||
broker.SignalStateChanged();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -293,8 +293,8 @@ void WebBrowser::Finalize() {
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(data)));
|
||||
broker.SignalStateChanged();
|
||||
|
||||
if (!temporary_dir.empty() && FileUtil::IsDirectory(temporary_dir)) {
|
||||
FileUtil::DeleteDirRecursively(temporary_dir);
|
||||
if (!temporary_dir.empty() && Common::FS::IsDirectory(temporary_dir)) {
|
||||
Common::FS::DeleteDirRecursively(temporary_dir);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,10 +452,10 @@ void WebBrowser::InitializeOffline() {
|
||||
};
|
||||
|
||||
temporary_dir =
|
||||
FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + "web_applet_" +
|
||||
WEB_SOURCE_NAMES[static_cast<u32>(source) - 1],
|
||||
FileUtil::DirectorySeparator::PlatformDefault);
|
||||
FileUtil::DeleteDirRecursively(temporary_dir);
|
||||
Common::FS::SanitizePath(Common::FS::GetUserPath(Common::FS::UserPath::CacheDir) +
|
||||
"web_applet_" + WEB_SOURCE_NAMES[static_cast<u32>(source) - 1],
|
||||
Common::FS::DirectorySeparator::PlatformDefault);
|
||||
Common::FS::DeleteDirRecursively(temporary_dir);
|
||||
|
||||
u64 title_id = 0; // 0 corresponds to current process
|
||||
ASSERT(args[WebArgTLVType::ApplicationID].size() >= 0x8);
|
||||
@@ -492,8 +492,8 @@ void WebBrowser::InitializeOffline() {
|
||||
}
|
||||
|
||||
filename =
|
||||
FileUtil::SanitizePath(temporary_dir + path_additional_directory + DIR_SEP + filename,
|
||||
FileUtil::DirectorySeparator::PlatformDefault);
|
||||
Common::FS::SanitizePath(temporary_dir + path_additional_directory + DIR_SEP + filename,
|
||||
Common::FS::DirectorySeparator::PlatformDefault);
|
||||
}
|
||||
|
||||
void WebBrowser::ExecuteShop() {
|
||||
@@ -551,7 +551,8 @@ void WebBrowser::ExecuteShop() {
|
||||
}
|
||||
|
||||
void WebBrowser::ExecuteOffline() {
|
||||
frontend.OpenPageLocal(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); });
|
||||
frontend.OpenPageLocal(
|
||||
filename, [this] { UnpackRomFS(); }, [this] { Finalize(); });
|
||||
}
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
|
||||
@@ -206,7 +206,7 @@ private:
|
||||
AudioCore::StreamPtr stream;
|
||||
std::string device_name;
|
||||
|
||||
[[maybe_unused]] AudoutParams audio_params {};
|
||||
[[maybe_unused]] AudoutParams audio_params{};
|
||||
|
||||
/// This is the event handle used to check if the audio buffer was released
|
||||
Kernel::EventPair buffer_event;
|
||||
|
||||
@@ -89,12 +89,12 @@ constexpr u32 TIMEOUT_SECONDS = 30;
|
||||
|
||||
std::string GetBINFilePath(u64 title_id) {
|
||||
return fmt::format("{}bcat/{:016X}/launchparam.bin",
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::CacheDir), title_id);
|
||||
Common::FS::GetUserPath(Common::FS::UserPath::CacheDir), title_id);
|
||||
}
|
||||
|
||||
std::string GetZIPFilePath(u64 title_id) {
|
||||
return fmt::format("{}bcat/{:016X}/data.zip",
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::CacheDir), title_id);
|
||||
Common::FS::GetUserPath(Common::FS::UserPath::CacheDir), title_id);
|
||||
}
|
||||
|
||||
// If the error is something the user should know about (build ID mismatch, bad client version),
|
||||
@@ -205,8 +205,8 @@ private:
|
||||
{std::string("Game-Build-Id"), fmt::format("{:016X}", build_id)},
|
||||
};
|
||||
|
||||
if (FileUtil::Exists(path)) {
|
||||
FileUtil::IOFile file{path, "rb"};
|
||||
if (Common::FS::Exists(path)) {
|
||||
Common::FS::IOFile file{path, "rb"};
|
||||
if (file.IsOpen()) {
|
||||
std::vector<u8> bytes(file.GetSize());
|
||||
file.ReadBytes(bytes.data(), bytes.size());
|
||||
@@ -236,8 +236,8 @@ private:
|
||||
return DownloadResult::InvalidContentType;
|
||||
}
|
||||
|
||||
FileUtil::CreateFullPath(path);
|
||||
FileUtil::IOFile file{path, "wb"};
|
||||
Common::FS::CreateFullPath(path);
|
||||
Common::FS::IOFile file{path, "wb"};
|
||||
if (!file.IsOpen())
|
||||
return DownloadResult::GeneralFSError;
|
||||
if (!file.Resize(response->body.size()))
|
||||
@@ -290,7 +290,7 @@ void SynchronizeInternal(AM::Applets::AppletManager& applet_manager, DirectoryGe
|
||||
LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res);
|
||||
|
||||
if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) {
|
||||
FileUtil::Delete(zip_path);
|
||||
Common::FS::Delete(zip_path);
|
||||
}
|
||||
|
||||
HandleDownloadDisplayResult(applet_manager, res);
|
||||
@@ -300,7 +300,7 @@ void SynchronizeInternal(AM::Applets::AppletManager& applet_manager, DirectoryGe
|
||||
|
||||
progress.StartProcessingDataList();
|
||||
|
||||
FileUtil::IOFile zip{zip_path, "rb"};
|
||||
Common::FS::IOFile zip{zip_path, "rb"};
|
||||
const auto size = zip.GetSize();
|
||||
std::vector<u8> bytes(size);
|
||||
if (!zip.IsOpen() || size == 0 || zip.ReadBytes(bytes.data(), bytes.size()) != bytes.size()) {
|
||||
@@ -365,8 +365,7 @@ bool Boxcat::Synchronize(TitleIDVersion title, ProgressServiceBackend& progress)
|
||||
|
||||
std::thread([this, title, &progress] {
|
||||
SynchronizeInternal(applet_manager, dir_getter, title, progress);
|
||||
})
|
||||
.detach();
|
||||
}).detach();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -377,8 +376,7 @@ bool Boxcat::SynchronizeDirectory(TitleIDVersion title, std::string name,
|
||||
|
||||
std::thread([this, title, name, &progress] {
|
||||
SynchronizeInternal(applet_manager, dir_getter, title, progress, name);
|
||||
})
|
||||
.detach();
|
||||
}).detach();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -422,7 +420,7 @@ std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title)
|
||||
LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res);
|
||||
|
||||
if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) {
|
||||
FileUtil::Delete(path);
|
||||
Common::FS::Delete(path);
|
||||
}
|
||||
|
||||
HandleDownloadDisplayResult(applet_manager, res);
|
||||
@@ -430,7 +428,7 @@ std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title)
|
||||
}
|
||||
}
|
||||
|
||||
FileUtil::IOFile bin{path, "rb"};
|
||||
Common::FS::IOFile bin{path, "rb"};
|
||||
const auto size = bin.GetSize();
|
||||
std::vector<u8> bytes(size);
|
||||
if (!bin.IsOpen() || size == 0 || bin.ReadBytes(bytes.data(), bytes.size()) != bytes.size()) {
|
||||
|
||||
@@ -36,7 +36,7 @@ constexpr u64 SUFFICIENT_SAVE_DATA_SIZE = 0xF0000000;
|
||||
|
||||
static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base,
|
||||
std::string_view dir_name_) {
|
||||
std::string dir_name(FileUtil::SanitizePath(dir_name_));
|
||||
std::string dir_name(Common::FS::SanitizePath(dir_name_));
|
||||
if (dir_name.empty() || dir_name == "." || dir_name == "/" || dir_name == "\\")
|
||||
return base;
|
||||
|
||||
@@ -53,13 +53,13 @@ std::string VfsDirectoryServiceWrapper::GetName() const {
|
||||
}
|
||||
|
||||
ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size) const {
|
||||
std::string path(FileUtil::SanitizePath(path_));
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
|
||||
std::string path(Common::FS::SanitizePath(path_));
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
|
||||
// dir can be nullptr if path contains subdirectories, create those prior to creating the file.
|
||||
if (dir == nullptr) {
|
||||
dir = backing->CreateSubdirectory(FileUtil::GetParentPath(path));
|
||||
dir = backing->CreateSubdirectory(Common::FS::GetParentPath(path));
|
||||
}
|
||||
auto file = dir->CreateFile(FileUtil::GetFilename(path));
|
||||
auto file = dir->CreateFile(Common::FS::GetFilename(path));
|
||||
if (file == nullptr) {
|
||||
// TODO(DarkLordZach): Find a better error code for this
|
||||
return RESULT_UNKNOWN;
|
||||
@@ -72,17 +72,17 @@ ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64
|
||||
}
|
||||
|
||||
ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const {
|
||||
std::string path(FileUtil::SanitizePath(path_));
|
||||
std::string path(Common::FS::SanitizePath(path_));
|
||||
if (path.empty()) {
|
||||
// TODO(DarkLordZach): Why do games call this and what should it do? Works as is but...
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
|
||||
if (dir->GetFile(FileUtil::GetFilename(path)) == nullptr) {
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
|
||||
if (dir->GetFile(Common::FS::GetFilename(path)) == nullptr) {
|
||||
return FileSys::ERROR_PATH_NOT_FOUND;
|
||||
}
|
||||
if (!dir->DeleteFile(FileUtil::GetFilename(path))) {
|
||||
if (!dir->DeleteFile(Common::FS::GetFilename(path))) {
|
||||
// TODO(DarkLordZach): Find a better error code for this
|
||||
return RESULT_UNKNOWN;
|
||||
}
|
||||
@@ -91,11 +91,11 @@ ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) cons
|
||||
}
|
||||
|
||||
ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) const {
|
||||
std::string path(FileUtil::SanitizePath(path_));
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
|
||||
if (dir == nullptr && FileUtil::GetFilename(FileUtil::GetParentPath(path)).empty())
|
||||
std::string path(Common::FS::SanitizePath(path_));
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
|
||||
if (dir == nullptr && Common::FS::GetFilename(Common::FS::GetParentPath(path)).empty())
|
||||
dir = backing;
|
||||
auto new_dir = dir->CreateSubdirectory(FileUtil::GetFilename(path));
|
||||
auto new_dir = dir->CreateSubdirectory(Common::FS::GetFilename(path));
|
||||
if (new_dir == nullptr) {
|
||||
// TODO(DarkLordZach): Find a better error code for this
|
||||
return RESULT_UNKNOWN;
|
||||
@@ -104,9 +104,9 @@ ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_)
|
||||
}
|
||||
|
||||
ResultCode VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path_) const {
|
||||
std::string path(FileUtil::SanitizePath(path_));
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
|
||||
if (!dir->DeleteSubdirectory(FileUtil::GetFilename(path))) {
|
||||
std::string path(Common::FS::SanitizePath(path_));
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
|
||||
if (!dir->DeleteSubdirectory(Common::FS::GetFilename(path))) {
|
||||
// TODO(DarkLordZach): Find a better error code for this
|
||||
return RESULT_UNKNOWN;
|
||||
}
|
||||
@@ -114,9 +114,9 @@ ResultCode VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path_)
|
||||
}
|
||||
|
||||
ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::string& path_) const {
|
||||
std::string path(FileUtil::SanitizePath(path_));
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
|
||||
if (!dir->DeleteSubdirectoryRecursive(FileUtil::GetFilename(path))) {
|
||||
std::string path(Common::FS::SanitizePath(path_));
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
|
||||
if (!dir->DeleteSubdirectoryRecursive(Common::FS::GetFilename(path))) {
|
||||
// TODO(DarkLordZach): Find a better error code for this
|
||||
return RESULT_UNKNOWN;
|
||||
}
|
||||
@@ -124,10 +124,10 @@ ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::str
|
||||
}
|
||||
|
||||
ResultCode VfsDirectoryServiceWrapper::CleanDirectoryRecursively(const std::string& path) const {
|
||||
const std::string sanitized_path(FileUtil::SanitizePath(path));
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(sanitized_path));
|
||||
const std::string sanitized_path(Common::FS::SanitizePath(path));
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(sanitized_path));
|
||||
|
||||
if (!dir->CleanSubdirectoryRecursive(FileUtil::GetFilename(sanitized_path))) {
|
||||
if (!dir->CleanSubdirectoryRecursive(Common::FS::GetFilename(sanitized_path))) {
|
||||
// TODO(DarkLordZach): Find a better error code for this
|
||||
return RESULT_UNKNOWN;
|
||||
}
|
||||
@@ -137,14 +137,14 @@ ResultCode VfsDirectoryServiceWrapper::CleanDirectoryRecursively(const std::stri
|
||||
|
||||
ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_,
|
||||
const std::string& dest_path_) const {
|
||||
std::string src_path(FileUtil::SanitizePath(src_path_));
|
||||
std::string dest_path(FileUtil::SanitizePath(dest_path_));
|
||||
std::string src_path(Common::FS::SanitizePath(src_path_));
|
||||
std::string dest_path(Common::FS::SanitizePath(dest_path_));
|
||||
auto src = backing->GetFileRelative(src_path);
|
||||
if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) {
|
||||
if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) {
|
||||
// Use more-optimized vfs implementation rename.
|
||||
if (src == nullptr)
|
||||
return FileSys::ERROR_PATH_NOT_FOUND;
|
||||
if (!src->Rename(FileUtil::GetFilename(dest_path))) {
|
||||
if (!src->Rename(Common::FS::GetFilename(dest_path))) {
|
||||
// TODO(DarkLordZach): Find a better error code for this
|
||||
return RESULT_UNKNOWN;
|
||||
}
|
||||
@@ -162,7 +162,7 @@ ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_,
|
||||
ASSERT_MSG(dest->WriteBytes(src->ReadAllBytes()) == src->GetSize(),
|
||||
"Could not write all of the bytes but everything else has succeded.");
|
||||
|
||||
if (!src->GetContainingDirectory()->DeleteFile(FileUtil::GetFilename(src_path))) {
|
||||
if (!src->GetContainingDirectory()->DeleteFile(Common::FS::GetFilename(src_path))) {
|
||||
// TODO(DarkLordZach): Find a better error code for this
|
||||
return RESULT_UNKNOWN;
|
||||
}
|
||||
@@ -172,14 +172,14 @@ ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_,
|
||||
|
||||
ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_,
|
||||
const std::string& dest_path_) const {
|
||||
std::string src_path(FileUtil::SanitizePath(src_path_));
|
||||
std::string dest_path(FileUtil::SanitizePath(dest_path_));
|
||||
std::string src_path(Common::FS::SanitizePath(src_path_));
|
||||
std::string dest_path(Common::FS::SanitizePath(dest_path_));
|
||||
auto src = GetDirectoryRelativeWrapped(backing, src_path);
|
||||
if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) {
|
||||
if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) {
|
||||
// Use more-optimized vfs implementation rename.
|
||||
if (src == nullptr)
|
||||
return FileSys::ERROR_PATH_NOT_FOUND;
|
||||
if (!src->Rename(FileUtil::GetFilename(dest_path))) {
|
||||
if (!src->Rename(Common::FS::GetFilename(dest_path))) {
|
||||
// TODO(DarkLordZach): Find a better error code for this
|
||||
return RESULT_UNKNOWN;
|
||||
}
|
||||
@@ -198,7 +198,7 @@ ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_pa
|
||||
|
||||
ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::string& path_,
|
||||
FileSys::Mode mode) const {
|
||||
const std::string path(FileUtil::SanitizePath(path_));
|
||||
const std::string path(Common::FS::SanitizePath(path_));
|
||||
std::string_view npath = path;
|
||||
while (!npath.empty() && (npath[0] == '/' || npath[0] == '\\')) {
|
||||
npath.remove_prefix(1);
|
||||
@@ -218,7 +218,7 @@ ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const std::string& path_) {
|
||||
std::string path(FileUtil::SanitizePath(path_));
|
||||
std::string path(Common::FS::SanitizePath(path_));
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, path);
|
||||
if (dir == nullptr) {
|
||||
// TODO(DarkLordZach): Find a better error code for this
|
||||
@@ -229,11 +229,11 @@ ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const s
|
||||
|
||||
ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
|
||||
const std::string& path_) const {
|
||||
std::string path(FileUtil::SanitizePath(path_));
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
|
||||
std::string path(Common::FS::SanitizePath(path_));
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
|
||||
if (dir == nullptr)
|
||||
return FileSys::ERROR_PATH_NOT_FOUND;
|
||||
auto filename = FileUtil::GetFilename(path);
|
||||
auto filename = Common::FS::GetFilename(path);
|
||||
// TODO(Subv): Some games use the '/' path, find out what this means.
|
||||
if (filename.empty())
|
||||
return MakeResult(FileSys::EntryType::Directory);
|
||||
@@ -695,13 +695,13 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove
|
||||
sdmc_factory = nullptr;
|
||||
}
|
||||
|
||||
auto nand_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir),
|
||||
auto nand_directory = vfs.OpenDirectory(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir),
|
||||
FileSys::Mode::ReadWrite);
|
||||
auto sd_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir),
|
||||
auto sd_directory = vfs.OpenDirectory(Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir),
|
||||
FileSys::Mode::ReadWrite);
|
||||
auto load_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir),
|
||||
auto load_directory = vfs.OpenDirectory(Common::FS::GetUserPath(Common::FS::UserPath::LoadDir),
|
||||
FileSys::Mode::ReadWrite);
|
||||
auto dump_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::DumpDir),
|
||||
auto dump_directory = vfs.OpenDirectory(Common::FS::GetUserPath(Common::FS::UserPath::DumpDir),
|
||||
FileSys::Mode::ReadWrite);
|
||||
|
||||
if (bis_factory == nullptr) {
|
||||
|
||||
@@ -90,7 +90,7 @@ u32 Controller_NPad::IndexToNPad(std::size_t index) {
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unknown npad index {}", index);
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {}
|
||||
@@ -630,7 +630,7 @@ Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unhandled npad_id {}", npad_id);
|
||||
return LedPattern{0, 0, 0, 0};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void Controller_NPad::SetVibrationEnabled(bool can_vibrate) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user