Compare commits

...

100 Commits

Author SHA1 Message Date
Lioncash 4c1a95ed61 fsp_srv: Resolve -Wunused-but-set-variable warning
We can just log out the parameters in the meantime.
2020-08-23 17:16:32 -04:00
Lioncash 85db5f4091 fsp_srv: Resolve -Wmaybe_uninitialized warning in OpenSaveDataFileSystem()
Initialize id to a deterministic value and also mark the unreachable
cases in the switch with UNREACHABLE().
2020-08-23 16:37:57 -04:00
bunnei 3ea3de4ecd Merge pull request #4546 from lioncash/telemetry
common/telemetry: Migrate namespace into the Common namespace
2020-08-20 14:29:13 -04:00
bunnei 3b8a8cf825 Merge pull request #4547 from lioncash/header-concept
common/concepts: Move <type_traits> include out of the Common namespace
2020-08-19 23:29:45 -04:00
bunnei 354811e556 Merge pull request #4552 from yuzu-emu/revert-4537-tz
Revert "common/time_zone: Simplify GetOsTimeZoneOffset()"
2020-08-19 18:27:49 -04:00
bunnei acbae572d3 Revert "common/time_zone: Simplify GetOsTimeZoneOffset()" 2020-08-19 18:27:31 -04:00
bunnei b1fa647f28 Merge pull request #4539 from lioncash/disc
common: Silence two discarded result warnings
2020-08-18 22:03:09 -04:00
bunnei 2d2e235bcf Merge pull request #4522 from lioncash/vulk-copy
vulkan/wrapper: Avoid unnecessary copy in EnumerateInstanceExtensionProperties()
2020-08-18 19:31:35 -04:00
Lioncash f6bb905182 common/telemetry: Migrate namespace into the Common namespace
Migrates the Telemetry namespace into the Common namespace to make the
code consistent with the rest of our common code.
2020-08-18 15:08:32 -04:00
Lioncash 999fc2fece common/concepts: Move <type_traits> include out of the Common namespace
This is a compiler/linker error waiting to happen.
2020-08-18 14:24:54 -04:00
bunnei bea9ed2548 Merge pull request #4381 from Morph1984/fix-open-folder-installed-title
main: Fix Open Save/Mod Locations for installed titles
2020-08-18 12:54:06 -04:00
bunnei 00573fb2c9 Merge pull request #4532 from lioncash/object-name
configuration_shared: Simplify name lookup in highlighting functions
2020-08-18 00:45:02 -04:00
bunnei 56c6a5def8 Merge pull request #4535 from lioncash/fileutil
common/fileutil: Convert namespace to Common::FS
2020-08-17 22:35:30 -04:00
bunnei 0c885249df Merge pull request #4537 from lioncash/tz
common/time_zone: Simplify GetOsTimeZoneOffset()
2020-08-17 14:27:02 -04:00
bunnei 3472c00b3b Merge pull request #4540 from lioncash/tr3
configure_hotkeys: Don't translate empty strings
2020-08-17 12:24:58 -04:00
bunnei 0530dd6ea1 Merge pull request #4494 from lioncash/transcode
aes_util: Make use of non-template variant of Transcode
2020-08-17 03:50:35 -04:00
Rodrigo Locatti d8a90e6536 Merge pull request #4531 from lioncash/overload
yuzu: Make use of qOverload where applicable
2020-08-17 04:13:14 -03:00
David cbaf1bc711 Merge pull request #4443 from ameerj/vk-async-shaders
vulkan_renderer: Async shader/graphics pipeline compilation
2020-08-17 15:06:11 +10:00
bunnei bbb5623f52 Merge pull request #4515 from lat9nq/pgs-menubar-config
main: Add an option to modify the currrent game's configuration
2020-08-17 01:03:39 -04:00
David a91acd5365 Merge pull request #4520 from lioncash/pessimize
async_shaders: Resolve -Wpessimizing-move warning
2020-08-17 14:36:05 +10:00
ameerj fde8102a41 Remove unneeded newlines, optional Registry in shader params
Addressing feedback from Rodrigo
2020-08-16 16:33:21 -04:00
bunnei ada9b7fb77 Merge pull request #4536 from lioncash/semi3
yuzu: Resolve -Wextra-semi warnings
2020-08-16 14:35:43 -04:00
Ameer J f49ffdd648 Morph: Update worker allocation comment
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
2020-08-16 12:02:22 -04:00
ameerj 1b829fbd7a move thread 1/4 count computation into allocate workers method 2020-08-16 12:02:22 -04:00
ameerj 31a76410e8 Address feedback, add shader compile notifier, update setting text 2020-08-16 12:02:22 -04:00
ameerj c02464f64e Vk Async Worker directly emplace in cache 2020-08-16 12:02:22 -04:00
ameerj 4539073ce1 Address feedback. Bruteforce delete duplicates 2020-08-16 12:02:22 -04:00
ameerj 6ac97405df Vk Async pipeline compilation 2020-08-16 12:02:22 -04:00
Lioncash e23289d869 configure_hotkeys: Don't translate empty strings
There's no need to translate an empty string. This just gives
translators unnecessary work.
2020-08-16 08:13:25 -04:00
Lioncash c4ed791164 common/fileutil: Convert namespace to Common::FS
Migrates a remaining common file over to the Common namespace, making it
consistent with the rest of common files.

This also allows for high-traffic FS related code to alias the
filesystem function namespace as

namespace FS = Common::FS;

