mirror of
				https://git.tardis.systems/mirrors/yuzu
				synced 2025-10-31 18:54:14 +01:00 
			
		
		
		
	Address review comments and fix compilation problems
This commit is contained in:
		
							parent
							
								
									2c049ae06d
								
							
						
					
					
						commit
						975deb7528
					
				| @ -1,12 +1,12 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include <core/core.h> | ||||
| #include <core/file_sys/mode.h> | ||||
| #include <core/file_sys/patch_manager.h> | ||||
| #include <core/loader/nro.h> | ||||
| #include <jni.h> | ||||
| #include "core/core.h" | ||||
| #include "core/file_sys/fs_filesystem.h" | ||||
| #include "core/file_sys/patch_manager.h" | ||||
| #include "core/loader/loader.h" | ||||
| #include "core/loader/nro.h" | ||||
| #include "jni.h" | ||||
| #include "jni/android_common/android_common.h" | ||||
| #include "native.h" | ||||
| 
 | ||||
| @ -79,7 +79,7 @@ extern "C" { | ||||
| jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobject obj, | ||||
|                                                                jstring jpath) { | ||||
|     const auto file = EmulationSession::GetInstance().System().GetFilesystem()->OpenFile( | ||||
|         GetJString(env, jpath), FileSys::Mode::Read); | ||||
|         GetJString(env, jpath), FileSys::OpenMode::Read); | ||||
|     if (!file) { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
| @ -35,9 +35,10 @@ | ||||
| #include "core/crypto/key_manager.h" | ||||
| #include "core/file_sys/card_image.h" | ||||
| #include "core/file_sys/content_archive.h" | ||||
| #include "core/file_sys/fs_filesystem.h" | ||||
| #include "core/file_sys/submission_package.h" | ||||
| #include "core/file_sys/vfs.h" | ||||
| #include "core/file_sys/vfs_real.h" | ||||
| #include "core/file_sys/vfs/vfs.h" | ||||
| #include "core/file_sys/vfs/vfs_real.h" | ||||
| #include "core/frontend/applets/cabinet.h" | ||||
| #include "core/frontend/applets/controller.h" | ||||
| #include "core/frontend/applets/error.h" | ||||
| @ -154,7 +155,7 @@ void EmulationSession::SurfaceChanged() { | ||||
| } | ||||
| 
 | ||||
| void EmulationSession::ConfigureFilesystemProvider(const std::string& filepath) { | ||||
|     const auto file = m_system.GetFilesystem()->OpenFile(filepath, FileSys::Mode::Read); | ||||
|     const auto file = m_system.GetFilesystem()->OpenFile(filepath, FileSys::OpenMode::Read); | ||||
|     if (!file) { | ||||
|         return; | ||||
|     } | ||||
| @ -475,8 +476,8 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* en | ||||
|     u64 program_id = EmulationSession::GetProgramId(env, jprogramId); | ||||
|     std::string updatePath = GetJString(env, jupdatePath); | ||||
|     std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>( | ||||
|         EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(updatePath, | ||||
|                                                                            FileSys::Mode::Read)); | ||||
|         EmulationSession::GetInstance().System().GetFilesystem()->OpenFile( | ||||
|             updatePath, FileSys::OpenMode::Read)); | ||||
|     for (const auto& item : nsp->GetNCAs()) { | ||||
|         for (const auto& nca_details : item.second) { | ||||
|             if (nca_details.second->GetName().ends_with(".cnmt.nca")) { | ||||
| @ -719,7 +720,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv* | ||||
|                                                                         jobject instance) { | ||||
|     const auto nand_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir); | ||||
|     auto vfs_nand_dir = EmulationSession::GetInstance().System().GetFilesystem()->OpenDirectory( | ||||
|         Common::FS::PathToUTF8String(nand_dir), FileSys::Mode::Read); | ||||
|         Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read); | ||||
| 
 | ||||
|     const auto user_id = EmulationSession::GetInstance().System().GetProfileManager().GetUser( | ||||
|         static_cast<std::size_t>(0)); | ||||
| @ -889,7 +890,7 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j | ||||
| 
 | ||||
|     const auto nandDir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir); | ||||
|     auto vfsNandDir = system.GetFilesystem()->OpenDirectory(Common::FS::PathToUTF8String(nandDir), | ||||
|                                                             FileSys::Mode::Read); | ||||
|                                                             FileSys::OpenMode::Read); | ||||
| 
 | ||||
