1// Copyright 2014 The Android Open Source Project
2//
3// This software is licensed under the terms of the GNU General Public
4// License version 2, as published by the Free Software Foundation, and
5// may be copied, distributed, and modified under those terms.
6//
7// This program is distributed in the hope that it will be useful,
8// but WITHOUT ANY WARRANTY; without even the implied warranty of
9// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10// GNU General Public License for more details.
11
12#ifndef ANDROID_BASE_FILES_PATH_UTIL_H
13#define ANDROID_BASE_FILES_PATH_UTIL_H
14
15#include "android/base/containers/StringVector.h"
16#include "android/base/String.h"
17
18namespace android {
19namespace base {
20
21// Utility functions to manage file paths. None of these should touch the
22// file system. All methods must be static.
23class PathUtils {
24public:
25    // An enum listing the supported host file system types.
26    // HOST_POSIX means a Posix-like file system.
27    // HOST_WIN32 means a Windows-like file system.
28    // HOST_TYPE means the current host type (one of the above).
29    // NOTE: If you update this list, modify kHostTypeCount below too.
30    enum HostType {
31        HOST_POSIX = 0,
32        HOST_WIN32 = 1,
33#ifdef _WIN32
34        HOST_TYPE = HOST_WIN32,
35#else
36        HOST_TYPE = HOST_POSIX,
37#endif
38    };
39
40    // The number of distinct items in the HostType enumeration above.
41    static const int kHostTypeCount = 2;
42
43    // Return true if |ch| is a directory separator for a given |hostType|.
44    static bool isDirSeparator(int ch, HostType hostType);
45
46    // Return true if |ch| is a directory separator for the current platform.
47    static inline bool isDirSeparator(int ch) {
48        return isDirSeparator(ch, HOST_TYPE);
49    }
50
51    // Return true if |ch| is a path separator for a given |hostType|.
52    static bool isPathSeparator(int ch, HostType hostType);
53
54    // Return true if |ch| is a path separator for the current platform.
55    static inline bool isPathSeparator(int ch) {
56        return isPathSeparator(ch, HOST_TYPE);
57    }
58
59    // If |path} starts with a root prefix, return its size in bytes, or
60    // 0 otherwise. The definition of valid root prefixes depends on the
61    // value of |hostType|. For HOST_POSIX, it's any path that begins
62    // with a slash (/). For HOST_WIN32, the following prefixes are
63    // recognized:
64    //    <drive>:
65    //    <drive>:<sep>
66    //    <sep><sep>volumeName<sep>
67    static size_t rootPrefixSize(const char* path, HostType hostType);
68
69    // Return the root prefix for the current platform. See above for
70    // documentation.
71    static inline size_t rootPrefixSize(const char* path) {
72        return rootPrefixSize(path, HOST_TYPE);
73    }
74
75    // Return true iff |path| is an absolute path for a given |hostType|.
76    static bool isAbsolute(const char* path, HostType hostType);
77
78    // Return true iff |path| is an absolute path for the current host.
79    static inline bool isAbsolute(const char* path) {
80        return isAbsolute(path, HOST_TYPE);
81    }
82
83    // Decompose |path| into individual components. If |path| has a root
84    // prefix, it will always be the first component. I.e. for Posix
85    // systems this will be '/' (for absolute paths). For Win32 systems,
86    // it could be 'C:" (for a path relative to a root volume) or "C:\"
87    // for an absolute path from volume C).,
88    // On success, return true and sets |out| to a vector of strings,
89    // each one being a path component (prefix or subdirectory or file
90    // name). Directory separators do not appear in components, except
91    // for the root prefix, if any.
92    static StringVector decompose(const char* path, HostType hostType);
93
94    // Decompose |path| into individual components for the host platform.
95    // See comments above for more details.
96    static inline StringVector decompose(const char* path) {
97        return decompose(path, HOST_TYPE);
98    }
99
100    // Recompose a path from individual components into a file path string.
101    // |components| is a vector of strings, and |hostType| the target
102    // host type to use. Return a new file path string. Note that if the
103    // first component is a root prefix, it will be kept as is, i.e.:
104    //   [ 'C:', 'foo' ] -> 'C:foo' on Win32, but not Posix where it will
105    // be 'C:/foo'.
106    static String recompose(const StringVector& components,
107                                 HostType hostType);
108
109    // Recompose a path from individual components into a file path string
110    // for the current host. |components| is a vector os strings.
111    // Returns a new file path string.
112    static inline String recompose(const StringVector& components) {
113        return recompose(components, HOST_TYPE);
114    }
115
116    // Given a list of components returned by decompose(), simplify it
117    // by removing instances of '.' and '..' when that makes sense.
118    // Note that it is not possible to simplify initial instances of
119    // '..', i.e. "foo/../../bar" -> "../bar"
120    static void simplifyComponents(StringVector* components);
121};
122
123// Useful shortcuts to avoid too much typing.
124static const PathUtils::HostType kHostPosix = PathUtils::HOST_POSIX;
125static const PathUtils::HostType kHostWin32 = PathUtils::HOST_WIN32;
126static const PathUtils::HostType kHostType = PathUtils::HOST_TYPE;
127
128}  // namespace base
129}  // namespace android
130
131#endif  // ANDROID_BASE_FILES_PATH_UTIL_H
132