| // Copyright 2020 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #pragma once |
| |
| #include <stddef.h> // for size_t |
| #include <string> // for string, basic_string |
| #include <utility> // for move, forward |
| #include <vector> // for vector |
| |
| #include "base/Optional.h" // for Optional |
| |
| #ifdef __APPLE__ |
| |
| #define LIBSUFFIX ".dylib" |
| |
| #else |
| |
| #ifdef _WIN32 |
| #include "base/Win32UnicodeString.h" |
| #define LIBSUFFIX ".dll" |
| |
| #else |
| |
| #define LIBSUFFIX ".so" |
| |
| #endif // !_WIN32 (linux) |
| |
| #endif // !__APPLE__ |
| |
| namespace android { |
| namespace base { |
| |
| // Utility functions to manage file paths. None of these should touch the |
| // file system. All methods must be static. |
| class PathUtils { |
| public: |
| // An enum listing the supported host file system types. |
| // HOST_POSIX means a Posix-like file system. |
| // HOST_WIN32 means a Windows-like file system. |
| // HOST_TYPE means the current host type (one of the above). |
| // NOTE: If you update this list, modify kHostTypeCount below too. |
| enum HostType { |
| HOST_POSIX = 0, |
| HOST_WIN32 = 1, |
| #ifdef _WIN32 |
| HOST_TYPE = HOST_WIN32, |
| #else |
| HOST_TYPE = HOST_POSIX, |
| #endif |
| }; |
| |
| // The number of distinct items in the HostType enumeration above. |
| static const int kHostTypeCount = 2; |
| |
| // Suffixes for an executable file (.exe on Windows, empty otherwise) |
| static const char* const kExeNameSuffixes[kHostTypeCount]; |
| |
| // Suffixe for an executable file on the current platform |
| static const char* const kExeNameSuffix; |
| |
| // Returns the executable name for a base name |baseName| |
| static std::string toExecutableName(const char* baseName, HostType hostType); |
| |
| static std::string toExecutableName(const char* baseName) { |
| return toExecutableName(baseName, HOST_TYPE); |
| } |
| |
| // Return true if |ch| is a directory separator for a given |hostType|. |
| static bool isDirSeparator(int ch, HostType hostType); |
| |
| // Return true if |ch| is a directory separator for the current platform. |
| static bool isDirSeparator(int ch) { |
| return isDirSeparator(ch, HOST_TYPE); |
| } |
| |
| // Return true if |ch| is a path separator for a given |hostType|. |
| static bool isPathSeparator(int ch, HostType hostType); |
| |
| // Return true if |ch| is a path separator for the current platform. |
| static bool isPathSeparator(int ch) { |
| return isPathSeparator(ch, HOST_TYPE); |
| } |
| |
| // Return the directory separator character for a given |hostType| |
| static char getDirSeparator(HostType hostType) { |
| return (hostType == HOST_WIN32) ? '\\' : '/'; |
| } |
| |
| // Remove trailing separators from a |path| string, for a given |hostType|. |
| static std::string removeTrailingDirSeparator(const char* path, |
| HostType hostType); |
| |
| // Remove trailing separators from a |path| string for the current host. |
| static std::string removeTrailingDirSeparator(const char* path) { |
| return removeTrailingDirSeparator(path, HOST_TYPE); |
| } |
| |
| // Add a trailing separator if needed. |
| static std::string addTrailingDirSeparator(const char* path, |
| HostType hostType); |
| |
| // Add a trailing separator if needed. |
| static std::string addTrailingDirSeparator(const char* path) { |
| return addTrailingDirSeparator(path, HOST_TYPE); |
| } |
| |
| // If |path| starts with a root prefix, return its size in bytes, or |
| // 0 otherwise. The definition of valid root prefixes depends on the |
| // value of |hostType|. For HOST_POSIX, it's any path that begins |
| // with a slash (/). For HOST_WIN32, the following prefixes are |
| // recognized: |
| // <drive>: |
| // <drive>:<sep> |
| // <sep><sep>volumeName<sep> |
| static size_t rootPrefixSize(const std::string& path, HostType hostType); |
| |
| // Return the root prefix for the current platform. See above for |
| // documentation. |
| static size_t rootPrefixSize(const char* path) { |
| return rootPrefixSize(path, HOST_TYPE); |
| } |
| |
| // Return true iff |path| is an absolute path for a given |hostType|. |
| static bool isAbsolute(const char* path, HostType hostType); |
| |
| // Return true iff |path| is an absolute path for the current host. |
| static bool isAbsolute(const char* path) { |
| return isAbsolute(path, HOST_TYPE); |
| } |
| |
| // Split |path| into a directory name and a file name. |dirName| and |
| // |baseName| are optional pointers to strings that will receive the |
| // corresponding components on success. |hostType| is a host type. |
| // Return true on success, or false on failure. |
| // Note that unlike the Unix 'basename' command, the command will fail |
| // if |path| ends with directory separator or is a single root prefix. |
| // Windows root prefixes are fully supported, which means the following: |
| // |
| // / -> error. |
| // /foo -> '/' + 'foo' |
| // foo -> '.' + 'foo' |
| // <drive>: -> error. |
| // <drive>:foo -> '<drive>:' + 'foo' |
| // <drive>:\foo -> '<drive>:\' + 'foo' |
| // |
| static bool split(const char* path, |
| HostType hostType, |
| const char** dirName, |
| const char** baseName); |
| |
| // A variant of split() for the current process' host type. |
| static bool split(const char* path, |
| const char** dirName, |
| const char** baseName) { |
| return split(path, HOST_TYPE, dirName, baseName); |
| } |
| |
| // Join two path components together. Note that if |path2| is an |
| // absolute path, this function returns a copy of |path2|, otherwise |
| // the result will be the concatenation of |path1| and |path2|, if |
| // |path1| doesn't end with a directory separator, a |hostType| specific |
| // one will be inserted between the two paths in the result. |
| static std::string join(const std::string& path1, |
| const std::string& path2, |
| HostType hostType); |
| |
| // A variant of join() for the current process' host type. |
| static std::string join(const std::string& path1, const std::string& path2) { |
| return join(path1, path2, HOST_TYPE); |
| } |
| |
| // A convenience function to join a bunch of paths at once |
| template <class... Paths> |
| static std::string join(const std::string& path1, |
| const std::string& path2, |
| Paths&&... paths) { |
| return join(path1, join(path2, std::forward<Paths>(paths)...)); |
| } |
| |
| // Decompose |path| into individual components. If |path| has a root |
| // prefix, it will always be the first component. I.e. for Posix |
| // systems this will be '/' (for absolute paths). For Win32 systems, |
| // it could be 'C:" (for a path relative to a root volume) or "C:\" |
| // for an absolute path from volume C)., |
| // On success, return true and sets |out| to a vector of strings, |
| // each one being a path component (prefix or subdirectory or file |
| // name). Directory separators do not appear in components, except |
| // for the root prefix, if any. |
| static std::vector<std::string> decompose(std::string&& path, |
| HostType hostType); |
| |
| template <class String> |
| static std::vector<String> decompose(const String& path, |
| HostType hostType); |
| |
| // Decompose |path| into individual components for the host platform. |
| // See comments above for more details. |
| static std::vector<std::string> decompose(std::string&& path) { |
| return decompose(std::move(path), HOST_TYPE); |
| } |
| |
| // Recompose a path from individual components into a file path string. |
| // |components| is a vector of strings, and |hostType| the target |
| // host type to use. Return a new file path string. Note that if the |
| // first component is a root prefix, it will be kept as is, i.e.: |
| // [ 'C:', 'foo' ] -> 'C:foo' on Win32, but not Posix where it will |
| // be 'C:/foo'. |
| static std::string recompose(const std::vector<std::string>& components, |
| HostType hostType); |
| template <class String> |
| static std::string recompose(const std::vector<String>& components, |
| HostType hostType); |
| |
| // Recompose a path from individual components into a file path string |
| // for the current host. |components| is a vector os strings. |
| // Returns a new file path string. |
| template <class String> |
| static std::string recompose(const std::vector<String>& components) { |
| return PathUtils::recompose(components, HOST_TYPE); |
| } |
| |
| // Given a list of components returned by decompose(), simplify it |
| // by removing instances of '.' and '..' when that makes sense. |
| // Note that it is not possible to simplify initial instances of |
| // '..', i.e. "foo/../../bar" -> "../bar" |
| static void simplifyComponents(std::vector<std::string>* components); |
| template <class String> |
| static void simplifyComponents(std::vector<String>* components); |
| |
| // Returns a version of |path| that is relative to |base|. |
| // This can be useful for converting absolute paths to |
| // relative paths given |base|. |
| // Example: |
| // |base|: C:\Users\foo |
| // |path|: C:\Users\foo\AppData\Local\Android\Sdk |
| // would give |
| // AppData\Local\Android\Sdk. |
| // If |base| is not a prefix of |path|, fails by returning |
| // the original |path| unmodified. |
| static std::string relativeTo(const char* base, const char* path, HostType hostType); |
| static std::string relativeTo(const char* base, const char* path) { |
| return relativeTo(base, path, HOST_TYPE); |
| } |
| |
| static Optional<std::string> pathWithoutDirs(const char* name); |
| static Optional<std::string> pathToDir(const char* name); |
| |
| // Replaces the entries ${xx} with the value of the environment variable |
| // xx if it exists. Returns kNullopt if the environment variable is |
| // not set or empty. |
| static Optional<std::string> pathWithEnvSubstituted(const char* path); |
| |
| // Replaces the entries ${xx} with the value of the environment variable |
| // xx if it exists. Returns kNullopt if the environment variable is |
| // not set or empty. |
| static Optional<std::string> pathWithEnvSubstituted(std::vector<std::string> decomposedPath); |
| |
| #ifdef _WIN32 |
| static Win32UnicodeString asUnicodePath(const char* path) { return Win32UnicodeString(path); } |
| #else |
| static std::string asUnicodePath(const char* path) { return path; } |
| #endif |
| }; |
| |
| // Useful shortcuts to avoid too much typing. |
| static const PathUtils::HostType kHostPosix = PathUtils::HOST_POSIX; |
| static const PathUtils::HostType kHostWin32 = PathUtils::HOST_WIN32; |
| static const PathUtils::HostType kHostType = PathUtils::HOST_TYPE; |
| |
| template <class... Paths> |
| std::string pj(const std::string& path1, |
| const std::string& path2, |
| Paths&&... paths) { |
| return PathUtils::join(path1, |
| pj(path2, std::forward<Paths>(paths)...)); |
| } |
| |
| std::string pj(const std::string& path1, const std::string& path2); |
| |
| std::string pj(const std::vector<std::string>& paths); |
| |
| bool pathExists(const char* path); |
| |
| } // namespace base |
| } // namespace android |