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