Bug 1805294 [wpt PR 37463] - WebKit export of https://bugs.webkit.org/show_bug.cgi...
[gecko.git] / dom / system / PathUtils.h
blobcbfceef269f5d6c6fac5f75428d45221fa7a125d
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_dom_PathUtils__
8 #define mozilla_dom_PathUtils__
10 #include "mozilla/DataMutex.h"
11 #include "mozilla/EnumeratedArray.h"
12 #include "mozilla/Maybe.h"
13 #include "mozilla/MozPromise.h"
14 #include "mozilla/Mutex.h"
15 #include "mozilla/Result.h"
16 #include "mozilla/dom/PathUtilsBinding.h"
17 #include "mozilla/dom/Promise.h"
18 #include "nsAppDirectoryServiceDefs.h"
19 #include "nsDirectoryServiceDefs.h"
20 #include "nsString.h"
21 #include "nsTArray.h"
23 namespace mozilla {
24 class ErrorResult;
26 namespace dom {
28 class PathUtils final {
29 public:
30 /**
31 * Initialize the given nsIFile with the given path.
33 * This is equivalent to calling nsIFile::InitWithPath() with the caveat that
34 * on Windows debug or during Windows CI tests, we will crash if the path
35 * contains a forward slash.
37 * @param aFile The file to initialize.
38 * @param aPath The path to initialize the file with.
40 * @return The result of calling nsIFile::InitWithPath.
42 static nsresult InitFileWithPath(nsIFile* aFile, const nsAString& aPath);
44 static void Filename(const GlobalObject&, const nsAString& aPath,
45 nsString& aResult, ErrorResult& aErr);
47 static void Parent(const GlobalObject&, const nsAString& aPath,
48 const int32_t aDepth, nsString& aResult,
49 ErrorResult& aErr);
51 static void Join(const GlobalObject&, const Sequence<nsString>& aComponents,
52 nsString& aResult, ErrorResult& aErr);
54 /**
55 * Join a sequence of path components and return an nsIFile with the resulting
56 * path.
58 * @param aComponents A sequence of path components. The first component must
59 * be an absolute path.
60 * @param aErr The error result, if any.
62 * @return An nsIFile with the resulting path, if there were no errors.
63 * Otherwise, nullptr is returned.
65 static already_AddRefed<nsIFile> Join(const Span<const nsString>& aComponents,
66 ErrorResult& aErr);
68 static void JoinRelative(const GlobalObject&, const nsAString& aBasePath,
69 const nsAString& aRelativePath, nsString& aResult,
70 ErrorResult& aErr);
72 static void ToExtendedWindowsPath(const GlobalObject&, const nsAString& aPath,
73 nsString& aResult, ErrorResult& aErr);
75 static void Normalize(const GlobalObject&, const nsAString& aPath,
76 nsString& aResult, ErrorResult& aErr);
78 static void Split(const GlobalObject&, const nsAString& aPath,
79 nsTArray<nsString>& aResult, ErrorResult& aErr);
81 static void SplitRelative(const GlobalObject& aGlobal, const nsAString& aPath,
82 const SplitRelativeOptions& aOptions,
83 nsTArray<nsString>& aResult, ErrorResult& aErr);
85 static void ToFileURI(const GlobalObject&, const nsAString& aPath,
86 nsCString& aResult, ErrorResult& aErr);
88 static bool IsAbsolute(const GlobalObject&, const nsAString& aPath);
90 static void GetProfileDirSync(const GlobalObject&, nsString& aResult,
91 ErrorResult& aErr);
92 static void GetLocalProfileDirSync(const GlobalObject&, nsString& aResult,
93 ErrorResult& aErr);
94 static void GetTempDirSync(const GlobalObject&, nsString& aResult,
95 ErrorResult& aErr);
96 static void GetOSTempDirSync(const GlobalObject&, nsString& aResult,
97 ErrorResult& aErr);
98 static void GetXulLibraryPathSync(const GlobalObject&, nsString& aResult,
99 ErrorResult& aErr);
101 static already_AddRefed<Promise> GetProfileDirAsync(
102 const GlobalObject& aGlobal, ErrorResult& aErr);
103 static already_AddRefed<Promise> GetLocalProfileDirAsync(
104 const GlobalObject& aGlobal, ErrorResult& aErr);
105 static already_AddRefed<Promise> GetTempDirAsync(const GlobalObject& aGlobal,
106 ErrorResult& aErr);
107 static already_AddRefed<Promise> GetOSTempDirAsync(
108 const GlobalObject& aGlobal, ErrorResult& aErr);
109 static already_AddRefed<Promise> GetXulLibraryPathAsync(
110 const GlobalObject& aGlobal, ErrorResult& aErr);
112 private:
113 class DirectoryCache;
114 friend class DirectoryCache;
116 static StaticDataMutex<Maybe<DirectoryCache>> sDirCache;
120 * A cache of commonly used directories
122 class PathUtils::DirectoryCache final {
123 public:
125 * A directory that can be requested via |GetDirectorySync| or
126 * |GetDirectoryAsync|.
128 enum class Directory {
130 * The user's profile directory.
132 Profile,
134 * The user's local profile directory.
136 LocalProfile,
138 * The temporary directory for the process.
140 Temp,
142 * The OS temporary directory.
144 OSTemp,
146 * The libxul path.
148 XulLibrary,
150 * The number of Directory entries.
152 Count,
155 DirectoryCache();
156 DirectoryCache(const DirectoryCache&) = delete;
157 DirectoryCache(DirectoryCache&&) = delete;
158 DirectoryCache& operator=(const DirectoryCache&) = delete;
159 DirectoryCache& operator=(DirectoryCache&&) = delete;
162 * Ensure the cache is instantiated and schedule its destructor to run at
163 * shutdown.
165 * If the cache is already instantiated, this is a no-op.
167 * @param aCache The cache to ensure is instantiated.
169 static DirectoryCache& Ensure(Maybe<DirectoryCache>& aCache);
171 void GetDirectorySync(nsString& aResult, ErrorResult& aErr,
172 const Directory aRequestedDir);
175 * Request the path of a specific directory.
177 * If the directory has not been requested before, this may require a trip to
178 * the main thread to retrieve its path.
180 * @param aGlobalObject The JavaScript global.
181 * @param aErr The error result.
182 * @param aRequestedDir The directory for which the path is to be retrieved.
184 * @return A promise that resolves to the path of the requested directory.
186 already_AddRefed<Promise> GetDirectoryAsync(const GlobalObject& aGlobalObject,
187 ErrorResult& aErr,
188 const Directory aRequestedDir);
190 private:
191 using PopulateDirectoriesPromise = MozPromise<Ok, nsresult, false>;
194 * Populate the directory cache entry for the requested directory.
196 * @param aRequestedDir The directory cache entry that was requested via
197 * |GetDirectory|.
199 * @return If the requested directory has not been populated, this returns a
200 * promise that resolves when the population is complete.
202 * If the requested directory has already been populated, it returns
203 * nullptr instead.
205 already_AddRefed<PopulateDirectoriesPromise> PopulateDirectories(
206 const Directory aRequestedDir);
209 * Initialize the requested directory cache entry.
211 * If |Directory::Temp| is requested, all cache entries will be populated.
212 * Otherwise, only the profile and local profile cache entries will be
213 * populated. The profile and local profile cache entries have no additional
214 * overhead for populating them, but the temp directory requires creating a
215 * directory on the main thread if it has not already happened.
217 * Must be called on the main thread.
219 * @param aRequestedDir The requested directory.
221 * @return The result of initializing directories.
223 nsresult PopulateDirectoriesImpl(const Directory aRequestedDir);
226 * Resolve the internal PopulateDirectoriesPromise corresponding to
227 * |aRequestedDir| with the given result.
229 * This will allow all pending queries for the requested directory to resolve
230 * or be rejected.
232 * @param aRv The return value from PopulateDirectoriesImpl.
233 * @param aRequestedDir The requested directory cache entry. This is used to
234 * determine which internal MozPromiseHolder we are
235 * resolving.
237 void ResolvePopulateDirectoriesPromise(nsresult aRv,
238 const Directory aRequestedDir);
241 * Resolve the given JS promise with the path of the requested directory
243 * Can only be called once the cache entry for the requested directory is
244 * populated.
246 * @param aPromise The JS promise to resolve.
247 * @param aRequestedDir The requested directory cache entry.
249 void ResolveWithDirectory(Promise* aPromise, const Directory aRequestedDir);
251 template <typename T>
252 using DirectoryArray = EnumeratedArray<Directory, Directory::Count, T>;
254 DirectoryArray<nsString> mDirectories;
255 DirectoryArray<MozPromiseHolder<PopulateDirectoriesPromise>> mPromises;
257 static constexpr DirectoryArray<const char*> kDirectoryNames{
258 NS_APP_USER_PROFILE_50_DIR, NS_APP_USER_PROFILE_LOCAL_50_DIR,
259 NS_APP_CONTENT_PROCESS_TEMP_DIR, NS_OS_TEMP_DIR,
260 NS_XPCOM_LIBRARY_FILE,
264 } // namespace dom
265 } // namespace mozilla
267 #endif