1 // Copyright 2020 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #pragma once
16 
17 #include <stddef.h>                   // for size_t
18 #include <optional>
19 #include <string>                     // for string, basic_string
20 #include <string_view>
21 #include <utility>                    // for move, forward
22 #include <vector>                     // for vector
23 
24 #include "aemu/base/Optional.h"    // for Optional
25 
26 #ifdef __APPLE__
27 
28 #define LIBSUFFIX ".dylib"
29 
30 #else
31 
32 #ifdef _WIN32
33 #include "aemu/base/system/Win32UnicodeString.h"
34 #define LIBSUFFIX ".dll"
35 
36 #else
37 
38 #define LIBSUFFIX ".so"
39 
40 #endif // !_WIN32 (linux)
41 
42 #endif // !__APPLE__
43 
44 namespace android {
45 namespace base {
46 
47 // Helper to get a null-terminated const char* from a string_view.
48 // Only allocates if the string_view is not null terminated.
49 //
50 // Usage:
51 //
52 //      std::string_view myString = ...;
53 //      printf("Contents: %s\n", CStrWrapper(myString).c_str());
54 //
55 // c_str(...) constructs a temporary object that may allocate memory if the
56 // StringView is not null termianted.  The lifetime of the temporary object will
57 // be until the next sequence point (typically the next semicolon).  If the
58 // value needs to exist for longer than that, cache the instance.
59 //
60 //      std::string_view myString = ...;
61 //      auto myNullTerminatedString = CStrWrapper(myString).c_str();
62 //      functionAcceptingConstCharPointer(myNullTerminatedString);
63 //
64 class CStrWrapper {
65 public:
CStrWrapper(std::string_view stringView)66     CStrWrapper(std::string_view stringView) : mStringView(stringView) {}
67 
68     // Returns a null-terminated char*, potentially creating a copy to add a
69     // null terminator.
get()70     const char* get() {
71         if (mStringView.back() == '\0') {
72             return mStringView.data();
73         } else {
74             // Create the std::string copy on-demand.
75             if (!mStringCopy) {
76                 mStringCopy.emplace(mStringView);
77             }
78 
79             return mStringCopy->c_str();
80         }
81     }
82 
83     // Alias for get
c_str()84     const char* c_str() {
85         return get();
86     }
87 
88     // Enable casting to const char*
89     operator const char*() { return get(); }
90 
91 private:
92     const std::string_view mStringView;
93     std::optional<std::string> mStringCopy;
94 };
95 
c_str(std::string_view stringView)96 inline CStrWrapper c_str(std::string_view stringView) {
97     return CStrWrapper(stringView);
98 }
99 
100 // Utility functions to manage file paths. None of these should touch the
101 // file system. All methods must be static.
102 class PathUtils {
103 public:
104     // An enum listing the supported host file system types.
105     // HOST_POSIX means a Posix-like file system.
106     // HOST_WIN32 means a Windows-like file system.
107     // HOST_TYPE means the current host type (one of the above).
108     // NOTE: If you update this list, modify kHostTypeCount below too.
109     enum HostType {
110         HOST_POSIX = 0,
111         HOST_WIN32 = 1,
112 #ifdef _WIN32
113         HOST_TYPE = HOST_WIN32,
114 #else
115         HOST_TYPE = HOST_POSIX,
116 #endif
117     };
118 
119     // The number of distinct items in the HostType enumeration above.
120     static const int kHostTypeCount = 2;
121 
122     // Suffixes for an executable file (.exe on Windows, empty otherwise)
123     static const char* const kExeNameSuffixes[kHostTypeCount];
124 
125     // Suffixe for an executable file on the current platform
126     static const char* const kExeNameSuffix;
127 
128     // Returns the executable name for a base name |baseName|
129     static std::string toExecutableName(const char* baseName, HostType hostType);
130 
toExecutableName(const char * baseName)131     static std::string toExecutableName(const char* baseName) {
132         return toExecutableName(baseName, HOST_TYPE);
133     }
134 
135     // Return true if |ch| is a directory separator for a given |hostType|.
136     static bool isDirSeparator(int ch, HostType hostType);
137 
138     // Return true if |ch| is a directory separator for the current platform.
isDirSeparator(int ch)139     static bool isDirSeparator(int ch) {
140         return isDirSeparator(ch, HOST_TYPE);
141     }
142 
143     // Return true if |ch| is a path separator for a given |hostType|.
144     static bool isPathSeparator(int ch, HostType hostType);
145 
146     // Return true if |ch| is a path separator for the current platform.
isPathSeparator(int ch)147     static bool isPathSeparator(int ch) {
148         return isPathSeparator(ch, HOST_TYPE);
149     }
150 
151     // Return the directory separator character for a given |hostType|
getDirSeparator(HostType hostType)152     static char getDirSeparator(HostType hostType) {
153         return (hostType == HOST_WIN32) ? '\\' : '/';
154     }
155 
156     // Remove trailing separators from a |path| string, for a given |hostType|.
157     static std::string  removeTrailingDirSeparator(const char* path,
158                                                  HostType hostType);
159 
160     // Remove trailing separators from a |path| string for the current host.
removeTrailingDirSeparator(const char * path)161     static std::string removeTrailingDirSeparator(const char* path) {
162         return removeTrailingDirSeparator(path, HOST_TYPE);
163     }
164 
165     // Add a trailing separator if needed.
166     static std::string addTrailingDirSeparator(const std::string& path,
167                                                HostType hostType);
168     static std::string addTrailingDirSeparator(const char* path,
169                                                HostType hostType);
170 
171     // Add a trailing separator if needed.
addTrailingDirSeparator(const std::string & path)172     static std::string addTrailingDirSeparator(const std::string& path) {
173         return addTrailingDirSeparator(path, HOST_TYPE);
174     }
175 
176     // If |path| starts with a root prefix, return its size in bytes, or
177     // 0 otherwise. The definition of valid root prefixes depends on the
178     // value of |hostType|. For HOST_POSIX, it's any path that begins
179     // with a slash (/). For HOST_WIN32, the following prefixes are
180     // recognized:
181     //    <drive>:
182     //    <drive>:<sep>
183     //    <sep><sep>volumeName<sep>
184     static size_t rootPrefixSize(const std::string& path, HostType hostType);
185 
186     // Return the root prefix for the current platform. See above for
187     // documentation.
rootPrefixSize(const char * path,HostType hostType)188     static size_t rootPrefixSize(const char* path, HostType hostType) {
189         return rootPrefixSize(path ? std::string(path) : std::string(""), hostType);
190     }
rootPrefixSize(const char * path)191     static size_t rootPrefixSize(const char* path) {
192         return rootPrefixSize(path, HOST_TYPE);
193     }
194 
195     // Return true iff |path| is an absolute path for a given |hostType|.
196     static bool isAbsolute(const char* path, HostType hostType);
197 
198     // Return true iff |path| is an absolute path for the current host.
isAbsolute(const char * path)199     static bool isAbsolute(const char* path) {
200         return isAbsolute(path, HOST_TYPE);
201     }
202 
203     // Return an extension part of the name/path (the part of the name after
204     // last dot, including the dot. E.g.:
205     //  "file.name" -> ".name"
206     //  "file" -> ""
207     //  "file." -> "."
208     //  "/full/path.png" -> ".png"
209     static std::string_view extension(const char* path, HostType hostType = HOST_TYPE);
210     static std::string_view extension(const std::string& path,
211                                       HostType hostType = HOST_TYPE);
212     // Split |path| into a directory name and a file name. |dirName| and
213     // |baseName| are optional pointers to strings that will receive the
214     // corresponding components on success. |hostType| is a host type.
215     // Return true on success, or false on failure.
216     // Note that unlike the Unix 'basename' command, the command will fail
217     // if |path| ends with directory separator or is a single root prefix.
218     // Windows root prefixes are fully supported, which means the following:
219     //
220     //     /            -> error.
221     //     /foo         -> '/' + 'foo'
222     //     foo          -> '.' + 'foo'
223     //     <drive>:     -> error.
224     //     <drive>:foo  -> '<drive>:' + 'foo'
225     //     <drive>:\foo -> '<drive>:\' + 'foo'
226     //
227     static bool split(const char* path,
228                       HostType hostType,
229                       std::string* dirName,
230                       std::string* baseName);
231 
232     // A variant of split() for the current process' host type.
split(const char * path,std::string * dirName,std::string * baseName)233     static bool split(const char* path,
234                       std::string* dirName,
235                       std::string* baseName) {
236         return split(path, HOST_TYPE, dirName, baseName);
237     }
238 
239     // Join two path components together. Note that if |path2| is an
240     // absolute path, this function returns a copy of |path2|, otherwise
241     // the result will be the concatenation of |path1| and |path2|, if
242     // |path1| doesn't end with a directory separator, a |hostType| specific
243     // one will be inserted between the two paths in the result.
244     static std::string join(const std::string& path1,
245                             const std::string& path2,
246                             HostType hostType);
247 
248     // A variant of join() for the current process' host type.
join(const std::string & path1,const std::string & path2)249     static std::string join(const std::string& path1, const std::string& path2) {
250         return join(path1, path2, HOST_TYPE);
251     }
252 
253     // A convenience function to join a bunch of paths at once
254     template <class... Paths>
join(const std::string & path1,const std::string & path2,Paths &&...paths)255     static std::string join(const std::string& path1,
256                             const std::string& path2,
257                             Paths&&... paths) {
258         return join(path1, join(path2, std::forward<Paths>(paths)...));
259     }
260 
261     // Decompose |path| into individual components. If |path| has a root
262     // prefix, it will always be the first component. I.e. for Posix
263     // systems this will be '/' (for absolute paths). For Win32 systems,
264     // it could be 'C:" (for a path relative to a root volume) or "C:\"
265     // for an absolute path from volume C).,
266     // On success, return true and sets |out| to a vector of strings,
267     // each one being a path component (prefix or subdirectory or file
268     // name). Directory separators do not appear in components, except
269     // for the root prefix, if any.
270     static std::vector<std::string> decompose(std::string&& path,
271                                               HostType hostType);
272     static std::vector<std::string> decompose(const std::string& path,
273                                               HostType hostType);
274 
275     // Decompose |path| into individual components for the host platform.
276     // See comments above for more details.
decompose(std::string && path)277     static std::vector<std::string> decompose(std::string&& path) {
278         return decompose(std::move(path), HOST_TYPE);
279     }
decompose(const std::string & path)280     static std::vector<std::string> decompose(const std::string& path) {
281         return decompose(path, HOST_TYPE);
282     }
283 
284     // Recompose a path from individual components into a file path string.
285     // |components| is a vector of strings, and |hostType| the target
286     // host type to use. Return a new file path string. Note that if the
287     // first component is a root prefix, it will be kept as is, i.e.:
288     //   [ 'C:', 'foo' ] -> 'C:foo' on Win32, but not Posix where it will
289     // be 'C:/foo'.
290     static std::string recompose(const std::vector<std::string>& components,
291                                  HostType hostType);
292     template <class String>
293     static std::string recompose(const std::vector<String>& components,
294                                  HostType hostType);
295 
296     // Recompose a path from individual components into a file path string
297     // for the current host. |components| is a vector os strings.
298     // Returns a new file path string.
299     template <class String>
recompose(const std::vector<String> & components)300     static std::string recompose(const std::vector<String>& components) {
301         return PathUtils::recompose(components, HOST_TYPE);
302     }
303 
304     static std::string canonicalPath(std::string path);
305 
306     // Given a list of components returned by decompose(), simplify it
307     // by removing instances of '.' and '..' when that makes sense.
308     // Note that it is not possible to simplify initial instances of
309     // '..', i.e. "foo/../../bar" -> "../bar"
310     static void simplifyComponents(std::vector<std::string>* components);
311     template <class String>
312     static void simplifyComponents(std::vector<String>* components);
313 
314     // Returns a version of |path| that is relative to |base|.
315     // This can be useful for converting absolute paths to
316     // relative paths given |base|.
317     // Example:
318     // |base|: C:\Users\foo
319     // |path|: C:\Users\foo\AppData\Local\Android\Sdk
320     // would give
321     // AppData\Local\Android\Sdk.
322     // If |base| is not a prefix of |path|, fails by returning
323     // the original |path| unmodified.
324     static std::string relativeTo(const std::string& base,
325                                   const std::string& path,
326                                   HostType hostType);
relativeTo(const std::string & base,const std::string & path)327     static std::string relativeTo(const std::string& base,
328                                   const std::string& path) {
329         return relativeTo(base, path, HOST_TYPE);
330     }
331 
332     static Optional<std::string> pathWithoutDirs(const char* name);
333     static Optional<std::string> pathToDir(const char* name);
334 
335     // Replaces the entries ${xx} with the value of the environment variable
336     // xx if it exists. Returns kNullopt if the environment variable is
337     // not set or empty.
338     static Optional<std::string> pathWithEnvSubstituted(const char* path);
339 
340     // Replaces the entries ${xx} with the value of the environment variable
341     // xx if it exists. Returns kNullopt if the environment variable is
342     // not set or empty.
343     static Optional<std::string> pathWithEnvSubstituted(std::vector<std::string> decomposedPath);
344 
345     // Move a file. It works even when from and to are on different disks.
346     static bool move(const std::string& from, const std::string& to);
347 
348 #ifdef _WIN32
asUnicodePath(const char * path)349     static Win32UnicodeString asUnicodePath(const char* path) { return Win32UnicodeString(path); }
350 #else
asUnicodePath(const char * path)351     static std::string asUnicodePath(const char* path) { return path; }
352 #endif
353 };
354 
355 // Useful shortcuts to avoid too much typing.
356 static const PathUtils::HostType kHostPosix = PathUtils::HOST_POSIX;
357 static const PathUtils::HostType kHostWin32 = PathUtils::HOST_WIN32;
358 static const PathUtils::HostType kHostType = PathUtils::HOST_TYPE;
359 
360 template <class... Paths>
pj(const std::string & path1,const std::string & path2,Paths &&...paths)361 std::string pj(const std::string& path1,
362                const std::string& path2,
363                Paths&&... paths) {
364     return PathUtils::join(path1,
365                pj(path2, std::forward<Paths>(paths)...));
366 }
367 
368 std::string pj(const std::string& path1, const std::string& path2);
369 
370 std::string pj(const std::vector<std::string>& paths);
371 
372 bool pathExists(const char* path);
373 
374 }  // namespace base
375 }  // namespace android
376