1 #pragma once
2 
3 #include "ppsspp_config.h"
4 
5 #include <string>
6 
7 #if defined(__APPLE__)
8 
9 #if TARGET_OS_IPHONE
10 #define HOST_IS_CASE_SENSITIVE 1
11 #elif TARGET_IPHONE_SIMULATOR
12 #define HOST_IS_CASE_SENSITIVE 0
13 #else
14 // Mac OSX case sensitivity defaults off, but is user configurable (when
15 // creating a filesytem), so assume the worst:
16 #define HOST_IS_CASE_SENSITIVE 1
17 #endif
18 
19 #elif defined(_WIN32)
20 #define HOST_IS_CASE_SENSITIVE 0
21 
22 #else  // Android, Linux, BSD (and the rest?)
23 #define HOST_IS_CASE_SENSITIVE 1
24 
25 #endif
26 
27 enum class PathType {
28 	UNDEFINED = 0,
29 	NATIVE = 1,  // Can be relative.
30 	CONTENT_URI = 2,  // Android only. Can only be absolute!
31 	HTTP = 3,  // http://, https://
32 };
33 
34 // Windows paths are always stored with '/' slashes in a Path.
35 // On .ToWString(), they are flipped back to '\'.
36 
37 class Path {
38 private:
39 	void Init(const std::string &str);
40 
41 public:
Path()42 	Path() : type_(PathType::UNDEFINED) {}
43 	explicit Path(const std::string &str);
44 
45 #if PPSSPP_PLATFORM(WINDOWS)
46 	explicit Path(const std::wstring &str);
47 #endif
48 
Type()49 	PathType Type() const {
50 		return type_;
51 	}
52 
Valid()53 	bool Valid() const { return !path_.empty(); }
IsRoot()54 	bool IsRoot() const { return path_ == "/"; }  // Special value - only path that can end in a slash.
55 
56 	// Some std::string emulation for simplicity.
empty()57 	bool empty() const { return !Valid(); }
clear()58 	void clear() {
59 		type_ = PathType::UNDEFINED;
60 		path_.clear();
61 	}
size()62 	size_t size() const {
63 		return path_.size();
64 	}
65 
66 	// WARNING: Potentially unsafe usage, if it's not NATIVE.
c_str()67 	const char *c_str() const {
68 		return path_.c_str();
69 	}
70 
71 	bool IsAbsolute() const;
72 
73 	// Returns a path extended with a subdirectory.
74 	Path operator /(const std::string &subdir) const;
75 
76 	// Navigates down into a subdir.
77 	void operator /=(const std::string &subdir);
78 
79 	// File extension manipulation.
80 	Path WithExtraExtension(const std::string &ext) const;
81 	Path WithReplacedExtension(const std::string &oldExtension, const std::string &newExtension) const;
82 	Path WithReplacedExtension(const std::string &newExtension) const;
83 
84 	// Removes the last component.
85 	std::string GetFilename() const;  // Really, GetLastComponent. Could be a file or directory. Includes the extension.
86 	std::string GetFileExtension() const;  // Always lowercase return. Includes the dot.
87 	std::string GetDirectory() const;
88 
89 	const std::string &ToString() const;
90 
91 #if PPSSPP_PLATFORM(WINDOWS)
92 	std::wstring ToWString() const;
93 #endif
94 
95 	std::string ToVisualString() const;
96 
97 	bool CanNavigateUp() const;
98 	Path NavigateUp() const;
99 
100 	// Navigates as far up as possible from this path. If not possible to navigate upwards, returns the same path.
101 	// Not actually always the root of the volume, especially on systems like Mac and Linux where things are often mounted.
102 	// For Android directory trees, navigates to the root of the tree.
103 	Path GetRootVolume() const;
104 
105 	bool ComputePathTo(const Path &other, std::string &path) const;
106 
107 	bool operator ==(const Path &other) const {
108 		return path_ == other.path_ && type_ == other.type_;
109 	}
110 	bool operator !=(const Path &other) const {
111 		return path_ != other.path_ || type_ != other.type_;
112 	}
113 
114 	bool FilePathContains(const std::string &needle) const;
115 
116 	bool StartsWith(const Path &other) const;
117 
118 	bool operator <(const Path &other) const {
119 		return path_ < other.path_;
120 	}
121 
122 private:
123 	// The internal representation is currently always the plain string.
124 	// For CPU efficiency we could keep an AndroidStorageContentURI too,
125 	// but I don't think the encode/decode cost is significant. We simply create
126 	// those for processing instead.
127 	std::string path_;
128 
129 	PathType type_;
130 };
131 
132 
133 // Utility function for fixing the case of paths. Only present on Unix-like systems.
134 
135 #if HOST_IS_CASE_SENSITIVE
136 
137 enum FixPathCaseBehavior {
138 	FPC_FILE_MUST_EXIST,  // all path components must exist (rmdir, move from)
139 	FPC_PATH_MUST_EXIST,  // all except the last one must exist - still tries to fix last one (fopen, move to)
140 	FPC_PARTIAL_ALLOWED,  // don't care how many exist (mkdir recursive)
141 };
142 
143 bool FixPathCase(const Path &basePath, std::string &path, FixPathCaseBehavior behavior);
144 
145 #endif
146