• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <string>                     // for string, basic_string
19 #include <utility>                    // for move, forward
20 #include <vector>                     // for vector
21 
22 #include "base/Optional.h"    // for Optional
23 
24 #ifdef __APPLE__
25 
26 #define LIBSUFFIX ".dylib"
27 
28 #else
29 
30 #ifdef _WIN32
31 #include "base/Win32UnicodeString.h"
32 #define LIBSUFFIX ".dll"
33 
34 #else
35 
36 #define LIBSUFFIX ".so"
37 
38 #endif // !_WIN32 (linux)
39 
40 #endif // !__APPLE__
41 
42 namespace android {
43 namespace base {
44 
45 // Utility functions to manage file paths. None of these should touch the
46 // file system. All methods must be static.
47 class PathUtils {
48 public:
49     // An enum listing the supported host file system types.
50     // HOST_POSIX means a Posix-like file system.
51     // HOST_WIN32 means a Windows-like file system.
52     // HOST_TYPE means the current host type (one of the above).
53     // NOTE: If you update this list, modify kHostTypeCount below too.
54     enum HostType {
55         HOST_POSIX = 0,
56         HOST_WIN32 = 1,
57 #ifdef _WIN32
58         HOST_TYPE = HOST_WIN32,
59 #else
60         HOST_TYPE = HOST_POSIX,
61 #endif
62     };
63 
64     // The number of distinct items in the HostType enumeration above.
65     static const int kHostTypeCount = 2;
66 
67     // Suffixes for an executable file (.exe on Windows, empty otherwise)
68     static const char* const kExeNameSuffixes[kHostTypeCount];
69 
70     // Suffixe for an executable file on the current platform
71     static const char* const kExeNameSuffix;
72 
73     // Returns the executable name for a base name |baseName|
74     static std::string toExecutableName(const char* baseName, HostType hostType);
75 
toExecutableName(const char * baseName)76     static std::string toExecutableName(const char* baseName) {
77         return toExecutableName(baseName, HOST_TYPE);
78     }
79 
80     // Return true if |ch| is a directory separator for a given |hostType|.
81     static bool isDirSeparator(int ch, HostType hostType);
82 
83     // Return true if |ch| is a directory separator for the current platform.
isDirSeparator(int ch)84     static bool isDirSeparator(int ch) {
85         return isDirSeparator(ch, HOST_TYPE);
86     }
87 
88     // Return true if |ch| is a path separator for a given |hostType|.
89     static bool isPathSeparator(int ch, HostType hostType);
90 
91     // Return true if |ch| is a path separator for the current platform.
isPathSeparator(int ch)92     static bool isPathSeparator(int ch) {
93         return isPathSeparator(ch, HOST_TYPE);
94     }
95 
96     // Return the directory separator character for a given |hostType|
getDirSeparator(HostType hostType)97     static char getDirSeparator(HostType hostType) {
98         return (hostType == HOST_WIN32) ? '\\' : '/';
99     }
100 
101     // Remove trailing separators from a |path| string, for a given |hostType|.
102     static std::string  removeTrailingDirSeparator(const char* path,
103                                                  HostType hostType);
104 
105     // Remove trailing separators from a |path| string for the current host.
removeTrailingDirSeparator(const char * path)106     static std::string removeTrailingDirSeparator(const char* path) {
107         return removeTrailingDirSeparator(path, HOST_TYPE);
108     }
109 
110     // Add a trailing separator if needed.
111     static std::string addTrailingDirSeparator(const std::string& path,
112                                                HostType hostType);
113     static std::string addTrailingDirSeparator(const char* path,
114                                                HostType hostType);
115 
116     // Add a trailing separator if needed.
addTrailingDirSeparator(const std::string & path)117     static std::string addTrailingDirSeparator(const std::string& path) {
118         return addTrailingDirSeparator(path, HOST_TYPE);
119     }
120 
121     // If |path| starts with a root prefix, return its size in bytes, or
122     // 0 otherwise. The definition of valid root prefixes depends on the
123     // value of |hostType|. For HOST_POSIX, it's any path that begins
124     // with a slash (/). For HOST_WIN32, the following prefixes are
125     // recognized:
126     //    <drive>:
127     //    <drive>:<sep>
128     //    <sep><sep>volumeName<sep>
129     static size_t rootPrefixSize(const std::string& path, HostType hostType);
130 
131     // Return the root prefix for the current platform. See above for
132     // documentation.
rootPrefixSize(const char * path)133     static size_t rootPrefixSize(const char* path) {
134         return rootPrefixSize(path, HOST_TYPE);
135     }
136 
137     // Return true iff |path| is an absolute path for a given |hostType|.
138     static bool isAbsolute(const char* path, HostType hostType);
139 
140     // Return true iff |path| is an absolute path for the current host.
isAbsolute(const char * path)141     static bool isAbsolute(const char* path) {
142         return isAbsolute(path, HOST_TYPE);
143     }
144 
145     // Split |path| into a directory name and a file name. |dirName| and
146     // |baseName| are optional pointers to strings that will receive the
147     // corresponding components on success. |hostType| is a host type.
148     // Return true on success, or false on failure.
149     // Note that unlike the Unix 'basename' command, the command will fail
150     // if |path| ends with directory separator or is a single root prefix.
151     // Windows root prefixes are fully supported, which means the following:
152     //
153     //     /            -> error.
154     //     /foo         -> '/' + 'foo'
155     //     foo          -> '.' + 'foo'
156     //     <drive>:     -> error.
157     //     <drive>:foo  -> '<drive>:' + 'foo'
158     //     <drive>:\foo -> '<drive>:\' + 'foo'
159     //
160     static bool split(const char* path,
161                       HostType hostType,
162                       const char** dirName,
163                       const char** baseName);
164 
165     // A variant of split() for the current process' host type.
split(const char * path,const char ** dirName,const char ** baseName)166     static bool split(const char* path,
167                       const char** dirName,
168                       const char** baseName) {
169         return split(path, HOST_TYPE, dirName, baseName);
170     }
171 
172     // Join two path components together. Note that if |path2| is an
173     // absolute path, this function returns a copy of |path2|, otherwise
174     // the result will be the concatenation of |path1| and |path2|, if
175     // |path1| doesn't end with a directory separator, a |hostType| specific
176     // one will be inserted between the two paths in the result.
177     static std::string join(const std::string& path1,
178                             const std::string& path2,
179                             HostType hostType);
180 
181     // A variant of join() for the current process' host type.
join(const std::string & path1,const std::string & path2)182     static std::string join(const std::string& path1, const std::string& path2) {
183         return join(path1, path2, HOST_TYPE);
184     }
185 
186     // A convenience function to join a bunch of paths at once
187     template <class... Paths>
join(const std::string & path1,const std::string & path2,Paths &&...paths)188     static std::string join(const std::string& path1,
189                             const std::string& path2,
190                             Paths&&... paths) {
191         return join(path1, join(path2, std::forward<Paths>(paths)...));
192     }
193 
194     // Decompose |path| into individual components. If |path| has a root
195     // prefix, it will always be the first component. I.e. for Posix
196     // systems this will be '/' (for absolute paths). For Win32 systems,
197     // it could be 'C:" (for a path relative to a root volume) or "C:\"
198     // for an absolute path from volume C).,
199     // On success, return true and sets |out| to a vector of strings,
200     // each one being a path component (prefix or subdirectory or file
201     // name). Directory separators do not appear in components, except
202     // for the root prefix, if any.
203     static std::vector<std::string> decompose(std::string&& path,
204                                               HostType hostType);
205     static std::vector<std::string> decompose(const std::string& path,
206                                               HostType hostType);
207 
208     template <class String>
209     static std::vector<String> decompose(const String& path,
210                                          HostType hostType);
211 
212     // Decompose |path| into individual components for the host platform.
213     // See comments above for more details.
decompose(std::string && path)214     static std::vector<std::string> decompose(std::string&& path) {
215         return decompose(std::move(path), HOST_TYPE);
216     }
217 
decompose(const std::string & path)218     static std::vector<std::string> decompose(const std::string& path) {
219         return decompose(path, HOST_TYPE);
220     }
221 
222     // Recompose a path from individual components into a file path string.
223     // |components| is a vector of strings, and |hostType| the target
224     // host type to use. Return a new file path string. Note that if the
225     // first component is a root prefix, it will be kept as is, i.e.:
226     //   [ 'C:', 'foo' ] -> 'C:foo' on Win32, but not Posix where it will
227     // be 'C:/foo'.
228     static std::string recompose(const std::vector<std::string>& components,
229                                  HostType hostType);
230     template <class String>
231     static std::string recompose(const std::vector<String>& components,
232                                  HostType hostType);
233 
234     // Recompose a path from individual components into a file path string
235     // for the current host. |components| is a vector os strings.
236     // Returns a new file path string.
237     template <class String>
recompose(const std::vector<String> & components)238     static std::string recompose(const std::vector<String>& components) {
239         return PathUtils::recompose(components, HOST_TYPE);
240     }
241 
242     // Given a list of components returned by decompose(), simplify it
243     // by removing instances of '.' and '..' when that makes sense.
244     // Note that it is not possible to simplify initial instances of
245     // '..', i.e. "foo/../../bar" -> "../bar"
246     static void simplifyComponents(std::vector<std::string>* components);
247     template <class String>
248     static void simplifyComponents(std::vector<String>* components);
249 
250     // Returns a version of |path| that is relative to |base|.
251     // This can be useful for converting absolute paths to
252     // relative paths given |base|.
253     // Example:
254     // |base|: C:\Users\foo
255     // |path|: C:\Users\foo\AppData\Local\Android\Sdk
256     // would give
257     // AppData\Local\Android\Sdk.
258     // If |base| is not a prefix of |path|, fails by returning
259     // the original |path| unmodified.
260     static std::string relativeTo(const char* base, const char* path, HostType hostType);
relativeTo(const char * base,const char * path)261     static std::string relativeTo(const char* base, const char* path) {
262         return relativeTo(base, path, HOST_TYPE);
263     }
264 
265     static Optional<std::string> pathWithoutDirs(const char* name);
266     static Optional<std::string> pathToDir(const char* name);
267 
268     // Replaces the entries ${xx} with the value of the environment variable
269     // xx if it exists. Returns kNullopt if the environment variable is
270     // not set or empty.
271     static Optional<std::string> pathWithEnvSubstituted(const char* path);
272 
273     // Replaces the entries ${xx} with the value of the environment variable
274     // xx if it exists. Returns kNullopt if the environment variable is
275     // not set or empty.
276     static Optional<std::string> pathWithEnvSubstituted(std::vector<std::string> decomposedPath);
277 
278 #ifdef _WIN32
asUnicodePath(const char * path)279     static Win32UnicodeString asUnicodePath(const char* path) { return Win32UnicodeString(path); }
280 #else
asUnicodePath(const char * path)281     static std::string asUnicodePath(const char* path) { return path; }
282 #endif
283 };
284 
285 // Useful shortcuts to avoid too much typing.
286 static const PathUtils::HostType kHostPosix = PathUtils::HOST_POSIX;
287 static const PathUtils::HostType kHostWin32 = PathUtils::HOST_WIN32;
288 static const PathUtils::HostType kHostType = PathUtils::HOST_TYPE;
289 
290 template <class... Paths>
pj(const std::string & path1,const std::string & path2,Paths &&...paths)291 std::string pj(const std::string& path1,
292                   const std::string& path2,
293                   Paths&&... paths) {
294     return PathUtils::join(path1,
295                pj(path2, std::forward<Paths>(paths)...));
296 }
297 
298 std::string pj(const std::string& path1, const std::string& path2);
299 
300 std::string pj(const std::vector<std::string>& paths);
301 
302 bool pathExists(const char* path);
303 
304 }  // namespace base
305 }  // namespace android
306