|
|
@@ -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,
|