|     const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( | ||||
|         {}, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, | ||||
|  | ||||
| @ -3,6 +3,7 @@ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <type_traits> | ||||
| #include "bit_cast.h" | ||||
| 
 | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
 | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
|  | ||||
| @ -1,12 +1,14 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
 | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| 
 | ||||
| namespace FileSys { | ||||
| 
 | ||||
| struct ReadOption { | ||||
|     u32 _value; | ||||
|     u32 value; | ||||
| 
 | ||||
|     static const ReadOption None; | ||||
| }; | ||||
| @ -18,7 +20,7 @@ enum ReadOptionFlag : u32 { | ||||
| inline constexpr const ReadOption ReadOption::None = {ReadOptionFlag_None}; | ||||
| 
 | ||||
| inline constexpr bool operator==(const ReadOption& lhs, const ReadOption& rhs) { | ||||
|     return lhs._value == rhs._value; | ||||
|     return lhs.value == rhs.value; | ||||
| } | ||||
| 
 | ||||
| inline constexpr bool operator!=(const ReadOption& lhs, const ReadOption& rhs) { | ||||
| @ -33,10 +35,10 @@ enum WriteOptionFlag : u32 { | ||||
| }; | ||||
| 
 | ||||
| struct WriteOption { | ||||
|     u32 _value; | ||||
|     u32 value; | ||||
| 
 | ||||
|     constexpr inline bool HasFlushFlag() const { | ||||
|         return _value & WriteOptionFlag_Flush; | ||||
|         return value & WriteOptionFlag_Flush; | ||||
|     } | ||||
| 
 | ||||
|     static const WriteOption None; | ||||
| @ -47,7 +49,7 @@ inline constexpr const WriteOption WriteOption::None = {WriteOptionFlag_None}; | ||||
| inline constexpr const WriteOption WriteOption::Flush = {WriteOptionFlag_Flush}; | ||||
| 
 | ||||
| inline constexpr bool operator==(const WriteOption& lhs, const WriteOption& rhs) { | ||||
|     return lhs._value == rhs._value; | ||||
|     return lhs.value == rhs.value; | ||||
| } | ||||
| 
 | ||||
| inline constexpr bool operator!=(const WriteOption& lhs, const WriteOption& rhs) { | ||||
|  | ||||
| @ -3,6 +3,9 @@ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/common_types.h" | ||||
| 
 | ||||
| namespace FileSys { | ||||
| 
 | ||||
| enum class OpenMode : u32 { | ||||
| @ -20,9 +23,6 @@ enum class OpenDirectoryMode : u64 { | ||||
|     File = (1 << 1), | ||||
| 
 | ||||
|     All = (Directory | File), | ||||
| 
 | ||||
|     /* TODO: Separate enum, like N? */ | ||||
|     _NotRequireFileSize = (1 << 31), | ||||
| }; | ||||
| DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode) | ||||
| 
 | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
 | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| @ -8,39 +8,31 @@ | ||||
| 
 | ||||
| namespace FileSys { | ||||
| 
 | ||||
| std::mutex g_mutex; | ||||
| 
 | ||||
| constexpr size_t RequiredAlignment = alignof(u64); | ||||
| 
 | ||||
| void* AllocateUnsafe(size_t size) { | ||||
|     /* Allocate. */ | ||||
|     // Allocate
 | ||||
|     void* const ptr = ::operator new(size, std::align_val_t{RequiredAlignment}); | ||||
| 
 | ||||
|     /* Check alignment. */ | ||||
|     // Check alignment
 | ||||
|     ASSERT(Common::IsAligned(reinterpret_cast<uintptr_t>(ptr), RequiredAlignment)); | ||||
| 
 | ||||
|     /* Return allocated pointer. */ | ||||
|     // Return allocated pointer
 | ||||
|     return ptr; | ||||
| } | ||||
| 
 | ||||
| void DeallocateUnsafe(void* ptr, size_t size) { | ||||
|     /* Deallocate the pointer. */ | ||||
|     // Deallocate the pointer
 | ||||
|     ::operator delete(ptr, std::align_val_t{RequiredAlignment}); | ||||
| } | ||||
| 
 | ||||
| void* Allocate(size_t size) { | ||||
|     /* Lock the allocator. */ | ||||
|     std::scoped_lock lk(g_mutex); | ||||
| 
 | ||||
|     return AllocateUnsafe(size); | ||||
| } | ||||
| 
 | ||||
| void Deallocate(void* ptr, size_t size) { | ||||
|     /* If the pointer is non-null, deallocate it. */ | ||||
|     // If the pointer is non-null, deallocate it
 | ||||
|     if (ptr != nullptr) { | ||||
|         /* Lock the allocator. */ | ||||
|         std::scoped_lock lk(g_mutex); | ||||
| 
 | ||||
|         DeallocateUnsafe(ptr, size); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,8 +1,10 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
 | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| 
 | ||||
| namespace FileSys { | ||||
| 
 | ||||
| enum class OperationId : s64 { | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
 | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| @ -34,8 +34,7 @@ public: | ||||
|         size_t m_length_and_is_normalized; | ||||
| 
 | ||||
|     public: | ||||
|         constexpr WriteBuffer() : m_buffer(nullptr), m_length_and_is_normalized(0) { /* ... */ | ||||
|         } | ||||
|         constexpr WriteBuffer() : m_buffer(nullptr), m_length_and_is_normalized(0) {} | ||||
| 
 | ||||
|         constexpr ~WriteBuffer() { | ||||
|             if (m_buffer != nullptr) { | ||||
| @ -113,35 +112,32 @@ private: | ||||
|     WriteBuffer m_write_buffer; | ||||
| 
 | ||||
| public: | ||||
|     constexpr Path() : m_str(EmptyPath), m_write_buffer() { | ||||
|         /* ... */ | ||||
|     } | ||||
|     constexpr Path() : m_str(EmptyPath), m_write_buffer() {} | ||||
| 
 | ||||
|     constexpr Path(const char* s) : m_str(s), m_write_buffer() { | ||||
|         m_write_buffer.SetNormalized(); | ||||
|     } | ||||
| 
 | ||||
|     constexpr ~Path() { /* ... */ | ||||
|     } | ||||
|     constexpr ~Path() = default; | ||||
| 
 | ||||
|     constexpr Result SetShallowBuffer(const char* buffer) { | ||||
|         /* Check pre-conditions. */ | ||||
|         // Check pre-conditions
 | ||||
|         ASSERT(m_write_buffer.GetLength() == 0); | ||||
| 
 | ||||
|         /* Check the buffer is valid. */ | ||||
|         // Check the buffer is valid
 | ||||
|         R_UNLESS(buffer != nullptr, ResultNullptrArgument); | ||||
| 
 | ||||
|         /* Set buffer. */ | ||||
|         // Set buffer
 | ||||
|         this->SetReadOnlyBuffer(buffer); | ||||
| 
 | ||||
|         /* Note that we're normalized. */ | ||||
|         // Note that we're normalized
 | ||||
|         this->SetNormalized(); | ||||
| 
 | ||||
|         R_SUCCEED(); | ||||
|     } | ||||
| 
 | ||||
|     constexpr const char* GetString() const { | ||||
|         /* Check pre-conditions. */ | ||||
|         // Check pre-conditions
 | ||||
|         ASSERT(this->IsNormalized()); | ||||
| 
 | ||||
|         return m_str; | ||||
| @ -164,69 +160,69 @@ public: | ||||
|     } | ||||
| 
 | ||||
|     Result Initialize(const Path& rhs) { | ||||
|         /* Check the other path is normalized. */ | ||||
|         // Check the other path is normalized
 | ||||
|         const bool normalized = rhs.IsNormalized(); | ||||
|         R_UNLESS(normalized, ResultNotNormalized); | ||||
| 
 | ||||
|         /* Allocate buffer for our path. */ | ||||
|         // Allocate buffer for our path
 | ||||
|         const auto len = rhs.GetLength(); | ||||
|         R_TRY(this->Preallocate(len + 1)); | ||||
| 
 | ||||
|         /* Copy the path. */ | ||||
|         // Copy the path
 | ||||
|         const size_t copied = Strlcpy<char>(m_write_buffer.Get(), rhs.GetString(), len + 1); | ||||
|         R_UNLESS(copied == len, ResultUnexpectedInPathA); | ||||
| 
 | ||||
|         /* Set normalized. */ | ||||
|         // Set normalized
 | ||||
|         this->SetNormalized(); | ||||
|         R_SUCCEED(); | ||||
|     } | ||||
| 
 | ||||
|     Result Initialize(const char* path, size_t len) { | ||||
|         /* Check the path is valid. */ | ||||
|         // Check the path is valid
 | ||||
|         R_UNLESS(path != nullptr, ResultNullptrArgument); | ||||
| 
 | ||||
|         /* Initialize. */ | ||||
|         // Initialize
 | ||||
|         R_TRY(this->InitializeImpl(path, len)); | ||||
| 
 | ||||
|         /* Set not normalized. */ | ||||
|         // Set not normalized
 | ||||
|         this->SetNotNormalized(); | ||||
| 
 | ||||
|         R_SUCCEED(); | ||||
|     } | ||||
| 
 | ||||
|     Result Initialize(const char* path) { | ||||
|         /* Check the path is valid. */ | ||||
|         // Check the path is valid
 | ||||
|         R_UNLESS(path != nullptr, ResultNullptrArgument); | ||||
| 
 | ||||
|         R_RETURN(this->Initialize(path, std::strlen(path))); | ||||
|     } | ||||
| 
 | ||||
|     Result InitializeWithReplaceBackslash(const char* path) { | ||||
|         /* Check the path is valid. */ | ||||
|         // Check the path is valid
 | ||||
|         R_UNLESS(path != nullptr, ResultNullptrArgument); | ||||
| 
 | ||||
|         /* Initialize. */ | ||||
|         // Initialize
 | ||||
|         R_TRY(this->InitializeImpl(path, std::strlen(path))); | ||||
| 
 | ||||
|         /* Replace slashes as desired. */ | ||||
|         // Replace slashes as desired
 | ||||
|         if (const auto write_buffer_length = m_write_buffer.GetLength(); write_buffer_length > 1) { | ||||
|             Replace(m_write_buffer.Get(), write_buffer_length - 1, '\\', '/'); | ||||
|         } | ||||
| 
 | ||||
|         /* Set not normalized. */ | ||||
|         // Set not normalized
 | ||||
|         this->SetNotNormalized(); | ||||
| 
 | ||||
|         R_SUCCEED(); | ||||
|     } | ||||
| 
 | ||||
|     Result InitializeWithReplaceForwardSlashes(const char* path) { | ||||
|         /* Check the path is valid. */ | ||||
|         // Check the path is valid
 | ||||
|         R_UNLESS(path != nullptr, ResultNullptrArgument); | ||||
| 
 | ||||
|         /* Initialize. */ | ||||
|         // Initialize
 | ||||
|         R_TRY(this->InitializeImpl(path, std::strlen(path))); | ||||
| 
 | ||||
|         /* Replace slashes as desired. */ | ||||
|         // Replace slashes as desired
 | ||||
|         if (m_write_buffer.GetLength() > 1) { | ||||
|             if (auto* p = m_write_buffer.Get(); p[0] == '/' && p[1] == '/') { | ||||
|                 p[0] = '\\'; | ||||
| @ -234,23 +230,23 @@ public: | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /* Set not normalized. */ | ||||
|         // Set not normalized
 | ||||
|         this->SetNotNormalized(); | ||||
| 
 | ||||
|         R_SUCCEED(); | ||||
|     } | ||||
| 
 | ||||
|     Result InitializeWithNormalization(const char* path, size_t size) { | ||||
|         /* Check the path is valid. */ | ||||
|         // Check the path is valid
 | ||||
|         R_UNLESS(path != nullptr, ResultNullptrArgument); | ||||
| 
 | ||||
|         /* Initialize. */ | ||||
|         // Initialize
 | ||||
|         R_TRY(this->InitializeImpl(path, size)); | ||||
| 
 | ||||
|         /* Set not normalized. */ | ||||
|         // Set not normalized
 | ||||
|         this->SetNotNormalized(); | ||||
| 
 | ||||
|         /* Perform normalization. */ | ||||
|         // Perform normalization
 | ||||
|         PathFlags path_flags; | ||||
|         if (IsPathRelative(m_str)) { | ||||
|             path_flags.AllowRelativePath(); | ||||
| @ -269,7 +265,7 @@ public: | ||||
|             R_SUCCEED(); | ||||
|         } | ||||
| 
 | ||||
|         /* Normalize. */ | ||||
|         // Normalize
 | ||||
|         R_TRY(this->Normalize(path_flags)); | ||||
| 
 | ||||
|         this->SetNormalized(); | ||||
| @ -277,30 +273,30 @@ public: | ||||
|     } | ||||
| 
 | ||||
|     Result InitializeWithNormalization(const char* path) { | ||||
|         /* Check the path is valid. */ | ||||
|         // Check the path is valid
 | ||||
|         R_UNLESS(path != nullptr, ResultNullptrArgument); | ||||
| 
 | ||||
|         R_RETURN(this->InitializeWithNormalization(path, std::strlen(path))); | ||||
|     } | ||||
| 
 | ||||
|     Result InitializeAsEmpty() { | ||||
|         /* Clear our buffer. */ | ||||
|         // Clear our buffer
 | ||||
|         this->ClearBuffer(); | ||||
| 
 | ||||
|         /* Set normalized. */ | ||||
|         // Set normalized
 | ||||
|         this->SetNormalized(); | ||||
| 
 | ||||
|         R_SUCCEED(); | ||||
|     } | ||||
| 
 | ||||
|     Result AppendChild(const char* child) { | ||||
|         /* Check the path is valid. */ | ||||
|         // Check the path is valid
 | ||||
|         R_UNLESS(child != nullptr, ResultNullptrArgument); | ||||
| 
 | ||||
|         /* Basic checks. If we hvea a path and the child is empty, we have nothing to do. */ | ||||
|         // Basic checks. If we have a path and the child is empty, we have nothing to do
 | ||||
|         const char* c = child; | ||||
|         if (m_str[0]) { | ||||
|             /* Skip an early separator. */ | ||||
|             // Skip an early separator
 | ||||
|             if (*c == '/') { | ||||
|                 ++c; | ||||
|             } | ||||
| @ -308,40 +304,40 @@ public: | ||||
|             R_SUCCEED_IF(*c == '\x00'); | ||||
|         } | ||||
| 
 | ||||
|         /* If we don't have a string, we can just initialize. */ | ||||
|         // If we don't have a string, we can just initialize
 | ||||
|         auto cur_len = std::strlen(m_str); | ||||
|         if (cur_len == 0) { | ||||
|             R_RETURN(this->Initialize(child)); | ||||
|         } | ||||
| 
 | ||||
|         /* Remove a trailing separator. */ | ||||
|         // Remove a trailing separator
 | ||||
|         if (m_str[cur_len - 1] == '/' || m_str[cur_len - 1] == '\\') { | ||||
|             --cur_len; | ||||
|         } | ||||
| 
 | ||||
|         /* Get the child path's length. */ | ||||
|         // Get the child path's length
 | ||||
|         auto child_len = std::strlen(c); | ||||
| 
 | ||||
|         /* Reset our write buffer. */ | ||||
|         // Reset our write buffer
 | ||||
|         WriteBuffer old_write_buffer; | ||||
|         if (m_write_buffer.Get() != nullptr) { | ||||
|             old_write_buffer = std::move(m_write_buffer); | ||||
|             this->ClearBuffer(); | ||||
|         } | ||||
| 
 | ||||
|         /* Pre-allocate the new buffer. */ | ||||
|         // Pre-allocate the new buffer
 | ||||
|         R_TRY(this->Preallocate(cur_len + 1 + child_len + 1)); | ||||
| 
 | ||||
|         /* Get our write buffer. */ | ||||
|         // Get our write buffer
 | ||||
|         auto* dst = m_write_buffer.Get(); | ||||
|         if (old_write_buffer.Get() != nullptr && cur_len > 0) { | ||||
|             Strlcpy<char>(dst, old_write_buffer.Get(), cur_len + 1); | ||||
|         } | ||||
| 
 | ||||
|         /* Add separator. */ | ||||
|         // Add separator
 | ||||
|         dst[cur_len] = '/'; | ||||
| 
 | ||||
|         /* Copy the child path. */ | ||||
|         // Copy the child path
 | ||||
|         const size_t copied = Strlcpy<char>(dst + cur_len + 1, c, child_len + 1); | ||||
|         R_UNLESS(copied == child_len, ResultUnexpectedInPathA); | ||||
| 
 | ||||
| @ -353,21 +349,21 @@ public: | ||||
|     } | ||||
| 
 | ||||
|     Result Combine(const Path& parent, const Path& child) { | ||||
|         /* Get the lengths. */ | ||||
|         // Get the lengths
 | ||||
|         const auto p_len = parent.GetLength(); | ||||
|         const auto c_len = child.GetLength(); | ||||
| 
 | ||||
|         /* Allocate our buffer. */ | ||||
|         // Allocate our buffer
 | ||||
|         R_TRY(this->Preallocate(p_len + c_len + 1)); | ||||
| 
 | ||||
|         /* Initialize as parent. */ | ||||
|         // Initialize as parent
 | ||||
|         R_TRY(this->Initialize(parent)); | ||||
| 
 | ||||
|         /* If we're empty, we can just initialize as child. */ | ||||
|         // If we're empty, we can just initialize as child
 | ||||
|         if (this->IsEmpty()) { | ||||
|             R_TRY(this->Initialize(child)); | ||||
|         } else { | ||||
|             /* Otherwise, we should append the child. */ | ||||
|             // Otherwise, we should append the child
 | ||||
|             R_TRY(this->AppendChild(child)); | ||||
|         } | ||||
| 
 | ||||
| @ -375,7 +371,7 @@ public: | ||||
|     } | ||||
| 
 | ||||
|     Result RemoveChild() { | ||||
|         /* If we don't have a write-buffer, ensure that we have one. */ | ||||
|         // If we don't have a write-buffer, ensure that we have one
 | ||||
|         if (m_write_buffer.Get() == nullptr) { | ||||
|             if (const auto len = std::strlen(m_str); len > 0) { | ||||
|                 R_TRY(this->Preallocate(len)); | ||||
| @ -383,17 +379,17 @@ public: | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /* Check that it's possible for us to remove a child. */ | ||||
|         // Check that it's possible for us to remove a child
 | ||||
|         auto* p = m_write_buffer.Get(); | ||||
|         s32 len = std::strlen(p); | ||||
|         R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), ResultNotImplemented); | ||||
| 
 | ||||
|         /* Handle a trailing separator. */ | ||||
|         // Handle a trailing separator
 | ||||
|         if (len > 0 && (p[len - 1] == '\\' || p[len - 1] == '/')) { | ||||
|             --len; | ||||
|         } | ||||
| 
 | ||||
|         /* Remove the child path segment. */ | ||||
|         // Remove the child path segment
 | ||||
|         while ((--len) >= 0 && p[len]) { | ||||
|             if (p[len] == '/' || p[len] == '\\') { | ||||
|                 if (len > 0) { | ||||
| @ -406,25 +402,25 @@ public: | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /* Check that length remains > 0. */ | ||||
|         // Check that length remains > 0
 | ||||
|         R_UNLESS(len > 0, ResultNotImplemented); | ||||
| 
 | ||||
|         R_SUCCEED(); | ||||
|     } | ||||
| 
 | ||||
|     Result Normalize(const PathFlags& flags) { | ||||
|         /* If we're already normalized, nothing to do. */ | ||||
|         // If we're already normalized, nothing to do
 | ||||
|         R_SUCCEED_IF(this->IsNormalized()); | ||||
| 
 | ||||
|         /* Check if we're normalized. */ | ||||
|         // Check if we're normalized
 | ||||
|         bool normalized; | ||||
|         size_t dummy; | ||||
|         R_TRY(PathFormatter::IsNormalized(std::addressof(normalized), std::addressof(dummy), m_str, | ||||
|                                           flags)); | ||||
| 
 | ||||
|         /* If we're not normalized, normalize. */ | ||||
|         // If we're not normalized, normalize
 | ||||
|         if (!normalized) { | ||||
|             /* Determine necessary buffer length. */ | ||||
|             // Determine necessary buffer length
 | ||||
|             auto len = m_write_buffer.GetLength(); | ||||
|             if (flags.IsRelativePathAllowed() && IsPathRelative(m_str)) { | ||||
|                 len += 2; | ||||
| @ -433,20 +429,20 @@ public: | ||||
|                 len += 1; | ||||
|             } | ||||
| 
 | ||||
|             /* Allocate a new buffer. */ | ||||
|             // Allocate a new buffer
 | ||||
|             const size_t size = Common::AlignUp(len, WriteBufferAlignmentLength); | ||||
|             auto buf = WriteBuffer::Make(size); | ||||
|             R_UNLESS(buf.Get() != nullptr, ResultAllocationMemoryFailedMakeUnique); | ||||
| 
 | ||||
|             /* Normalize into it. */ | ||||
|             // Normalize into it
 | ||||
|             R_TRY(PathFormatter::Normalize(buf.Get(), size, m_write_buffer.Get(), | ||||
|                                            m_write_buffer.GetLength(), flags)); | ||||
| 
 | ||||
|             /* Set the normalized buffer as our buffer. */ | ||||
|             // Set the normalized buffer as our buffer
 | ||||
|             this->SetModifiableBuffer(std::move(buf)); | ||||
|         } | ||||
| 
 | ||||
|         /* Set normalized. */ | ||||
|         // Set normalized
 | ||||
|         this->SetNormalized(); | ||||
|         R_SUCCEED(); | ||||
|     } | ||||
| @ -458,19 +454,19 @@ private: | ||||
|     } | ||||
| 
 | ||||
|     void SetModifiableBuffer(WriteBuffer&& buffer) { | ||||
|         /* Check pre-conditions. */ | ||||
|         // Check pre-conditions
 | ||||
|         ASSERT(buffer.Get() != nullptr); | ||||
|         ASSERT(buffer.GetLength() > 0); | ||||
|         ASSERT(Common::IsAligned(buffer.GetLength(), WriteBufferAlignmentLength)); | ||||
| 
 | ||||
|         /* Get whether we're normalized. */ | ||||
|         // Get whether we're normalized
 | ||||
|         if (m_write_buffer.IsNormalized()) { | ||||
|             buffer.SetNormalized(); | ||||
|         } else { | ||||
|             buffer.SetNotNormalized(); | ||||
|         } | ||||
| 
 | ||||
|         /* Set write buffer. */ | ||||
|         // Set write buffer
 | ||||
|         m_write_buffer = std::move(buffer); | ||||
|         m_str = m_write_buffer.Get(); | ||||
|     } | ||||
| @ -481,14 +477,14 @@ private: | ||||
|     } | ||||
| 
 | ||||
|     Result Preallocate(size_t length) { | ||||
|         /* Allocate additional space, if needed. */ | ||||
|         // Allocate additional space, if needed
 | ||||
|         if (length > m_write_buffer.GetLength()) { | ||||
|             /* Allocate buffer. */ | ||||
|             // Allocate buffer
 | ||||
|             const size_t size = Common::AlignUp(length, WriteBufferAlignmentLength); | ||||
|             auto buf = WriteBuffer::Make(size); | ||||
|             R_UNLESS(buf.Get() != nullptr, ResultAllocationMemoryFailedMakeUnique); | ||||
| 
 | ||||
|             /* Set write buffer. */ | ||||
|             // Set write buffer
 | ||||
|             this->SetModifiableBuffer(std::move(buf)); | ||||
|         } | ||||
| 
 | ||||
| @ -497,14 +493,14 @@ private: | ||||
| 
 | ||||
|     Result InitializeImpl(const char* path, size_t size) { | ||||
|         if (size > 0 && path[0]) { | ||||
|             /* Pre allocate a buffer for the path. */ | ||||
|             // Pre allocate a buffer for the path
 | ||||
|             R_TRY(this->Preallocate(size + 1)); | ||||
| 
 | ||||
|             /* Copy the path. */ | ||||
|             // Copy the path
 | ||||
|             const size_t copied = Strlcpy<char>(m_write_buffer.Get(), path, size + 1); | ||||
|             R_UNLESS(copied >= size, ResultUnexpectedInPathA); | ||||
|         } else { | ||||
|             /* We can just clear the buffer. */ | ||||
|             // We can just clear the buffer
 | ||||
|             this->ClearBuffer(); | ||||
|         } | ||||
| 
 | ||||
| @ -548,14 +544,14 @@ public: | ||||
| }; | ||||
| 
 | ||||
| inline Result SetUpFixedPath(FileSys::Path* out, const char* s) { | ||||
|     /* Verify the path is normalized. */ | ||||
|     // Verify the path is normalized
 | ||||
|     bool normalized; | ||||
|     size_t dummy; | ||||
|     R_TRY(PathNormalizer::IsNormalized(std::addressof(normalized), std::addressof(dummy), s)); | ||||
| 
 | ||||
|     R_UNLESS(normalized, ResultInvalidPathFormat); | ||||
| 
 | ||||
|     /* Set the fixed path. */ | ||||
|     // Set the fixed path
 | ||||
|     R_RETURN(out->SetShallowBuffer(s)); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,9 +1,10 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
 | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "common/assert.h" | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/common_types.h" | ||||
| #include "common/scope_exit.h" | ||||
| #include "core/file_sys/fs_directory.h" | ||||
| @ -14,7 +15,6 @@ | ||||
| namespace FileSys { | ||||
| 
 | ||||
| constexpr inline size_t MountNameLengthMax = 15; | ||||
| using Result = ::Result; | ||||
| 
 | ||||
| namespace StringTraits { | ||||
| 
 | ||||
| @ -57,15 +57,15 @@ constexpr bool IsInvalidCharacterImpl(char c) { | ||||
| } // namespace impl
 | ||||
| 
 | ||||
| constexpr bool IsInvalidCharacter(char c) { | ||||
|     return impl::IsInvalidCharacterImpl<InvalidCharacters, size(InvalidCharacters)>(c); | ||||
|     return impl::IsInvalidCharacterImpl<InvalidCharacters, Common::Size(InvalidCharacters)>(c); | ||||
| } | ||||
| constexpr bool IsInvalidCharacterForHostName(char c) { | ||||
|     return impl::IsInvalidCharacterImpl<InvalidCharactersForHostName, | ||||
|                                         size(InvalidCharactersForHostName)>(c); | ||||
|                                         Common::Size(InvalidCharactersForHostName)>(c); | ||||
| } | ||||
| constexpr bool IsInvalidCharacterForMountName(char c) { | ||||
|     return impl::IsInvalidCharacterImpl<InvalidCharactersForMountName, | ||||
|                                         size(InvalidCharactersForMountName)>(c); | ||||
|                                         Common::Size(InvalidCharactersForMountName)>(c); | ||||
| } | ||||
| 
 | ||||
| } // namespace StringTraits
 | ||||
| @ -177,14 +177,14 @@ constexpr inline bool IsPathStartWithCurrentDirectory(const char* path) { | ||||
| } | ||||
| 
 | ||||
| constexpr inline bool IsSubPath(const char* lhs, const char* rhs) { | ||||
|     /* Check pre-conditions. */ | ||||
|     // Check pre-conditions
 | ||||
|     ASSERT(lhs != nullptr); | ||||
|     ASSERT(rhs != nullptr); | ||||
| 
 | ||||
|     /* Import StringTraits names for current scope. */ | ||||
|     // Import StringTraits names for current scope
 | ||||
|     using namespace StringTraits; | ||||
| 
 | ||||
|     /* Special case certain paths. */ | ||||
|     // Special case certain paths
 | ||||
|     if (IsUncPath(lhs) && !IsUncPath(rhs)) { | ||||
|         return false; | ||||
|     } | ||||
| @ -201,7 +201,7 @@ constexpr inline bool IsSubPath(const char* lhs, const char* rhs) { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     /* Check subpath. */ | ||||
|     // Check subpath
 | ||||
|     for (size_t i = 0; /* ... */; ++i) { | ||||
|         if (lhs[i] == NullTerminator) { | ||||
|             return rhs[i] == DirectorySeparator; | ||||
| @ -213,7 +213,7 @@ constexpr inline bool IsSubPath(const char* lhs, const char* rhs) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* Path utilities. */ | ||||
| // Path utilities
 | ||||
| constexpr inline void Replace(char* dst, size_t dst_size, char old_char, char new_char) { | ||||
|     ASSERT(dst != nullptr); | ||||
|     for (char* cur = dst; cur < dst + dst_size && *cur; ++cur) { | ||||
| @ -224,10 +224,10 @@ constexpr inline void Replace(char* dst, size_t dst_size, char old_char, char ne | ||||
| } | ||||
| 
 | ||||
| constexpr inline Result CheckUtf8(const char* s) { | ||||
|     /* Check pre-conditions. */ | ||||
|     // Check pre-conditions
 | ||||
|     ASSERT(s != nullptr); | ||||
| 
 | ||||
|     /* Iterate, checking for utf8-validity. */ | ||||
|     // Iterate, checking for utf8-validity
 | ||||
|     while (*s) { | ||||
|         char utf8_buf[4] = {}; | ||||
| 
 | ||||
| @ -242,7 +242,7 @@ constexpr inline Result CheckUtf8(const char* s) { | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| /* Path formatting. */ | ||||
| // Path formatting
 | ||||
| class PathNormalizer { | ||||
| private: | ||||
|     enum class PathState { | ||||
| @ -256,10 +256,10 @@ private: | ||||
| 
 | ||||
| private: | ||||
|     static constexpr void ReplaceParentDirectoryPath(char* dst, const char* src) { | ||||
|         /* Use StringTraits names for remainder of scope. */ | ||||
|         // Use StringTraits names for remainder of scope
 | ||||
|         using namespace StringTraits; | ||||
| 
 | ||||
|         /* Start with a dir-separator. */ | ||||
|         // Start with a dir-separator
 | ||||
|         dst[0] = DirectorySeparator; | ||||
| 
 | ||||
|         auto i = 1; | ||||
| @ -292,14 +292,14 @@ private: | ||||
| 
 | ||||
| public: | ||||
|     static constexpr bool IsParentDirectoryPathReplacementNeeded(const char* path) { | ||||
|         /* Use StringTraits names for remainder of scope. */ | ||||
|         // Use StringTraits names for remainder of scope
 | ||||
|         using namespace StringTraits; | ||||
| 
 | ||||
|         if (path[0] != DirectorySeparator && path[0] != AlternateDirectorySeparator) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         /* Check to find a parent reference using alternate separators. */ | ||||
|         // Check to find a parent reference using alternate separators
 | ||||
|         if (path[0] != NullTerminator && path[1] != NullTerminator && path[2] != NullTerminator) { | ||||
|             size_t i; | ||||
|             for (i = 0; path[i + 3] != NullTerminator; ++path) { | ||||
| @ -333,24 +333,24 @@ public: | ||||
| 
 | ||||
|     static constexpr Result IsNormalized(bool* out, size_t* out_len, const char* path, | ||||
|                                          bool allow_all_characters = false) { | ||||
|         /* Use StringTraits names for remainder of scope. */ | ||||
|         // Use StringTraits names for remainder of scope
 | ||||
|         using namespace StringTraits; | ||||
| 
 | ||||
|         /* Parse the path. */ | ||||
|         // Parse the path
 | ||||
|         auto state = PathState::Start; | ||||
|         size_t len = 0; | ||||
|         while (path[len] != NullTerminator) { | ||||
|             /* Get the current character. */ | ||||
|             // Get the current character
 | ||||
|             const char c = path[len++]; | ||||
| 
 | ||||
|             /* Check the current character is valid. */ | ||||
|             // Check the current character is valid
 | ||||
|             if (!allow_all_characters && state != PathState::Start) { | ||||
|                 R_UNLESS(!IsInvalidCharacter(c), ResultInvalidCharacter); | ||||
|             } | ||||
| 
 | ||||
|             /* Process depending on current state. */ | ||||
|             // Process depending on current state
 | ||||
|             switch (state) { | ||||
|                 /* Import the PathState enums for convenience. */ | ||||
|                 // Import the PathState enums for convenience
 | ||||
|                 using enum PathState; | ||||
| 
 | ||||
|             case Start: | ||||
| @ -401,9 +401,9 @@ public: | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /* Check the final state. */ | ||||
|         // Check the final state
 | ||||
|         switch (state) { | ||||
|             /* Import the PathState enums for convenience. */ | ||||
|             // Import the PathState enums for convenience
 | ||||
|             using enum PathState; | ||||
|         case Start: | ||||
|             R_THROW(ResultInvalidPathFormat); | ||||
| @ -421,7 +421,7 @@ public: | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         /* Set the output length. */ | ||||
|         // Set the output length
 | ||||
|         *out_len = len; | ||||
|         R_SUCCEED(); | ||||
|     } | ||||
| @ -429,21 +429,21 @@ public: | ||||
|     static Result Normalize(char* dst, size_t* out_len, const char* path, size_t max_out_size, | ||||
|                             bool is_windows_path, bool is_drive_relative_path, | ||||
|                             bool allow_all_characters = false) { | ||||
|         /* Use StringTraits names for remainder of scope. */ | ||||
|         // Use StringTraits names for remainder of scope
 | ||||
|         using namespace StringTraits; | ||||
| 
 | ||||
|         /* Prepare to iterate. */ | ||||
|         // Prepare to iterate
 | ||||
|         const char* cur_path = path; | ||||
|         size_t total_len = 0; | ||||
| 
 | ||||
|         /* If path begins with a separator, check that we're not drive relative. */ | ||||
|         // If path begins with a separator, check that we're not drive relative
 | ||||
|         if (cur_path[0] != DirectorySeparator) { | ||||
|             R_UNLESS(is_drive_relative_path, ResultInvalidPathFormat); | ||||
| 
 | ||||
|             dst[total_len++] = DirectorySeparator; | ||||
|         } | ||||
| 
 | ||||
|         /* We're going to need to do path replacement, potentially. */ | ||||
|         // We're going to need to do path replacement, potentially
 | ||||
|         char* replacement_path = nullptr; | ||||
|         size_t replacement_path_size = 0; | ||||
| 
 | ||||
| @ -457,7 +457,7 @@ public: | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         /* Perform path replacement, if necessary. */ | ||||
|         // Perform path replacement, if necessary
 | ||||
|         if (IsParentDirectoryPathReplacementNeeded(cur_path)) { | ||||
|             if (std::is_constant_evaluated()) { | ||||
|                 replacement_path_size = EntryNameLengthMax + 1; | ||||
| @ -472,25 +472,24 @@ public: | ||||
|             cur_path = replacement_path; | ||||
|         } | ||||
| 
 | ||||
|         /* Iterate, normalizing path components. */ | ||||
|         // Iterate, normalizing path components
 | ||||
|         bool skip_next_sep = false; | ||||
|         size_t i = 0; | ||||
| 
 | ||||
|         while (cur_path[i] != NullTerminator) { | ||||
|             /* Process a directory separator, if we run into one. */ | ||||
|             // Process a directory separator, if we run into one
 | ||||
|             if (cur_path[i] == DirectorySeparator) { | ||||
|                 /* Swallow separators. */ | ||||
|                 // Swallow separators
 | ||||
|                 do { | ||||
|                     ++i; | ||||
|                 } while (cur_path[i] == DirectorySeparator); | ||||
| 
 | ||||
|                 /* Check if we hit end of string. */ | ||||
|                 // Check if we hit end of string
 | ||||
|                 if (cur_path[i] == NullTerminator) { | ||||
|                     break; | ||||
|                 } | ||||
| 
 | ||||
|                 /* If we aren't skipping the separator, write it, checking that we remain in bounds.
 | ||||
|                  */ | ||||
|                 // If we aren't skipping the separator, write it, checking that we remain in bounds.
 | ||||
|                 if (!skip_next_sep) { | ||||
|                     if (total_len + 1 == max_out_size) { | ||||
|                         dst[total_len] = NullTerminator; | ||||
| @ -501,15 +500,15 @@ public: | ||||
|                     dst[total_len++] = DirectorySeparator; | ||||
|                 } | ||||
| 
 | ||||
|                 /* Don't skip the next separator. */ | ||||
|                 // Don't skip the next separator
 | ||||
|                 skip_next_sep = false; | ||||
|             } | ||||
| 
 | ||||
|             /* Get the length of the current directory component. */ | ||||
|             // Get the length of the current directory component
 | ||||
|             size_t dir_len = 0; | ||||
|             while (cur_path[i + dir_len] != DirectorySeparator && | ||||
|                    cur_path[i + dir_len] != NullTerminator) { | ||||
|                 /* Check for validity. */ | ||||
|                 // Check for validity
 | ||||
|                 if (!allow_all_characters) { | ||||
|                     R_UNLESS(!IsInvalidCharacter(cur_path[i + dir_len]), ResultInvalidCharacter); | ||||
|                 } | ||||
| @ -517,19 +516,19 @@ public: | ||||
|                 ++dir_len; | ||||
|             } | ||||
| 
 | ||||
|             /* Handle the current dir component. */ | ||||
|             // Handle the current dir component
 | ||||
|             if (IsCurrentDirectory(cur_path + i)) { | ||||
|                 skip_next_sep = true; | ||||
|             } else if (IsParentDirectory(cur_path + i)) { | ||||
|                 /* We should have just written a separator. */ | ||||
|                 // We should have just written a separator
 | ||||
|                 ASSERT(dst[total_len - 1] == DirectorySeparator); | ||||
| 
 | ||||
|                 /* We should have started with a separator, for non-windows paths. */ | ||||
|                 // We should have started with a separator, for non-windows paths
 | ||||
|                 if (!is_windows_path) { | ||||
|                     ASSERT(dst[0] == DirectorySeparator); | ||||
|                 } | ||||
| 
 | ||||
|                 /* Remove the previous component. */ | ||||
|                 // Remove the previous component
 | ||||
|                 if (total_len == 1) { | ||||
|                     R_UNLESS(is_windows_path, ResultDirectoryUnobtainable); | ||||
| 
 | ||||
| @ -544,15 +543,15 @@ public: | ||||
|                     } while ((--total_len) != 0); | ||||
|                 } | ||||
| 
 | ||||
|                 /* We should be pointing to a directory separator, for non-windows paths. */ | ||||
|                 // We should be pointing to a directory separator, for non-windows paths
 | ||||
|                 if (!is_windows_path) { | ||||
|                     ASSERT(dst[total_len] == DirectorySeparator); | ||||
|                 } | ||||
| 
 | ||||
|                 /* We should remain in bounds. */ | ||||
|                 // We should remain in bounds
 | ||||
|                 ASSERT(total_len < max_out_size); | ||||
|             } else { | ||||
|                 /* Copy, possibly truncating. */ | ||||
|                 // Copy, possibly truncating
 | ||||
|                 if (total_len + dir_len + 1 > max_out_size) { | ||||
|                     const size_t copy_len = max_out_size - (total_len + 1); | ||||
| 
 | ||||
| @ -570,7 +569,7 @@ public: | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             /* Advance past the current directory component. */ | ||||
|             // Advance past the current directory component
 | ||||
|             i += dir_len; | ||||
|         } | ||||
| 
 | ||||
| @ -583,22 +582,22 @@ public: | ||||
|             dst[0] = DirectorySeparator; | ||||
|         } | ||||
| 
 | ||||
|         /* NOTE: Probable nintendo bug, as max_out_size must be at least total_len + 1 for the null
 | ||||
|          * terminator. */ | ||||
|         // NOTE: Probable nintendo bug, as max_out_size must be at least total_len + 1 for the null
 | ||||
|         // terminator.
 | ||||
|         R_UNLESS(max_out_size >= total_len - 1, ResultTooLongPath); | ||||
| 
 | ||||
|         dst[total_len] = NullTerminator; | ||||
| 
 | ||||
|         /* Check that the result path is normalized. */ | ||||
|         // Check that the result path is normalized
 | ||||
|         bool is_normalized; | ||||
|         size_t dummy; | ||||
|         R_TRY(IsNormalized(std::addressof(is_normalized), std::addressof(dummy), dst, | ||||
|                            allow_all_characters)); | ||||
| 
 | ||||
|         /* Assert that the result path is normalized. */ | ||||
|         // Assert that the result path is normalized
 | ||||
|         ASSERT(is_normalized); | ||||
| 
 | ||||
|         /* Set the output length. */ | ||||
|         // Set the output length
 | ||||
|         *out_len = total_len; | ||||
|         R_SUCCEED(); | ||||
|     } | ||||
| @ -607,7 +606,7 @@ public: | ||||
| class PathFormatter { | ||||
| private: | ||||
|     static constexpr Result CheckSharedName(const char* name, size_t len) { | ||||
|         /* Use StringTraits names for remainder of scope. */ | ||||
|         // Use StringTraits names for remainder of scope
 | ||||
|         using namespace StringTraits; | ||||
| 
 | ||||
|         if (len == 1) { | ||||
| @ -624,7 +623,7 @@ private: | ||||
|     } | ||||
| 
 | ||||
|     static constexpr Result CheckHostName(const char* name, size_t len) { | ||||
|         /* Use StringTraits names for remainder of scope. */ | ||||
|         // Use StringTraits names for remainder of scope
 | ||||
|         using namespace StringTraits; | ||||
| 
 | ||||
|         if (len == 2) { | ||||
| @ -640,10 +639,10 @@ private: | ||||
| 
 | ||||
|     static constexpr Result CheckInvalidBackslash(bool* out_contains_backslash, const char* path, | ||||
|                                                   bool allow_backslash) { | ||||
|         /* Use StringTraits names for remainder of scope. */ | ||||
|         // Use StringTraits names for remainder of scope
 | ||||
|         using namespace StringTraits; | ||||
| 
 | ||||
|         /* Default to no backslashes, so we can just write if we see one. */ | ||||
|         // Default to no backslashes, so we can just write if we see one
 | ||||
|         *out_contains_backslash = false; | ||||
| 
 | ||||
|         while (*path != NullTerminator) { | ||||
| @ -670,34 +669,34 @@ public: | ||||
| 
 | ||||
|     static constexpr Result ParseMountName(const char** out, size_t* out_len, char* out_mount_name, | ||||
|                                            size_t out_mount_name_buffer_size, const char* path) { | ||||
|         /* Check pre-conditions. */ | ||||
|         // Check pre-conditions
 | ||||
|         ASSERT(path != nullptr); | ||||
|         ASSERT(out_len != nullptr); | ||||
|         ASSERT(out != nullptr); | ||||
|         ASSERT((out_mount_name == nullptr) == (out_mount_name_buffer_size == 0)); | ||||
| 
 | ||||
|         /* Use StringTraits names for remainder of scope. */ | ||||
|         // Use StringTraits names for remainder of scope
 | ||||
|         using namespace StringTraits; | ||||
| 
 | ||||
|         /* Determine max mount length. */ | ||||
|         // Determine max mount length
 | ||||
|         const auto max_mount_len = | ||||
|             out_mount_name_buffer_size == 0 | ||||
|                 ? MountNameLengthMax + 1 | ||||
|                 : std::min(MountNameLengthMax + 1, out_mount_name_buffer_size); | ||||
| 
 | ||||
|         /* Parse the path until we see a drive separator. */ | ||||
|         // Parse the path until we see a drive separator
 | ||||
|         size_t mount_len = 0; | ||||
|         for (/* ... */; mount_len < max_mount_len && path[mount_len]; ++mount_len) { | ||||
|             const char c = path[mount_len]; | ||||
| 
 | ||||
|             /* If we see a drive separator, advance, then we're done with the pre-drive separator
 | ||||
|              * part of the mount. */ | ||||
|             // If we see a drive separator, advance, then we're done with the pre-drive separator
 | ||||
|             // part of the mount.
 | ||||
|             if (c == DriveSeparator) { | ||||
|                 ++mount_len; | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|             /* If we see a directory separator, we're not in a mount name. */ | ||||
|             // If we see a directory separator, we're not in a mount name
 | ||||
|             if (c == DirectorySeparator || c == AlternateDirectorySeparator) { | ||||
|                 *out = path; | ||||
|                 *out_len = 0; | ||||
| @ -705,19 +704,19 @@ public: | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /* Check to be sure we're actually looking at a mount name. */ | ||||
|         // Check to be sure we're actually looking at a mount name
 | ||||
|         if (mount_len <= 2 || path[mount_len - 1] != DriveSeparator) { | ||||
|             *out = path; | ||||
|             *out_len = 0; | ||||
|             R_SUCCEED(); | ||||
|         } | ||||
| 
 | ||||
|         /* Check that all characters in the mount name are allowable. */ | ||||
|         // Check that all characters in the mount name are allowable
 | ||||
|         for (size_t i = 0; i < mount_len; ++i) { | ||||
|             R_UNLESS(!IsInvalidCharacterForMountName(path[i]), ResultInvalidCharacter); | ||||
|         } | ||||
| 
 | ||||
|         /* Copy out the mount name. */ | ||||
|         // Copy out the mount name
 | ||||
|         if (out_mount_name_buffer_size > 0) { | ||||
|             R_UNLESS(mount_len < out_mount_name_buffer_size, ResultTooLongPath); | ||||
| 
 | ||||
| @ -727,7 +726,7 @@ public: | ||||
|             out_mount_name[mount_len] = NullTerminator; | ||||
|         } | ||||
| 
 | ||||
|         /* Set the output. */ | ||||
|         // Set the output
 | ||||
|         *out = path + mount_len; | ||||
|         *out_len = mount_len; | ||||
|         R_SUCCEED(); | ||||
| @ -742,21 +741,21 @@ public: | ||||
|                                                  char* out_relative, | ||||
|                                                  size_t out_relative_buffer_size, | ||||
|                                                  const char* path) { | ||||
|         /* Check pre-conditions. */ | ||||
|         // Check pre-conditions
 | ||||
|         ASSERT(path != nullptr); | ||||
|         ASSERT(out_len != nullptr); | ||||
|         ASSERT(out != nullptr); | ||||
|         ASSERT((out_relative == nullptr) == (out_relative_buffer_size == 0)); | ||||
| 
 | ||||
|         /* Use StringTraits names for remainder of scope. */ | ||||
|         // Use StringTraits names for remainder of scope
 | ||||
|         using namespace StringTraits; | ||||
| 
 | ||||
|         /* Initialize the output buffer, if we have one. */ | ||||
|         // Initialize the output buffer, if we have one
 | ||||
|         if (out_relative_buffer_size > 0) { | ||||
|             out_relative[0] = NullTerminator; | ||||
|         } | ||||
| 
 | ||||
|         /* Check if the path is relative. */ | ||||
|         // Check if the path is relative
 | ||||
|         if (path[0] == Dot && (path[1] == NullTerminator || path[1] == DirectorySeparator || | ||||
|                                path[1] == AlternateDirectorySeparator)) { | ||||
|             if (out_relative_buffer_size > 0) { | ||||
| @ -771,10 +770,10 @@ public: | ||||
|             R_SUCCEED(); | ||||
|         } | ||||
| 
 | ||||
|         /* Ensure the path isn't a parent directory. */ | ||||
|         // Ensure the path isn't a parent directory
 | ||||
|         R_UNLESS(!(path[0] == Dot && path[1] == Dot), ResultDirectoryUnobtainable); | ||||
| 
 | ||||
|         /* There was no relative dot path. */ | ||||
|         // There was no relative dot path
 | ||||
|         *out = path; | ||||
|         *out_len = 0; | ||||
|         R_SUCCEED(); | ||||
| @ -782,7 +781,7 @@ public: | ||||
| 
 | ||||
|     static constexpr Result SkipWindowsPath(const char** out, size_t* out_len, bool* out_normalized, | ||||
|                                             const char* path, bool has_mount_name) { | ||||
|         /* We're normalized if and only if the parsing doesn't throw ResultNotNormalized(). */ | ||||
|         // We're normalized if and only if the parsing doesn't throw ResultNotNormalized()
 | ||||
|         *out_normalized = true; | ||||
| 
 | ||||
|         R_TRY_CATCH(ParseWindowsPath(out, out_len, nullptr, 0, path, has_mount_name)) { | ||||
| @ -801,21 +800,21 @@ public: | ||||
|     static constexpr Result ParseWindowsPath(const char** out, size_t* out_len, char* out_win, | ||||
|                                              size_t out_win_buffer_size, const char* path, | ||||
|                                              bool has_mount_name) { | ||||
|         /* Check pre-conditions. */ | ||||
|         // Check pre-conditions
 | ||||
|         ASSERT(path != nullptr); | ||||
|         ASSERT(out_len != nullptr); | ||||
|         ASSERT(out != nullptr); | ||||
|         ASSERT((out_win == nullptr) == (out_win_buffer_size == 0)); | ||||
| 
 | ||||
|         /* Use StringTraits names for remainder of scope. */ | ||||
|         // Use StringTraits names for remainder of scope
 | ||||
|         using namespace StringTraits; | ||||
| 
 | ||||
|         /* Initialize the output buffer, if we have one. */ | ||||
|         // Initialize the output buffer, if we have one
 | ||||
|         if (out_win_buffer_size > 0) { | ||||
|             out_win[0] = NullTerminator; | ||||
|         } | ||||
| 
 | ||||
|         /* Handle path start. */ | ||||
|         // Handle path start
 | ||||
|         const char* cur_path = path; | ||||
|         if (has_mount_name && path[0] == DirectorySeparator) { | ||||
|             if (path[1] == AlternateDirectorySeparator && path[2] == AlternateDirectorySeparator) { | ||||
| @ -829,9 +828,9 @@ public: | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /* Handle windows drive. */ | ||||
|         // Handle windows drive
 | ||||
|         if (IsWindowsDrive(cur_path)) { | ||||
|             /* Parse up to separator. */ | ||||
|             // Parse up to separator
 | ||||
|             size_t win_path_len = WindowsDriveLength; | ||||
|             for (/* ... */; cur_path[win_path_len] != NullTerminator; ++win_path_len) { | ||||
|                 R_UNLESS(!IsInvalidCharacter(cur_path[win_path_len]), ResultInvalidCharacter); | ||||
| @ -842,13 +841,13 @@ public: | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             /* Ensure that we're normalized, if we're required to be. */ | ||||
|             // Ensure that we're normalized, if we're required to be
 | ||||
|             if (out_win_buffer_size == 0) { | ||||
|                 for (size_t i = 0; i < win_path_len; ++i) { | ||||
|                     R_UNLESS(cur_path[i] != AlternateDirectorySeparator, ResultNotNormalized); | ||||
|                 } | ||||
|             } else { | ||||
|                 /* Ensure we can copy into the normalized buffer. */ | ||||
|                 // Ensure we can copy into the normalized buffer
 | ||||
|                 R_UNLESS(win_path_len < out_win_buffer_size, ResultTooLongPath); | ||||
| 
 | ||||
|                 for (size_t i = 0; i < win_path_len; ++i) { | ||||
| @ -864,7 +863,7 @@ public: | ||||
|             R_SUCCEED(); | ||||
|         } | ||||
| 
 | ||||
|         /* Handle DOS device. */ | ||||
|         // Handle DOS device
 | ||||
|         if (IsDosDevicePath(cur_path)) { | ||||
|             size_t dos_prefix_len = DosDevicePathPrefixLength; | ||||
| 
 | ||||
| @ -875,7 +874,7 @@ public: | ||||
|             } | ||||
| 
 | ||||
|             if (out_win_buffer_size > 0) { | ||||
|                 /* Ensure we can copy into the normalized buffer. */ | ||||
|                 // Ensure we can copy into the normalized buffer
 | ||||
|                 R_UNLESS(dos_prefix_len < out_win_buffer_size, ResultTooLongPath); | ||||
| 
 | ||||
|                 for (size_t i = 0; i < dos_prefix_len; ++i) { | ||||
| @ -891,7 +890,7 @@ public: | ||||
|             R_SUCCEED(); | ||||
|         } | ||||
| 
 | ||||
|         /* Handle UNC path. */ | ||||
|         // Handle UNC path
 | ||||
|         if (IsUncPath(cur_path, false, true)) { | ||||
|             const char* final_path = cur_path; | ||||
| 
 | ||||
| @ -932,13 +931,13 @@ public: | ||||
| 
 | ||||
|             size_t unc_prefix_len = final_path - cur_path; | ||||
| 
 | ||||
|             /* Ensure that we're normalized, if we're required to be. */ | ||||
|             // Ensure that we're normalized, if we're required to be
 | ||||
|             if (out_win_buffer_size == 0) { | ||||
|                 for (size_t i = 0; i < unc_prefix_len; ++i) { | ||||
|                     R_UNLESS(cur_path[i] != DirectorySeparator, ResultNotNormalized); | ||||
|                 } | ||||
|             } else { | ||||
|                 /* Ensure we can copy into the normalized buffer. */ | ||||
|                 // Ensure we can copy into the normalized buffer
 | ||||
|                 R_UNLESS(unc_prefix_len < out_win_buffer_size, ResultTooLongPath); | ||||
| 
 | ||||
|                 for (size_t i = 0; i < unc_prefix_len; ++i) { | ||||
| @ -954,7 +953,7 @@ public: | ||||
|             R_SUCCEED(); | ||||
|         } | ||||
| 
 | ||||
|         /* There's no windows path to parse. */ | ||||
|         // There's no windows path to parse
 | ||||
|         *out = path; | ||||
|         *out_len = 0; | ||||
|         R_SUCCEED(); | ||||
| @ -962,18 +961,18 @@ public: | ||||
| 
 | ||||
|     static constexpr Result IsNormalized(bool* out, size_t* out_len, const char* path, | ||||
|                                          const PathFlags& flags = {}) { | ||||
|         /* Ensure nothing is null. */ | ||||
|         // Ensure nothing is null
 | ||||
|         R_UNLESS(out != nullptr, ResultNullptrArgument); | ||||
|         R_UNLESS(out_len != nullptr, ResultNullptrArgument); | ||||
|         R_UNLESS(path != nullptr, ResultNullptrArgument); | ||||
| 
 | ||||
|         /* Verify that the path is valid utf-8. */ | ||||
|         // Verify that the path is valid utf-8
 | ||||
|         R_TRY(CheckUtf8(path)); | ||||
| 
 | ||||
|         /* Use StringTraits names for remainder of scope. */ | ||||
|         // Use StringTraits names for remainder of scope
 | ||||
|         using namespace StringTraits; | ||||
| 
 | ||||
|         /* Handle the case where the path is empty. */ | ||||
|         // Handle the case where the path is empty
 | ||||
|         if (path[0] == NullTerminator) { | ||||
|             R_UNLESS(flags.IsEmptyPathAllowed(), ResultInvalidPathFormat); | ||||
| 
 | ||||
| @ -982,32 +981,32 @@ public: | ||||
|             R_SUCCEED(); | ||||
|         } | ||||
| 
 | ||||
|         /* All normalized paths start with a directory separator...unless they're windows paths,
 | ||||
|          * relative paths, or have mount names. */ | ||||
|         // All normalized paths start with a directory separator...unless they're windows paths,
 | ||||
|         // relative paths, or have mount names.
 | ||||
|         if (path[0] != DirectorySeparator) { | ||||
|             R_UNLESS(flags.IsWindowsPathAllowed() || flags.IsRelativePathAllowed() || | ||||
|                          flags.IsMountNameAllowed(), | ||||
|                      ResultInvalidPathFormat); | ||||
|         } | ||||
| 
 | ||||
|         /* Check that the path is allowed to be a windows path, if it is. */ | ||||
|         // Check that the path is allowed to be a windows path, if it is
 | ||||
|         if (IsWindowsPath(path, false)) { | ||||
|             R_UNLESS(flags.IsWindowsPathAllowed(), ResultInvalidPathFormat); | ||||
|         } | ||||
| 
 | ||||
|         /* Skip past the mount name, if one is present. */ | ||||
|         // Skip past the mount name, if one is present
 | ||||
|         size_t total_len = 0; | ||||
|         size_t mount_name_len = 0; | ||||
|         R_TRY(SkipMountName(std::addressof(path), std::addressof(mount_name_len), path)); | ||||
| 
 | ||||
|         /* If we had a mount name, check that that was allowed. */ | ||||
|         // If we had a mount name, check that that was allowed
 | ||||
|         if (mount_name_len > 0) { | ||||
|             R_UNLESS(flags.IsMountNameAllowed(), ResultInvalidPathFormat); | ||||
| 
 | ||||
|             total_len += mount_name_len; | ||||
|         } | ||||
| 
 | ||||
|         /* Check that the path starts as a normalized path should. */ | ||||
|         // Check that the path starts as a normalized path should
 | ||||
|         if (path[0] != DirectorySeparator && !IsPathStartWithCurrentDirectory(path) && | ||||
|             !IsWindowsPath(path, false)) { | ||||
|             R_UNLESS(flags.IsRelativePathAllowed(), ResultInvalidPathFormat); | ||||
| @ -1017,11 +1016,11 @@ public: | ||||
|             R_SUCCEED(); | ||||
|         } | ||||
| 
 | ||||
|         /* Process relative path. */ | ||||
|         // Process relative path
 | ||||
|         size_t relative_len = 0; | ||||
|         R_TRY(SkipRelativeDotPath(std::addressof(path), std::addressof(relative_len), path)); | ||||
| 
 | ||||
|         /* If we have a relative path, check that was allowed. */ | ||||
|         // If we have a relative path, check that was allowed
 | ||||
|         if (relative_len > 0) { | ||||
|             R_UNLESS(flags.IsRelativePathAllowed(), ResultInvalidPathFormat); | ||||
| 
 | ||||
| @ -1034,13 +1033,13 @@ public: | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /* Process windows path. */ | ||||
|         // Process windows path
 | ||||
|         size_t windows_len = 0; | ||||
|         bool normalized_win = false; | ||||
|         R_TRY(SkipWindowsPath(std::addressof(path), std::addressof(windows_len), | ||||
|                               std::addressof(normalized_win), path, mount_name_len > 0)); | ||||
| 
 | ||||
|         /* If the windows path wasn't normalized, we're not normalized. */ | ||||
|         // If the windows path wasn't normalized, we're not normalized
 | ||||
|         if (!normalized_win) { | ||||
|             R_UNLESS(flags.IsWindowsPathAllowed(), ResultInvalidPathFormat); | ||||
| 
 | ||||
| @ -1048,22 +1047,22 @@ public: | ||||
|             R_SUCCEED(); | ||||
|         } | ||||
| 
 | ||||
|         /* If we had a windows path, check that was allowed. */ | ||||
|         // If we had a windows path, check that was allowed
 | ||||
|         if (windows_len > 0) { | ||||
|             R_UNLESS(flags.IsWindowsPathAllowed(), ResultInvalidPathFormat); | ||||
| 
 | ||||
|             total_len += windows_len; | ||||
| 
 | ||||
|             /* We can't have both a relative path and a windows path. */ | ||||
|             // We can't have both a relative path and a windows path
 | ||||
|             R_UNLESS(relative_len == 0, ResultInvalidPathFormat); | ||||
| 
 | ||||
|             /* A path ending in a windows path isn't normalized. */ | ||||
|             // A path ending in a windows path isn't normalized
 | ||||
|             if (path[0] == NullTerminator) { | ||||
|                 *out = false; | ||||
|                 R_SUCCEED(); | ||||
|             } | ||||
| 
 | ||||
|             /* Check that there are no windows directory separators in the path. */ | ||||
|             // Check that there are no windows directory separators in the path
 | ||||
|             for (size_t i = 0; path[i] != NullTerminator; ++i) { | ||||
|                 if (path[i] == AlternateDirectorySeparator) { | ||||
|                     *out = false; | ||||
| @ -1072,48 +1071,48 @@ public: | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /* Check that parent directory replacement is not needed if backslashes are allowed. */ | ||||
|         // Check that parent directory replacement is not needed if backslashes are allowed
 | ||||
|         if (flags.IsBackslashAllowed() && | ||||
|             PathNormalizer::IsParentDirectoryPathReplacementNeeded(path)) { | ||||
|             *out = false; | ||||
|             R_SUCCEED(); | ||||
|         } | ||||
| 
 | ||||
|         /* Check that the backslash state is valid. */ | ||||
|         // Check that the backslash state is valid
 | ||||
|         bool is_backslash_contained = false; | ||||
|         R_TRY(CheckInvalidBackslash(std::addressof(is_backslash_contained), path, | ||||
|                                     flags.IsWindowsPathAllowed() || flags.IsBackslashAllowed())); | ||||
| 
 | ||||
|         /* Check that backslashes are contained only if allowed. */ | ||||
|         // Check that backslashes are contained only if allowed
 | ||||
|         if (is_backslash_contained && !flags.IsBackslashAllowed()) { | ||||
|             *out = false; | ||||
|             R_SUCCEED(); | ||||
|         } | ||||
| 
 | ||||
|         /* Check that the final result path is normalized. */ | ||||
|         // Check that the final result path is normalized
 | ||||
|         size_t normal_len = 0; | ||||
|         R_TRY(PathNormalizer::IsNormalized(out, std::addressof(normal_len), path, | ||||
|                                            flags.IsAllCharactersAllowed())); | ||||
| 
 | ||||
|         /* Add the normal length. */ | ||||
|         // Add the normal length
 | ||||
|         total_len += normal_len; | ||||
| 
 | ||||
|         /* Set the output length. */ | ||||
|         // Set the output length
 | ||||
|         *out_len = total_len; | ||||
|         R_SUCCEED(); | ||||
|     } | ||||
| 
 | ||||
|     static Result Normalize(char* dst, size_t dst_size, const char* path, size_t path_len, | ||||
|                             const PathFlags& flags) { | ||||
|         /* Use StringTraits names for remainder of scope. */ | ||||
|         // Use StringTraits names for remainder of scope
 | ||||
|         using namespace StringTraits; | ||||
| 
 | ||||
|         /* Prepare to iterate. */ | ||||
|         // Prepare to iterate
 | ||||
|         const char* src = path; | ||||
|         size_t cur_pos = 0; | ||||
|         bool is_windows_path = false; | ||||
| 
 | ||||
|         /* Check if the path is empty. */ | ||||
|         // Check if the path is empty
 | ||||
|         if (src[0] == NullTerminator) { | ||||
|             if (dst_size != 0) { | ||||
|                 dst[0] = NullTerminator; | ||||
| @ -1124,7 +1123,7 @@ public: | ||||
|             R_SUCCEED(); | ||||
|         } | ||||
| 
 | ||||
|         /* Handle a mount name. */ | ||||
|         // Handle a mount name
 | ||||
|         size_t mount_name_len = 0; | ||||
|         if (flags.IsMountNameAllowed()) { | ||||
|             R_TRY(ParseMountName(std::addressof(src), std::addressof(mount_name_len), dst + cur_pos, | ||||
| @ -1133,7 +1132,7 @@ public: | ||||
|             cur_pos += mount_name_len; | ||||
|         } | ||||
| 
 | ||||
|         /* Handle a drive-relative prefix. */ | ||||
|         // Handle a drive-relative prefix
 | ||||
|         bool is_drive_relative = false; | ||||
|         if (src[0] != DirectorySeparator && !IsPathStartWithCurrentDirectory(src) && | ||||
|             !IsWindowsPath(src, false)) { | ||||
| @ -1161,7 +1160,7 @@ public: | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /* Handle a windows path. */ | ||||
|         // Handle a windows path
 | ||||
|         if (flags.IsWindowsPathAllowed()) { | ||||
|             const char* const orig = src; | ||||
| 
 | ||||
| @ -1187,16 +1186,16 @@ public: | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /* Check for invalid backslash. */ | ||||
|         // Check for invalid backslash
 | ||||
|         bool backslash_contained = false; | ||||
|         R_TRY(CheckInvalidBackslash(std::addressof(backslash_contained), src, | ||||
|                                     flags.IsWindowsPathAllowed() || flags.IsBackslashAllowed())); | ||||
| 
 | ||||
|         /* Handle backslash replacement as necessary. */ | ||||
|         // Handle backslash replacement as necessary
 | ||||
|         if (backslash_contained && flags.IsWindowsPathAllowed()) { | ||||
|             /* Create a temporary buffer holding a slash-replaced version of the path. */ | ||||
|             /* NOTE: Nintendo unnecessarily allocates and replaces here a fully copy of the path,
 | ||||
|              * despite having skipped some of it already. */ | ||||
|             // Create a temporary buffer holding a slash-replaced version of the path.
 | ||||
|             // NOTE: Nintendo unnecessarily allocates and replaces here a fully copy of the path,
 | ||||
|             // despite having skipped some of it already.
 | ||||
|             const size_t replaced_src_len = path_len - (src - path); | ||||
| 
 | ||||
|             char* replaced_src = nullptr; | ||||
| @ -1226,7 +1225,7 @@ public: | ||||
|                                             dst_size - cur_pos, is_windows_path, is_drive_relative, | ||||
|                                             flags.IsAllCharactersAllowed())); | ||||
|         } else { | ||||
|             /* We can just do normalization. */ | ||||
|             // We can just do normalization
 | ||||
|             size_t dummy; | ||||
|             R_TRY(PathNormalizer::Normalize(dst + cur_pos, std::addressof(dummy), src, | ||||
|                                             dst_size - cur_pos, is_windows_path, is_drive_relative, | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
 | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| @ -71,21 +71,6 @@ static constexpr int Strlcpy(T* dst, const T* src, int count) { | ||||
|     return static_cast<int>(cur - src); | ||||
| } | ||||
| 
 | ||||
| /* std::size() does not support zero-size C arrays. We're fixing that. */ | ||||
| template <class C> | ||||
| constexpr auto size(const C& c) -> decltype(c.size()) { | ||||
|     return std::size(c); | ||||
| } | ||||
| 
 | ||||
| template <class C> | ||||
| constexpr std::size_t size(const C& c) { | ||||
|     if constexpr (sizeof(C) == 0) { | ||||
|         return 0; | ||||
|     } else { | ||||
|         return std::size(c); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| enum CharacterEncodingResult { | ||||
|     CharacterEncodingResult_Success = 0, | ||||
|     CharacterEncodingResult_InsufficientLength = 1, | ||||
| @ -116,11 +101,11 @@ public: | ||||
| } // namespace impl
 | ||||
| 
 | ||||
| constexpr inline CharacterEncodingResult ConvertCharacterUtf8ToUtf32(u32* dst, const char* src) { | ||||
|     /* Check pre-conditions. */ | ||||
|     // Check pre-conditions
 | ||||
|     ASSERT(dst != nullptr); | ||||
|     ASSERT(src != nullptr); | ||||
| 
 | ||||
|     /* Perform the conversion. */ | ||||
|     // Perform the conversion
 | ||||
|     const auto* p = src; | ||||
|     switch (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[0]))) { | ||||
|     case 1: | ||||
| @ -164,24 +149,24 @@ constexpr inline CharacterEncodingResult ConvertCharacterUtf8ToUtf32(u32* dst, c | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     /* We failed to convert. */ | ||||
|     // We failed to convert
 | ||||
|     return CharacterEncodingResult_InvalidFormat; | ||||
| } | ||||
| 
 | ||||
| constexpr inline CharacterEncodingResult PickOutCharacterFromUtf8String(char* dst, | ||||
|                                                                         const char** str) { | ||||
|     /* Check pre-conditions. */ | ||||
|     // Check pre-conditions
 | ||||
|     ASSERT(dst != nullptr); | ||||
|     ASSERT(str != nullptr); | ||||
|     ASSERT(*str != nullptr); | ||||
| 
 | ||||
|     /* Clear the output. */ | ||||
|     // Clear the output
 | ||||
|     dst[0] = 0; | ||||
|     dst[1] = 0; | ||||
|     dst[2] = 0; | ||||
|     dst[3] = 0; | ||||
| 
 | ||||
|     /* Perform the conversion. */ | ||||
|     // Perform the conversion
 | ||||
|     const auto* p = *str; | ||||
|     u32 c = static_cast<u32>(*p); | ||||
|     switch (impl::CharacterEncodingHelper::GetUtf8NBytes(c)) { | ||||
|  | ||||
| @ -4,6 +4,7 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <mutex> | ||||
| #include "common/common_types.h" | ||||
| #include "core/file_sys/fs_directory.h" | ||||
| #include "core/file_sys/fs_filesystem.h" | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
| 
 | ||||
| #include "common/settings.h" | ||||
| #include "common/time_zone.h" | ||||
| #include "core/file_sys/vfs.h" | ||||
| #include "core/file_sys/vfs/vfs.h" | ||||
| #include "core/hle/kernel/svc.h" | ||||
| #include "core/hle/service/glue/time/manager.h" | ||||
| #include "core/hle/service/glue/time/time_zone_binary.h" | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
| #include <string> | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| #include "core/file_sys/vfs_types.h" | ||||
| #include "core/file_sys/vfs/vfs_types.h" | ||||
| #include "core/hle/service/glue/time/file_timestamp_worker.h" | ||||
| #include "core/hle/service/glue/time/standard_steady_clock_resource.h" | ||||
| #include "core/hle/service/glue/time/worker.h" | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
| #include "core/file_sys/registered_cache.h" | ||||
| #include "core/file_sys/romfs.h" | ||||
| #include "core/file_sys/system_archive/system_archive.h" | ||||
| #include "core/file_sys/vfs.h" | ||||
| #include "core/file_sys/vfs/vfs.h" | ||||
| #include "core/hle/service/filesystem/filesystem.h" | ||||
| #include "core/hle/service/glue/time/time_zone_binary.h" | ||||
| 
 | ||||
|  | ||||
| @ -159,7 +159,7 @@ inline InstallResult InstallNSP(Core::System& system, FileSys::VfsFilesystem& vf | ||||
|     }; | ||||
| 
 | ||||
|     std::shared_ptr<FileSys::NSP> nsp; | ||||
|     FileSys::VirtualFile file = vfs.OpenFile(filename, FileSys::Mode::Read); | ||||
|     FileSys::VirtualFile file = vfs.OpenFile(filename, FileSys::OpenMode::Read); | ||||
|     if (boost::to_lower_copy(file->GetName()).ends_with(std::string("nsp"))) { | ||||
|         nsp = std::make_shared<FileSys::NSP>(file); | ||||
|         if (nsp->IsExtractedType()) { | ||||
| @ -224,7 +224,8 @@ inline InstallResult InstallNCA(FileSys::VfsFilesystem& vfs, const std::string& | ||||
|         return true; | ||||
|     }; | ||||
| 
 | ||||
|     const auto nca = std::make_shared<FileSys::NCA>(vfs.OpenFile(filename, FileSys::Mode::Read)); | ||||
|     const auto nca = | ||||
|         std::make_shared<FileSys::NCA>(vfs.OpenFile(filename, FileSys::OpenMode::Read)); | ||||
|     const auto id = nca->GetStatus(); | ||||
| 
 | ||||
|     // Game updates necessary are missing base RomFS
 | ||||
| @ -345,8 +346,8 @@ inline std::vector<std::string> VerifyInstalledContents( | ||||
| inline GameVerificationResult VerifyGameContents( | ||||
|     Core::System& system, const std::string& game_path, | ||||
|     const std::function<bool(size_t, size_t)>& callback) { | ||||
|     const auto loader = | ||||
|         Loader::GetLoader(system, system.GetFilesystem()->OpenFile(game_path, FileSys::Mode::Read)); | ||||
|     const auto loader = Loader::GetLoader( | ||||
|         system, system.GetFilesystem()->OpenFile(game_path, FileSys::OpenMode::Read)); | ||||
|     if (loader == nullptr) { | ||||
|         return GameVerificationResult::NotImplemented; | ||||
|     } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user