for more concise typing.
2020-08-16 06:52:40 -04:00
Lioncash d09456fc41 common: Silence two discarded result warnings
These are intentionally discarded internally, since the rest of the
public API allows querying success. We want all non-internal uses of
these functions to be explicitly checked, so we can signify that we
intentionally want to discard the return values here.
2020-08-16 06:17:33 -04:00
Lioncash fe97d34156 common/time_zone: Simplify GetOsTimeZoneOffset()
We can simplify this function down into a single line with the use of
fmt. A benefit with the fmt approach is that the fmt variant of
localtime is thread-safe as well, making GetOsTimeZoneOffset()
thread-safe as well.
2020-08-16 03:58:47 -04:00
Lioncash dbb1cbce67 yuzu: Resolve -Wextra-semi warnings
While we're in the same area, we can ensure GameDir member variables are
always initialized to consistent values.
2020-08-16 03:58:29 -04:00
bunnei db96034ea4 Merge pull request #4528 from lioncash/discard
common: Make use of [[nodiscard]] where applicable
2020-08-16 01:47:54 -04:00
bunnei 404362e1b0 Merge pull request #4519 from lioncash/semi
maxwell_3d: Resolve -Wextra-semi warning
2020-08-16 00:55:15 -04:00
lat9nq 9f972b7d01 main: Add an option to modify the currrent game's configuration
Creates a new entry in the Emulation menu called "Configure Current Game..." that is only available if a game is currently being executed in yuzu. When selected, it opens the game properties dialog for the current game.

