summaryrefslogtreecommitdiff
path: root/src/common/fs/path_util.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/fs/path_util.h')
-rw-r--r--src/common/fs/path_util.h309
1 files changed, 309 insertions, 0 deletions
diff --git a/src/common/fs/path_util.h b/src/common/fs/path_util.h
new file mode 100644
index 000000000..a9fadbceb
--- /dev/null
+++ b/src/common/fs/path_util.h
@@ -0,0 +1,309 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <filesystem>
8#include <vector>
9
10#include "common/fs/fs_util.h"
11
12namespace Common::FS {
13
14enum class YuzuPath {
15 YuzuDir, // Where yuzu stores its data.
16 CacheDir, // Where cached filesystem data is stored.
17 ConfigDir, // Where config files are stored.
18 DumpDir, // Where dumped data is stored.
19 KeysDir, // Where key files are stored.
20 LoadDir, // Where cheat/mod files are stored.
21 LogDir, // Where log files are stored.
22 NANDDir, // Where the emulated NAND is stored.
23 ScreenshotsDir, // Where yuzu screenshots are stored.
24 SDMCDir, // Where the emulated SDMC is stored.
25 ShaderDir, // Where shaders are stored.
26};
27
28/**
29 * Converts a filesystem path to a UTF-8 encoded std::string.
30 *
31 * @param path Filesystem path
32 *
33 * @returns UTF-8 encoded std::string.
34 */
35[[nodiscard]] std::string PathToUTF8String(const std::filesystem::path& path);
36
37/**
38 * Validates a given path.
39 *
40 * A given path is valid if it meets these conditions:
41 * - The path is not empty
42 * - The path is not too long
43 *
44 * @param path Filesystem path
45 *
46 * @returns True if the path is valid, false otherwise.
47 */
48[[nodiscard]] bool ValidatePath(const std::filesystem::path& path);
49
50#ifdef _WIN32
51template <typename Path>
52[[nodiscard]] bool ValidatePath(const Path& path) {
53 if constexpr (IsChar<typename Path::value_type>) {
54 return ValidatePath(ToU8String(path));
55 } else {
56 return ValidatePath(std::filesystem::path{path});
57 }
58}
59#endif
60
61/**
62 * Concatenates two filesystem paths together.
63 *
64 * This is needed since the following occurs when using std::filesystem::path's operator/:
65 * first: "/first/path"
66 * second: "/second/path" (Note that the second path has a directory separator in the front)
67 * first / second yields "/second/path" when the desired result is first/path/second/path
68 *
69 * @param first First filesystem path
70 * @param second Second filesystem path
71 *
72 * @returns A concatenated filesystem path.
73 */
74[[nodiscard]] std::filesystem::path ConcatPath(const std::filesystem::path& first,
75 const std::filesystem::path& second);
76
77#ifdef _WIN32
78template <typename Path1, typename Path2>
79[[nodiscard]] std::filesystem::path ConcatPath(const Path1& first, const Path2& second) {
80 using ValueType1 = typename Path1::value_type;
81 using ValueType2 = typename Path2::value_type;
82 if constexpr (IsChar<ValueType1> && IsChar<ValueType2>) {
83 return ConcatPath(ToU8String(first), ToU8String(second));
84 } else if constexpr (IsChar<ValueType1> && !IsChar<ValueType2>) {
85 return ConcatPath(ToU8String(first), second);
86 } else if constexpr (!IsChar<ValueType1> && IsChar<ValueType2>) {
87 return ConcatPath(first, ToU8String(second));
88 } else {
89 return ConcatPath(std::filesystem::path{first}, std::filesystem::path{second});
90 }
91}
92#endif
93
94/**
95 * Safe variant of ConcatPath that takes in a base path and an offset path from the given base path.
96 *
97 * If ConcatPath(base, offset) resolves to a path that is sandboxed within the base path,
98 * this will return the concatenated path. Otherwise this will return the base path.
99 *
100 * @param base Base filesystem path
101 * @param offset Offset filesystem path
102 *
103 * @returns A concatenated filesystem path if it is within the base path,
104 * returns the base path otherwise.
105 */
106[[nodiscard]] std::filesystem::path ConcatPathSafe(const std::filesystem::path& base,
107 const std::filesystem::path& offset);
108
109#ifdef _WIN32
110template <typename Path1, typename Path2>
111[[nodiscard]] std::filesystem::path ConcatPathSafe(const Path1& base, const Path2& offset) {
112 using ValueType1 = typename Path1::value_type;
113 using ValueType2 = typename Path2::value_type;
114 if constexpr (IsChar<ValueType1> && IsChar<ValueType2>) {
115 return ConcatPathSafe(ToU8String(base), ToU8String(offset));
116 } else if constexpr (IsChar<ValueType1> && !IsChar<ValueType2>) {
117 return ConcatPathSafe(ToU8String(base), offset);
118 } else if constexpr (!IsChar<ValueType1> && IsChar<ValueType2>) {
119 return ConcatPathSafe(base, ToU8String(offset));
120 } else {
121 return ConcatPathSafe(std::filesystem::path{base}, std::filesystem::path{offset});
122 }
123}
124#endif
125
126/**
127 * Checks whether a given path is sandboxed within a given base path.
128 *
129 * @param base Base filesystem path
130 * @param path Filesystem path
131 *
132 * @returns True if the given path is sandboxed within the given base path, false otherwise.
133 */
134[[nodiscard]] bool IsPathSandboxed(const std::filesystem::path& base,
135 const std::filesystem::path& path);
136
137#ifdef _WIN32
138template <typename Path1, typename Path2>
139[[nodiscard]] bool IsPathSandboxed(const Path1& base, const Path2& path) {
140 using ValueType1 = typename Path1::value_type;
141 using ValueType2 = typename Path2::value_type;
142 if constexpr (IsChar<ValueType1> && IsChar<ValueType2>) {
143 return IsPathSandboxed(ToU8String(base), ToU8String(path));
144 } else if constexpr (IsChar<ValueType1> && !IsChar<ValueType2>) {
145 return IsPathSandboxed(ToU8String(base), path);
146 } else if constexpr (!IsChar<ValueType1> && IsChar<ValueType2>) {
147 return IsPathSandboxed(base, ToU8String(path));
148 } else {
149 return IsPathSandboxed(std::filesystem::path{base}, std::filesystem::path{path});
150 }
151}
152#endif
153
154/**
155 * Checks if a character is a directory separator (either a forward slash or backslash).
156 *
157 * @param character Character
158 *
159 * @returns True if the character is a directory separator, false otherwise.
160 */
161[[nodiscard]] bool IsDirSeparator(char character);
162
163/**
164 * Checks if a character is a directory separator (either a forward slash or backslash).
165 *
166 * @param character Character
167 *
168 * @returns True if the character is a directory separator, false otherwise.
169 */
170[[nodiscard]] bool IsDirSeparator(char8_t character);
171
172/**
173 * Removes any trailing directory separators if they exist in the given path.
174 *
175 * @param path Filesystem path
176 *
177 * @returns The filesystem path without any trailing directory separators.
178 */
179[[nodiscard]] std::filesystem::path RemoveTrailingSeparators(const std::filesystem::path& path);
180
181#ifdef _WIN32
182template <typename Path>
183[[nodiscard]] std::filesystem::path RemoveTrailingSeparators(const Path& path) {
184 if constexpr (IsChar<typename Path::value_type>) {
185 return RemoveTrailingSeparators(ToU8String(path));
186 } else {
187 return RemoveTrailingSeparators(std::filesystem::path{path});
188 }
189}
190#endif
191
192/**
193 * Gets the filesystem path associated with the YuzuPath enum.
194 *
195 * @param yuzu_path YuzuPath enum
196 *
197 * @returns The filesystem path associated with the YuzuPath enum.
198 */
199[[nodiscard]] const std::filesystem::path& GetYuzuPath(YuzuPath yuzu_path);
200
201/**
202 * Gets the filesystem path associated with the YuzuPath enum as a UTF-8 encoded std::string.
203 *
204 * @param yuzu_path YuzuPath enum
205 *
206 * @returns The filesystem path associated with the YuzuPath enum as a UTF-8 encoded std::string.
207 */
208[[nodiscard]] std::string GetYuzuPathString(YuzuPath yuzu_path);
209
210/**
211 * Sets a new filesystem path associated with the YuzuPath enum.
212 * If the filesystem object at new_path is not a directory, this function will not do anything.
213 *
214 * @param yuzu_path YuzuPath enum
215 * @param new_path New filesystem path
216 */
217void SetYuzuPath(YuzuPath yuzu_path, const std::filesystem::path& new_path);
218
219#ifdef _WIN32
220template <typename Path>
221[[nodiscard]] void SetYuzuPath(YuzuPath yuzu_path, const Path& new_path) {
222 if constexpr (IsChar<typename Path::value_type>) {
223 SetYuzuPath(yuzu_path, ToU8String(new_path));
224 } else {
225 SetYuzuPath(yuzu_path, std::filesystem::path{new_path});
226 }
227}
228#endif
229
230#ifdef _WIN32
231
232/**
233 * Gets the path of the directory containing the executable of the current process.
234 *
235 * @returns The path of the directory containing the executable of the current process.
236 */
237[[nodiscard]] std::filesystem::path GetExeDirectory();
238
239/**
240 * Gets the path of the current user's %APPDATA% directory (%USERPROFILE%/AppData/Roaming).
241 *
242 * @returns The path of the current user's %APPDATA% directory.
243 */
244[[nodiscard]] std::filesystem::path GetAppDataRoamingDirectory();
245
246#else
247
248/**
249 * Gets the path of the directory specified by the #HOME environment variable.
250 * If $HOME is not defined, it will attempt to query the user database in passwd instead.
251 *
252 * @returns The path of the current user's home directory.
253 */
254[[nodiscard]] std::filesystem::path GetHomeDirectory();
255
256/**
257 * Gets the relevant paths for yuzu to store its data based on the given XDG environment variable.
258 * See https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
259 * Defaults to $HOME/.local/share for main application data,
260 * $HOME/.cache for cached data, and $HOME/.config for configuration files.
261 *
262 * @param env_name XDG environment variable name
263 *
264 * @returns The path where yuzu should store its data.
265 */
266[[nodiscard]] std::filesystem::path GetDataDirectory(const std::string& env_name);
267
268#endif
269
270#ifdef __APPLE__
271
272[[nodiscard]] std::filesystem::path GetBundleDirectory();
273
274#endif
275
276// vvvvvvvvvv Deprecated vvvvvvvvvv //
277
278// Removes the final '/' or '\' if one exists
279[[nodiscard]] std::string_view RemoveTrailingSlash(std::string_view path);
280
281enum class DirectorySeparator {
282 ForwardSlash,
283 BackwardSlash,
284 PlatformDefault,
285};
286
287// Splits the path on '/' or '\' and put the components into a vector
288// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" }
289[[nodiscard]] std::vector<std::string> SplitPathComponents(std::string_view filename);
290
291// Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\'
292// depending if directory_separator is BackwardSlash or PlatformDefault and running on windows
293[[nodiscard]] std::string SanitizePath(
294 std::string_view path,
295 DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash);
296
297// Gets all of the text up to the last '/' or '\' in the path.
298[[nodiscard]] std::string_view GetParentPath(std::string_view path);
299
300// Gets all of the text after the first '/' or '\' in the path.
301[[nodiscard]] std::string_view GetPathWithoutTop(std::string_view path);
302
303// Gets the filename of the path
304[[nodiscard]] std::string_view GetFilename(std::string_view path);
305
306// Gets the extension of the filename
307[[nodiscard]] std::string_view GetExtensionFromFilename(std::string_view name);
308
309} // namespace Common::FS