// 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 // for size_t #include // for string, basic_string #include // for move, forward #include // 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 std::string& path, HostType hostType); static std::string addTrailingDirSeparator(const char* path, HostType hostType); // Add a trailing separator if needed. static std::string addTrailingDirSeparator(const std::string& 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: // : // : // volumeName 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' // : -> error. // :foo -> ':' + 'foo' // :\foo -> ':\' + '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 static std::string join(const std::string& path1, const std::string& path2, Paths&&... paths) { return join(path1, join(path2, std::forward(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 decompose(std::string&& path, HostType hostType); static std::vector decompose(const std::string& path, HostType hostType); template static std::vector decompose(const String& path, HostType hostType); // Decompose |path| into individual components for the host platform. // See comments above for more details. static std::vector decompose(std::string&& path) { return decompose(std::move(path), HOST_TYPE); } static std::vector decompose(const std::string& path) { return decompose(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& components, HostType hostType); template static std::string recompose(const std::vector& 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 static std::string recompose(const std::vector& 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* components); template static void simplifyComponents(std::vector* 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 pathWithoutDirs(const char* name); static Optional 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 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 pathWithEnvSubstituted(std::vector 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 std::string pj(const std::string& path1, const std::string& path2, Paths&&... paths) { return PathUtils::join(path1, pj(path2, std::forward(paths)...)); } std::string pj(const std::string& path1, const std::string& path2); std::string pj(const std::vector& paths); bool pathExists(const char* path); } // namespace base } // namespace android