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