Thanks to @BSoDGamingYT for reminding me to do this.
2020-08-15 20:28:48 -04:00
Lioncash 1ee060ca0d common/compression: Roll back std::span changes
Seems like all compilers don't support std::span yet.
2020-08-15 17:17:56 -04:00
Lioncash df72480395 common: Make use of [[nodiscard]] where applicable
Now that clang-format makes [[nodiscard]] attributes format sensibly, we
can apply them to several functions within the common library to allow
the compiler to complain about any misuses of the functions.
2020-08-15 17:17:52 -04:00
bunnei 2b601e8636 Merge pull request #4526 from lioncash/core-semi
core: Resolve several -Wextra-semi warnings
2020-08-15 02:14:11 -04:00
bunnei e6f9231ef0 Merge pull request #4527 from lioncash/pessimizing2
software_keyboard: Resolve a pessimizing move warning
2020-08-15 02:13:44 -04:00
bunnei cb6808b4d0 Merge pull request #4492 from lioncash/linkage
system_control: Make functions internally linked where applicable
2020-08-15 02:11:49 -04:00
bunnei 2aabd1eb05 Merge pull request #4463 from lioncash/lockdiscard
kernel/scheduler: Mark SchedulerLock constructor as nodiscard
2020-08-15 01:31:23 -04:00
bunnei feb243b08d Merge pull request #4416 from lioncash/span
lz4_compression/zstd_compression: Make use of std::span in interfaces
2020-08-15 00:53:11 -04:00
bunnei fc2f8963bb Merge pull request #4518 from lioncash/fmtlib
CMakeLists: Update fmt to 7.0.3
2020-08-14 23:29:27 -04:00
bunnei 2dace90346 Merge pull request #4453 from ReinUsesLisp/block-to-linear
textures/decoders: Fix block linear to pitch copies
2020-08-14 19:52:12 -04:00
Lioncash fe86109877 configuration_shared: Simplify name lookup in highlighting functions
We can query the given object name directly from the widget itself. This
removes any potential for forgetting to change the name if the widget
gets renamed and makes the API much simpler (just pass in the widget,
and not worry about its name).
2020-08-14 14:17:02 -04:00
Lioncash 969a4cc4da yuzu: Make use of qOverload where applicable
Eliminates a verbose function cast.
2020-08-14 14:12:55 -04:00
bunnei f482b4b40d Merge pull request #4529 from lioncash/assignment
time_zone_content_manager: Collapse auto and default case
2020-08-14 11:02:00 -04:00
Lioncash b14277ef97 time_zone_content_manager: Collapse auto and default case
Prevents a useless self-assignment from occurring.
2020-08-14 10:58:58 -04:00
Lioncash 1f9ac1541f CMakeLists: Update fmt to 7.0.3
Keeps the library up to date and fixes a few bugs
2020-08-14 09:17:23 -04:00
Lioncash 03d5a5d9de software_keyboard: Resolve a pessimizing move warning
A std::vector created in place like this is already an rvalue and
doesn't need to be moved.
2020-08-14 09:14:54 -04:00
Lioncash 2296e921d2 core: Resolve several -Wextra-semi warnings
We can amend one of the cascade macros to require semicolons in order to
compile. In other cases, we can just remove the superfluous semicolons.
2020-08-14 09:09:20 -04:00
Lioncash 167d36ec3c vulkan/wrapper: Avoid unnecessary copy in EnumerateInstanceExtensionProperties()
Given this is implicitly creating a std::optional, we can move the
vector into it.
2020-08-14 08:23:49 -04:00
Lioncash 6b13d08822 async_shaders: Resolve -Wpessimizing-move warning
Prevents pessimization of the move constructor (which thankfully didn't
actually happen in practice here, given std::thread isn't copyable).
2020-08-14 08:16:50 -04:00
Lioncash 83d8bf9af9 maxwell_3d: Resolve -Wextra-semi warning
Semicolons after a function definition aren't necessary.
2020-08-14 08:13:41 -04:00
Lioncash a93f6e51d3 emu_window: Mark Scoped constructor and Acquire() as nodiscard
Ensures that callers make use of the constructor, preventing bugs from
silently occurring.
2020-08-14 04:43:44 -04:00
Lioncash f808258ed9 kernel/scheduler: Mark SchedulerLock constructor as nodiscard
Allows the compiler to warn about cases where the constructor is used
but then immediately discarded, which is a potential cause of
locking/unlocking bugs.
2020-08-14 04:43:44 -04:00
Rodrigo Locatti e050594706 Merge pull request #4495 from lioncash/conv
cheat_engine: Resolve implicit bool->u64 conversion
2020-08-14 03:10:17 -03:00
bunnei a9de967fa3 Merge pull request #4514 from Morph1984/worker-alloc
gl_shader_cache: Use std::max() for determining num_workers
2020-08-13 17:06:57 -04:00
LC ff0b14ee62 Merge pull request #4511 from lioncash/build2
General: Tidy up clang-format warnings part 2
2020-08-13 15:13:21 -04:00
Lioncash b724a4d90c General: Tidy up clang-format warnings part 2 2020-08-13 14:19:08 -04:00
Morph e0ff98dd34 gl_shader_cache: Use std::max() for determining num_workers
Does not allocate more threads than available in the host system for boot-time shader compilation and always allocates at least 1 thread if hardware_concurrency() returns 0.
2020-08-12 09:23:34 -04:00
bunnei a8ffe6eee4 Merge pull request #4497 from lioncash/freezer-alg
freezer: Make use of std::erase_if
2020-08-11 23:07:17 -04:00
bunnei e143adc3cf Merge pull request #4493 from jbeich/dragonfly
common/virtual_buffer: drop unused includes
2020-08-11 12:52:50 -04:00
bunnei 4605e4d6ff Merge pull request #4502 from lioncash/build
General: Tidy up clang-format warnings
2020-08-11 11:04:05 -04:00
ReinUsesLisp f00641459e textures/decoders: Fix block linear to pitch copies
There were two issues with block linear copies. First the swizzling was
wrong and this commit reimplements them.

The other issue was that these copies are generally used to download
render targets from the GPU and yuzu was not downloading them from
host GPU memory unless the extreme GPU accuracy setting was selected.
This commit enables cached memory reads for all accuracy levels.

- Fixes level thumbnails in Super Mario Maker 2.
2020-08-10 20:45:03 -03:00
bunnei 257b1d2c4b Merge pull request #4496 from lioncash/ce-desig
cheat_engine: Make use of designated initializers
2020-08-10 13:53:43 -04:00
bunnei 85feaf3005 Merge pull request #4330 from ameerj/master
input_configuration: Add range logic for analog sticks
2020-08-10 12:57:13 -04:00
ameerj d6672501ac Remove UI changes
This PR is now only the Analog devices handling the range value defaulting at 100%
2020-08-10 12:46:14 -04:00
ameerj 9c6ae697f5 Add range slider functionality for gc adapter 2020-08-10 12:46:14 -04:00
Ameer 8928aa3008 undo unnecessary newlines, slider range 50-150 2020-08-10 12:46:14 -04:00
Ameer 504095cea9 Address c++20 warning, fix inaccurate range text display when slide == 0 2020-08-10 12:46:14 -04:00
Ameer ed51c2abda Add range slider for analog sticks 2020-08-10 12:46:14 -04:00
bunnei acfd771e79 Merge pull request #4491 from lioncash/unused-vars
kernel: Remove unused variables
2020-08-10 12:04:30 -04:00
bunnei 664019954a Merge pull request #4488 from lioncash/file
vfs_vector: Make creation of array vfs files less verbose
2020-08-09 17:19:34 -04:00
Lioncash 1c3490a8db General: Tidy up clang-format warnings 2020-08-08 20:08:44 -04:00
bunnei f14bb61acd Merge pull request #4448 from Morph1984/fix-entries
game_list_worker: Do not clear entries when > 1 gamedir is present
2020-08-07 17:11:52 -04:00
bunnei 929fc849e9 Merge pull request #4457 from ogniK5377/SetScreenShotPermission
am: Unstub SetScreenShotPermission
2020-08-07 09:34:20 -04:00
bunnei 5429ea0e69 Merge pull request #4389 from ogniK5377/redundant-format-type
video_core: Remove redundant pixel format type
2020-08-07 09:33:58 -04:00
bunnei 62fa00f586 Merge pull request #4464 from lioncash/format-pass
ci: Make use of clang-format 10.0
2020-08-07 09:12:08 -04:00
David 53e94c7be8 Merge pull request #4501 from lioncash/is_base_of
common/concepts: Rename IsBaseOf to DerivedFrom
2020-08-07 22:59:01 +10:00
Lioncash 61cd7eb47d freezer: Move entry finding to its own function
Cleans up the callsites in other functions.
2020-08-06 03:11:21 -04:00
Lioncash 06ab28263b freezer: Take address values by value
VAddr will always be 64-bit, so there's no need to take a trivial
primitive alias by reference.
2020-08-06 03:04:54 -04:00
Lioncash 253a17451b freezer: Make use of std::erase_if
With C++20 we can simplify the erasing idiom.
2020-08-06 03:03:05 -04:00
Lioncash 5b89291308 cheat_engine: Resolve implicit bool->u64 conversion
We can just return zero here.
2020-08-06 02:55:47 -04:00
Lioncash df96a214ae cheat_engine: Make use of designated initializers
Same behavior, but makes the member being assigned obvious.
2020-08-06 02:48:13 -04:00
Lioncash 04bb47f57f partition_data_manager: Eliminate magic value
We can use sizeof to make it obvious at the call site where the value is
coming from.
2020-08-06 02:34:10 -04:00
Lioncash 09f884b7bd aes_util: Make use of non-template variant of Transcode
Same behavior, less template instantiations.
2020-08-06 02:31:19 -04:00
Jan Beich 238208ee30 common/virtual_buffer: drop unused includes
On DragonFly and NetBSD build fails with

src/common/virtual_buffer.cpp
src/common/virtual_buffer.cpp:16:10: fatal error: sys/sysinfo.h: No such file or directory
 #include <sys/sysinfo.h>
          ^~~~~~~~~~~~~~~
2020-08-05 21:36:35 +00:00
Lioncash 87c64c41d2 system_control: Make functions internally linked where applicable
These functions are only ever used internally as implementation details
for GenerateRandomRange(), so these can be given internal linkage.
2020-08-05 15:34:27 -04:00
Lioncash a10d64ea79 kernel: Remove unused variables
Resolves a few compiler warnings.
2020-08-05 15:19:48 -04:00
Lioncash 0a5456feb9 vfs_vector: Make creation of array vfs files less verbose
We can add a helper function to make creation of these files nicer.
While we're at it, we can eliminate an unnecessary std::array copy in
the constructor. This makes the overhead on some of these functions way
less intensive, given some arrays were quite large.

e.g. The timezone location names are 9633 bytes in size.
2020-08-05 12:37:00 -04:00
Morph cf946312ca main: Fallback to loader if no control nca is found with patch manager
In some rare instances, the patch manager is not able to find a control nca, fallback to the previous method of parsing a control nca through the loader if this occurs.
2020-08-04 21:14:20 -04:00
Morph 1146049de0 main: Fix Open Save/Mod Locations for installed titles
Previously NAND/SDMC installed titles would open device saves when they are supposed to be user saves. This is due to the control nca not being read and thus returns 0 for both GetDefaultNormalSaveSize() and GetDeviceSaveDataSize(). Fix this by utilizing the patch manager to read the control nca.
2020-08-04 21:14:20 -04:00
Morph 123024cea2 game_list_worker: Do not clear entries when > 1 gamedir is present
Previously the map of entries was being cleared while looping through each game directory, this resulted into all game directories except the last game dir to lose content metadata information. Fix this by clearing the entries only once.
2020-08-04 21:13:35 -04:00
Lioncash 0105368cc1 ci: Make use of clang-format 10.0
10.0 seems to play nicer with C++ attributes compared to clang-format
6.0.
2020-08-02 20:55:54 -04:00
David Marcec e586921c28 am: Unstub SetScreenShotPermission 2020-08-01 00:44:14 +10:00
Lioncash 2e511246fa lz4_compression: Make use of std::span in interfaces
Allows compressing the data and size parameters into one.
2020-07-25 03:17:04 -04:00
Lioncash c5bdccfecb zstd_compression: Make use of std::span in interfaces
Allows condensing the data and size parameters into a single argument.
2020-07-25 03:11:56 -04:00
David Marcec dd4a02d15c video_core: Remove redundant pixel format type
We already get the format type before converting shadow formats and during shadow formats.
2020-07-21 12:44:32 +10:00
158 changed files with 1757 additions and 1494 deletions
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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
+2 -1
View File
@@ -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)
+7 -7
View File
@@ -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}));
}
+5 -5
View File
@@ -8,10 +8,10 @@
namespace Common {
bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected);
bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected);
bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected);
bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected);
bool AtomicCompareAndSwap(volatile u64* 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
+6 -13
View File
@@ -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 -17
View File
@@ -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));
}
+12 -11
View File
@@ -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;
+17 -17
View File
@@ -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]};
}
+7 -7
View File
@@ -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;
}
+2 -2
View File
@@ -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) {
+1 -2
View File
@@ -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
+1 -1
View File
@@ -21,7 +21,7 @@ namespace Common {
DynamicLibrary::DynamicLibrary() = default;
DynamicLibrary::DynamicLibrary(const char* filename) {
Open(filename);
void(Open(filename));
}
DynamicLibrary::DynamicLibrary(DynamicLibrary&& rhs) noexcept
+7 -6
View File
@@ -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;
}
+1 -1
View File
@@ -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);
+38 -30
View File
@@ -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
+46 -39
View File
@@ -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
-25
View File
@@ -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 {
+6 -6
View File
@@ -14,7 +14,7 @@
namespace Common {
constexpr u8 ToHexNibble(char c) {
[[nodiscard]] constexpr u8 ToHexNibble(char c) {
if (c >= 65 && c <= 70) {
return c - 55;
}
@@ -26,10 +26,10 @@ constexpr u8 ToHexNibble(char c) {
return c - 48;
}
std::vector<u8> HexStringToVector(std::string_view str, bool little_endian);
[[nodiscard]] std::vector<u8> HexStringToVector(std::string_view str, bool little_endian);
template <std::size_t Size, bool le = false>
constexpr 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) {
@@ -44,7 +44,7 @@ constexpr std::array<u8, Size> HexStringToArray(std::string_view str) {
}
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.");
@@ -60,11 +60,11 @@ std::string HexToString(const ContiguousContainer& data, bool upper = true) {
return out;
}
constexpr std::array<u8, 16> AsArray(const char (&data)[17]) {
[[nodiscard]] constexpr std::array<u8, 16> AsArray(const char (&data)[17]) {
return HexStringToArray<16>(data);
}
constexpr std::array<u8, 32> AsArray(const char (&data)[65]) {
[[nodiscard]] constexpr std::array<u8, 32> AsArray(const char (&data)[65]) {
return HexStringToArray<32>(data);
}
+1 -1
View File
@@ -94,7 +94,7 @@ public:
void Write(const Entry& entry) override;
private:
FileUtil::IOFile file;
Common::FS::IOFile file;
std::size_t bytes_written;
};
+8 -8
View File
@@ -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 -11
View File
@@ -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
+6 -6
View File
@@ -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
+1 -1
View File
@@ -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
+19 -18
View File
@@ -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;
+2 -2
View File
@@ -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);
}
};
+5 -5
View File
@@ -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();
+8 -7
View File
@@ -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)};
}
+2 -2
View File
@@ -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;
}
+1 -1
View File
@@ -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;
+18 -16
View File
@@ -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
+2 -2
View File
@@ -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
+8 -8
View File
@@ -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
+5 -5
View File
@@ -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();
}
+6 -6
View File
@@ -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();
}
+2 -2
View File
@@ -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
+8 -8
View File
@@ -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;
+3 -3
View File
@@ -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
+7 -7
View File
@@ -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!");
+103 -101
View File
@@ -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]);
}
-9
View File
@@ -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"
+5 -5
View File
@@ -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);
}
+8 -8
View File
@@ -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
-1
View File
@@ -5,7 +5,6 @@
#include <algorithm>
#include <zstd.h>
#include "common/assert.h"
#include "common/zstd_compression.h"
namespace Common::Compression {
+9 -8
View File
@@ -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
+7 -7
View File
@@ -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());
}
+1 -1
View File
@@ -116,7 +116,7 @@ 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);
}
}
+176 -110
View File
@@ -96,13 +96,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;
}
@@ -110,13 +110,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;
}
@@ -124,13 +124,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;
}
@@ -233,8 +233,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);
@@ -261,27 +262,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());
@@ -291,23 +295,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));
@@ -320,14 +327,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)),
@@ -336,8 +346,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);
@@ -355,9 +366,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()) {
@@ -417,7 +429,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;
}
}
@@ -427,16 +439,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; })) {
@@ -468,15 +482,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{};
@@ -487,8 +503,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);
@@ -506,34 +522,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]);
@@ -553,14 +574,16 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
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]);
@@ -568,8 +591,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);
@@ -604,10 +628,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 {
@@ -615,8 +640,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) ||
@@ -641,14 +667,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});
}
@@ -670,7 +698,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";
@@ -679,9 +707,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;
}
@@ -765,29 +793,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) {
@@ -799,11 +829,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)) &&
@@ -820,10 +852,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) {
@@ -833,15 +866,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(
@@ -850,16 +885,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>{}) {
@@ -883,16 +920,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);
@@ -922,16 +962,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();
@@ -941,16 +984,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;
@@ -976,8 +1022,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);
@@ -992,18 +1039,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);
@@ -1013,8 +1062,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());
@@ -1043,27 +1094,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]);
@@ -1085,8 +1142,9 @@ void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) {
static_cast<u64>(SourceKeyType::Keyblob), i);
}
if (data.HasFuses())
if (data.HasFuses()) {
SetKeyWrapped(S128KeyType::SecureBoot, data.GetSecureBootKey());
}
DeriveBase();
@@ -1100,8 +1158,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();
@@ -1111,8 +1170,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);
@@ -1150,12 +1210,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());
@@ -1166,12 +1229,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());
+2 -2
View File
@@ -17,7 +17,7 @@
#include "core/crypto/partition_data_manager.h"
#include "core/file_sys/vfs_types.h"
namespace FileUtil {
namespace Common::FS {
class IOFile;
}
@@ -308,7 +308,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)
+2 -2
View File
@@ -367,8 +367,8 @@ static bool AttemptDecrypt(const std::array<u8, 16>& key, Package2Header& header
Package2Header temp = header;
AESCipher<Key128> cipher(key, Mode::CTR);
cipher.SetIV(header.header_ctr);
cipher.Transcode(&temp.header_ctr, sizeof(Package2Header) - 0x100, &temp.header_ctr,
Op::Decrypt);
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;
+1 -1
View File
@@ -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) {
+1 -1
View File
@@ -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);
+3 -3
View File
@@ -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;
+6 -12
View File
@@ -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;
}
+18 -24
View File
@@ -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
+28 -28
View File
@@ -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) {
+1 -1
View File
@@ -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;
+94 -83
View File
@@ -14,6 +14,8 @@
namespace FileSys {
namespace FS = Common::FS;
static std::string ModeFlagsToString(Mode mode) {
std::string mode_str;
@@ -57,17 +59,19 @@ 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);
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
if (cache.find(path) != cache.end()) {
auto weak = cache[path];
if (!weak.expired()) {
@@ -75,11 +79,11 @@ VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode 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());
auto backing = std::make_shared<FS::IOFile>(path, ModeFlagsToString(perms).c_str());
cache[path] = backing;
// Cannot use make_shared as RealVfsFile constructor is private
@@ -87,33 +91,31 @@ VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode 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);
if (cache.find(old_path) != cache.end()) {
auto file = cache[old_path].lock();
@@ -122,8 +124,8 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_
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;
}
@@ -139,28 +141,30 @@ 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);
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
if (cache.find(path) != cache.end()) {
if (!cache[path].expired())
if (!cache[path].expired()) {
cache[path].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,35 +172,33 @@ 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);
FS::SanitizePath(kv.first, FS::DirectorySeparator::PlatformDefault);
const auto file_new_path =
FileUtil::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()),
FileUtil::DirectorySeparator::PlatformDefault);
FS::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()),
FS::DirectorySeparator::PlatformDefault);
auto cached = cache[file_old_path];
if (!cached.expired()) {
auto file = cached.lock();
@@ -211,24 +213,24 @@ VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_,
}
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())
if (!cache[kv.first].expired()) {
cache[kv.first].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 +260,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(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(offset, SEEK_SET)) {
return 0;
}
return backing->WriteBytes(data, length);
}
@@ -282,16 +286,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 +306,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 +325,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 +361,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 +396,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 +435,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;
});
+4 -4
View File
@@ -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;
+12 -1
View File
@@ -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:
+1 -1
View File
@@ -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);
+2 -2
View File
@@ -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};
}
};
+26 -20
View File
@@ -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;
+12 -11
View File
@@ -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;
}
+11 -10
View File
@@ -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
+11 -17
View File
@@ -664,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();
}
+1 -1
View File
@@ -289,7 +289,7 @@ private:
class SchedulerLock {
public:
explicit SchedulerLock(KernelCore& kernel);
[[nodiscard]] explicit SchedulerLock(KernelCore& kernel);
~SchedulerLock();
protected:
+8 -4
View File
@@ -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)
+4 -4
View File
@@ -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() ||
+11 -11
View File
@@ -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 "
+5 -1
View File
@@ -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);
+7
View File
@@ -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
+1 -1
View File
@@ -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;
+12 -14
View File
@@ -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()) {
+40 -40
View File
@@ -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) {
+13 -3
View File
@@ -844,8 +844,7 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
return;
}
FileSys::StorageId id;
FileSys::StorageId id{};
switch (parameters.space_id) {
case FileSys::SaveDataSpaceId::NandUser:
id = FileSys::StorageId::NandUser;
@@ -857,6 +856,10 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
case FileSys::SaveDataSpaceId::NandSystem:
id = FileSys::StorageId::NandSystem;
break;
case FileSys::SaveDataSpaceId::TemporaryStorage:
case FileSys::SaveDataSpaceId::ProperSystem:
case FileSys::SaveDataSpaceId::SafeMode:
UNREACHABLE();
}
auto filesystem =
@@ -902,7 +905,14 @@ void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
// Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData
constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None);
LOG_WARNING(Service_FS, "(STUBBED) called, flags={}", flags);
LOG_WARNING(Service_FS,
"(STUBBED) called, flags={}, space_id={}, attribute.title_id={:016X}\n"
"attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n"
"attribute.type={}, attribute.rank={}, attribute.index={}",
flags, static_cast<u32>(parameters.space_id), parameters.attribute.title_id,
parameters.attribute.user_id[1], parameters.attribute.user_id[0],
parameters.attribute.save_id, static_cast<u32>(parameters.attribute.type),
static_cast<u32>(parameters.attribute.rank), parameters.attribute.index);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
@@ -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) {
@@ -21,8 +21,9 @@ namespace Service::Nvidia::Devices {
/// implement the ioctl interface.
class nvdevice {
public:
explicit nvdevice(Core::System& system) : system{system} {};
explicit nvdevice(Core::System& system) : system{system} {}
virtual ~nvdevice() = default;
union Ioctl {
u32_le raw;
BitField<0, 8, u32> cmd;
+6 -4
View File
@@ -86,11 +86,13 @@ public:
[[nodiscard]] s64 GetNextTicks() const;
[[nodiscard]] std::unique_lock<std::mutex> Lock() const { return std::unique_lock{*guard}; }
[[nodiscard]] std::unique_lock<std::mutex> Lock() const {
return std::unique_lock{*guard};
}
private :
/// Finds the display identified by the specified ID.
[[nodiscard]] VI::Display* FindDisplay(u64 display_id);
private:
/// Finds the display identified by the specified ID.
[[nodiscard]] VI::Display* FindDisplay(u64 display_id);
/// Finds the display identified by the specified ID.
[[nodiscard]] const VI::Display* FindDisplay(u64 display_id) const;
@@ -73,10 +73,8 @@ TimeZoneContentManager::TimeZoneContentManager(TimeManager& time_manager, Core::
std::string location_name;
const auto timezone_setting = Settings::GetTimeZoneString();
if (timezone_setting == "auto") {
if (timezone_setting == "auto" || timezone_setting == "default") {
location_name = Common::TimeZone::GetDefaultTimeZone();
} else if (timezone_setting == "default") {
location_name = location_name;
} else {
location_name = timezone_setting;
}
+1 -1
View File
@@ -67,7 +67,7 @@ FileType GuessFromFilename(const std::string& name) {
return FileType::NCA;
const std::string extension =
Common::ToLower(std::string(FileUtil::GetExtensionFromFilename(name)));
Common::ToLower(std::string(Common::FS::GetExtensionFromFilename(name)));
if (extension == "elf")
return FileType::ELF;
+19 -7
View File
@@ -42,7 +42,7 @@ u64 StandardVmCallbacks::HidKeysDown() {
if (applet_resource == nullptr) {
LOG_WARNING(CheatEngine,
"Attempted to read input state, but applet resource is not initialized!");
return false;
return 0;
}
const auto press_state =
@@ -199,17 +199,29 @@ void CheatEngine::Initialize() {
metadata.title_id = system.CurrentProcess()->GetTitleID();
const auto& page_table = system.CurrentProcess()->PageTable();
metadata.heap_extents = {page_table.GetHeapRegionStart(), page_table.GetHeapRegionSize()};
metadata.address_space_extents = {page_table.GetAddressSpaceStart(),
page_table.GetAddressSpaceSize()};
metadata.alias_extents = {page_table.GetAliasCodeRegionStart(),
page_table.GetAliasCodeRegionSize()};
metadata.heap_extents = {
.base = page_table.GetHeapRegionStart(),
.size = page_table.GetHeapRegionSize(),
};
metadata.address_space_extents = {
.base = page_table.GetAddressSpaceStart(),
.size = page_table.GetAddressSpaceSize(),
};
metadata.alias_extents = {
.base = page_table.GetAliasCodeRegionStart(),
.size = page_table.GetAliasCodeRegionSize(),
};
is_pending_reload.exchange(true);
}
void CheatEngine::SetMainMemoryParameters(VAddr main_region_begin, u64 main_region_size) {
metadata.main_nso_extents = {main_region_begin, main_region_size};
metadata.main_nso_extents = {
.base = main_region_begin,
.size = main_region_size,
};
}
void CheatEngine::Reload(std::vector<CheatEntry> cheats) {
+2 -2
View File
@@ -38,11 +38,11 @@ PerfStats::~PerfStats() {
std::ostringstream stream;
std::copy(perf_history.begin() + IgnoreFrames, perf_history.begin() + current_index,
std::ostream_iterator<double>(stream, "\n"));
const std::string& path = FileUtil::GetUserPath(FileUtil::UserPath::LogDir);
const std::string& path = Common::FS::GetUserPath(Common::FS::UserPath::LogDir);
// %F Date format expanded is "%Y-%m-%d"
const std::string filename =
fmt::format("{}/{:%F-%H-%M}_{:016X}.csv", path, *std::localtime(&t), title_id);
FileUtil::IOFile file(filename, "w");
Common::FS::IOFile file(filename, "w");
file.WriteString(stream.str());
}
+5 -4
View File
@@ -28,8 +28,9 @@
namespace {
std::string GetPath(std::string_view type, u64 title_id, std::string_view timestamp) {
return fmt::format("{}{}/{:016X}_{}.json", FileUtil::GetUserPath(FileUtil::UserPath::LogDir),
type, title_id, timestamp);
return fmt::format("{}{}/{:016X}_{}.json",
Common::FS::GetUserPath(Common::FS::UserPath::LogDir), type, title_id,
timestamp);
}
std::string GetTimestamp() {
@@ -40,13 +41,13 @@ std::string GetTimestamp() {
using namespace nlohmann;
void SaveToFile(json json, const std::string& filename) {
if (!FileUtil::CreateFullPath(filename)) {
if (!Common::FS::CreateFullPath(filename)) {
LOG_ERROR(Core, "Failed to create path for '{}' to save report!", filename);
return;
}
std::ofstream file(
FileUtil::SanitizePath(filename, FileUtil::DirectorySeparator::PlatformDefault));
Common::FS::SanitizePath(filename, Common::FS::DirectorySeparator::PlatformDefault));
file << std::setw(4) << json << std::endl;
}
+2 -2
View File
@@ -121,8 +121,8 @@ void LogSettings() {
log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching.GetValue());
log_setting("Audio_OutputDevice", values.audio_device_id);
log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd);
log_setting("DataStorage_NandDir", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
log_setting("DataStorage_SdmcDir", FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir));
log_setting("DataStorage_NandDir", Common::FS::GetUserPath(Common::FS::UserPath::NANDDir));
log_setting("DataStorage_SdmcDir", Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir));
log_setting("Debugging_UseGdbstub", values.use_gdbstub);
log_setting("Debugging_GdbstubPort", values.gdbstub_port);
log_setting("Debugging_ProgramArgs", values.program_args);
+8 -6
View File
@@ -25,6 +25,8 @@
namespace Core {
namespace Telemetry = Common::Telemetry;
static u64 GenerateTelemetryId() {
u64 telemetry_id{};
@@ -70,12 +72,12 @@ static const char* TranslateGPUAccuracyLevel(Settings::GPUAccuracy backend) {
u64 GetTelemetryId() {
u64 telemetry_id{};
const std::string filename{FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) +
const std::string filename{Common::FS::GetUserPath(Common::FS::UserPath::ConfigDir) +
"telemetry_id"};
bool generate_new_id = !FileUtil::Exists(filename);
bool generate_new_id = !Common::FS::Exists(filename);
if (!generate_new_id) {
FileUtil::IOFile file(filename, "rb");
Common::FS::IOFile file(filename, "rb");
if (!file.IsOpen()) {
LOG_ERROR(Core, "failed to open telemetry_id: {}", filename);
return {};
@@ -88,7 +90,7 @@ u64 GetTelemetryId() {
}
if (generate_new_id) {
FileUtil::IOFile file(filename, "wb");
Common::FS::IOFile file(filename, "wb");
if (!file.IsOpen()) {
LOG_ERROR(Core, "failed to open telemetry_id: {}", filename);
return {};
@@ -102,10 +104,10 @@ u64 GetTelemetryId() {
u64 RegenerateTelemetryId() {
const u64 new_telemetry_id{GenerateTelemetryId()};
const std::string filename{FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) +
const std::string filename{Common::FS::GetUserPath(Common::FS::UserPath::ConfigDir) +
"telemetry_id"};
FileUtil::IOFile file(filename, "wb");
Common::FS::IOFile file(filename, "wb");
if (!file.IsOpen()) {
LOG_ERROR(Core, "failed to open telemetry_id: {}", filename);
return {};
+3 -2
View File
@@ -52,7 +52,7 @@ public:
* @param value Value for the field to add.
*/
template <typename T>
void AddField(Telemetry::FieldType type, const char* name, T value) {
void AddField(Common::Telemetry::FieldType type, const char* name, T value) {
field_collection.AddField(type, name, std::move(value));
}
@@ -63,7 +63,8 @@ public:
bool SubmitTestcase();
private:
Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session
/// Tracks all added fields for the session
Common::Telemetry::FieldCollection field_collection;
};
/**
+16 -15
View File
@@ -107,28 +107,21 @@ void Freezer::Unfreeze(VAddr address) {
LOG_DEBUG(Common_Memory, "Unfreezing memory for address={:016X}", address);
entries.erase(
std::remove_if(entries.begin(), entries.end(),
[&address](const Entry& entry) { return entry.address == address; }),
entries.end());
std::erase_if(entries, [address](const Entry& entry) { return entry.address == address; });
}
bool Freezer::IsFrozen(VAddr address) const {
std::lock_guard lock{entries_mutex};
return std::find_if(entries.begin(), entries.end(), [&address](const Entry& entry) {
return entry.address == address;
}) != entries.end();
return FindEntry(address) != entries.cend();
}
void Freezer::SetFrozenValue(VAddr address, u64 value) {
std::lock_guard lock{entries_mutex};
const auto iter = std::find_if(entries.begin(), entries.end(), [&address](const Entry& entry) {
return entry.address == address;
});
const auto iter = FindEntry(address);
if (iter == entries.end()) {
if (iter == entries.cend()) {
LOG_ERROR(Common_Memory,
"Tried to set freeze value for address={:016X} that is not frozen!", address);
return;
@@ -143,11 +136,9 @@ void Freezer::SetFrozenValue(VAddr address, u64 value) {
std::optional<Freezer::Entry> Freezer::GetEntry(VAddr address) const {
std::lock_guard lock{entries_mutex};
const auto iter = std::find_if(entries.begin(), entries.end(), [&address](const Entry& entry) {
return entry.address == address;
});
const auto iter = FindEntry(address);
if (iter == entries.end()) {
if (iter == entries.cend()) {
return std::nullopt;
}
@@ -160,6 +151,16 @@ std::vector<Freezer::Entry> Freezer::GetEntries() const {
return entries;
}
Freezer::Entries::iterator Freezer::FindEntry(VAddr address) {
return std::find_if(entries.begin(), entries.end(),
[address](const Entry& entry) { return entry.address == address; });
}
Freezer::Entries::const_iterator Freezer::FindEntry(VAddr address) const {
return std::find_if(entries.begin(), entries.end(),
[address](const Entry& entry) { return entry.address == address; });
}
void Freezer::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late) {
if (!IsActive()) {
LOG_DEBUG(Common_Memory, "Memory freezer has been deactivated, ending callback events.");
+6 -1
View File
@@ -73,13 +73,18 @@ public:
std::vector<Entry> GetEntries() const;
private:
using Entries = std::vector<Entry>;
Entries::iterator FindEntry(VAddr address);
Entries::const_iterator FindEntry(VAddr address) const;
void FrameCallback(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
void FillEntryReads();
std::atomic_bool active{false};
mutable std::mutex entries_mutex;
std::vector<Entry> entries;
Entries entries;
std::shared_ptr<Core::Timing::EventType> event;
Core::Timing::CoreTiming& core_timing;
+7 -7
View File
@@ -148,19 +148,17 @@ void GCButtonFactory::EndConfiguration() {
class GCAnalog final : public Input::AnalogDevice {
public:
GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter)
GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter,
float range_)
: port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter),
origin_value_x(adapter->GetOriginValue(port_, axis_x_)),
origin_value_y(adapter->GetOriginValue(port_, axis_y_)) {}
origin_value_y(adapter->GetOriginValue(port_, axis_y_)), range(range_) {}
float GetAxis(int axis) const {
if (gcadapter->DeviceConnected(port)) {
std::lock_guard lock{mutex};
const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y;
// division is not by a perfect 128 to account for some variance in center location
// e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range
// [20-230]
return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / 95.0f;
return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / (100.0f * range);
}
return 0.0f;
}
@@ -215,6 +213,7 @@ private:
GCAdapter::Adapter* gcadapter;
const float origin_value_x;
const float origin_value_y;
const float range;
mutable std::mutex mutex;
};
@@ -234,8 +233,9 @@ std::unique_ptr<Input::AnalogDevice> GCAnalogFactory::Create(const Common::Param
const int axis_x = params.Get("axis_x", 0);
const int axis_y = params.Get("axis_y", 1);
const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f);
const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
return std::make_unique<GCAnalog>(port, axis_x, axis_y, deadzone, adapter.get());
return std::make_unique<GCAnalog>(port, axis_x, axis_y, deadzone, adapter.get(), range);
}
void GCAnalogFactory::BeginConfiguration() {
+14 -11
View File
@@ -66,14 +66,14 @@ public:
state.axes.insert_or_assign(axis, value);
}
float GetAxis(int axis) const {
float GetAxis(int axis, float range) const {
std::lock_guard lock{mutex};
return state.axes.at(axis) / 32767.0f;
return state.axes.at(axis) / (32767.0f * range);
}
std::tuple<float, float> GetAnalog(int axis_x, int axis_y) const {
float x = GetAxis(axis_x);
float y = GetAxis(axis_y);
std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range) const {
float x = GetAxis(axis_x, range);
float y = GetAxis(axis_y, range);
y = -y; // 3DS uses an y-axis inverse from SDL
// Make sure the coordinates are in the unit circle,
@@ -313,7 +313,7 @@ public:
trigger_if_greater(trigger_if_greater_) {}
bool GetStatus() const override {
const float axis_value = joystick->GetAxis(axis);
const float axis_value = joystick->GetAxis(axis, 1.0f);
if (trigger_if_greater) {
return axis_value > threshold;
}
@@ -329,11 +329,13 @@ private:
class SDLAnalog final : public Input::AnalogDevice {
public:
SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, float deadzone_)
: joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_) {}
SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, float deadzone_,
float range_)
: joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_),
range(range_) {}
std::tuple<float, float> GetStatus() const override {
const auto [x, y] = joystick->GetAnalog(axis_x, axis_y);
const auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range);
const float r = std::sqrt((x * x) + (y * y));
if (r > deadzone) {
return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone),
@@ -363,6 +365,7 @@ private:
const int axis_x;
const int axis_y;
const float deadzone;
const float range;
};
/// A button device factory that creates button devices from SDL joystick
@@ -458,13 +461,13 @@ public:
const int axis_x = params.Get("axis_x", 0);
const int axis_y = params.Get("axis_y", 1);
const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f);
const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
auto joystick = state.GetSDLJoystickByGUID(guid, port);
// This is necessary so accessing GetAxis with axis_x and axis_y won't crash
joystick->SetAxis(axis_x, 0);
joystick->SetAxis(axis_y, 0);
return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, deadzone);
return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, deadzone, range);
}
private:
+2 -4
View File
@@ -224,8 +224,7 @@ void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 clie
} else {
failure_callback();
}
})
.detach();
}).detach();
}
CalibrationConfigurationJob::CalibrationConfigurationJob(
@@ -279,8 +278,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
complete_event.Wait();
socket.Stop();
worker_thread.join();
})
.detach();
}).detach();
}
CalibrationConfigurationJob::~CalibrationConfigurationJob() {
+1 -1
View File
@@ -647,7 +647,7 @@ public:
GetX() + GetWidth(), // right
GetY() // bottom
};
};
}
f32 GetX() const {
return std::max(0.0f, translate_x - std::fabs(scale_x));
+8 -13
View File
@@ -94,7 +94,8 @@ void MaxwellDMA::CopyPitchToPitch() {
}
void MaxwellDMA::CopyBlockLinearToPitch() {
ASSERT(regs.src_params.block_size.depth == 0);
UNIMPLEMENTED_IF(regs.src_params.block_size.depth != 0);
UNIMPLEMENTED_IF(regs.src_params.layer != 0);
// Optimized path for micro copies.
const size_t dst_size = static_cast<size_t>(regs.pitch_out) * regs.line_count;
@@ -123,17 +124,12 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
write_buffer.resize(dst_size);
}
if (Settings::IsGPULevelExtreme()) {
memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size);
memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size);
} else {
memory_manager.ReadBlockUnsafe(regs.offset_in, read_buffer.data(), src_size);
memory_manager.ReadBlockUnsafe(regs.offset_out, write_buffer.data(), dst_size);
}
memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size);
memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size);
UnswizzleSubrect(regs.line_length_in, regs.line_count, regs.pitch_out, width, bytes_per_pixel,
read_buffer.data() + src_layer_size * src_params.layer, write_buffer.data(),
block_height, src_params.origin.x, src_params.origin.y);
block_height, src_params.origin.x, src_params.origin.y, write_buffer.data(),
read_buffer.data());
memory_manager.WriteBlock(regs.offset_out, write_buffer.data(), dst_size);
}
@@ -198,7 +194,6 @@ void MaxwellDMA::FastCopyBlockLinearToPitch() {
if (read_buffer.size() < src_size) {
read_buffer.resize(src_size);
}
if (write_buffer.size() < dst_size) {
write_buffer.resize(dst_size);
}
@@ -212,8 +207,8 @@ void MaxwellDMA::FastCopyBlockLinearToPitch() {
}
UnswizzleSubrect(regs.line_length_in, regs.line_count, regs.pitch_out, regs.src_params.width,
bytes_per_pixel, read_buffer.data(), write_buffer.data(),
regs.src_params.block_size.height, pos_x, pos_y);
bytes_per_pixel, regs.src_params.block_size.height, pos_x, pos_y,
write_buffer.data(), read_buffer.data());
memory_manager.WriteBlock(regs.offset_out, write_buffer.data(), dst_size);
}

Some files were not shown because too many files have changed in this diff Show More