1 /* 2 * Copyright 2011-2013 Arx Libertatis Team (see the AUTHORS file) 3 * 4 * This file is part of Arx Libertatis. 5 * 6 * Arx Libertatis is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * Arx Libertatis is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with Arx Libertatis. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #ifndef ARX_IO_RESOURCE_RESOURCEPATH_H 21 #define ARX_IO_RESOURCE_RESOURCEPATH_H 22 23 #include <string> 24 #include <ostream> 25 26 namespace res { 27 28 class path { 29 30 private: 31 32 std::string pathstr; 33 34 #ifdef ARX_DEBUG 35 void check() const; 36 #else check()37 inline void check() const { } 38 #endif 39 40 static path resolve(const path & base, const path & branch); 41 42 public: 43 44 static const char dir_or_ext_sep[]; 45 static const char dir_sep = '/'; 46 static const char ext_sep = '.'; 47 path()48 path() { } path(const path & other)49 path(const path & other) : pathstr(other.pathstr) { } path(const std::string & str)50 /* implicit */ path(const std::string & str) : pathstr(str) { check(); } path(const char * str)51 /* implicit */ path(const char * str) : pathstr(str) { check(); } 52 53 inline path & operator=(const path & other) { 54 return (pathstr = other.pathstr, *this); 55 } 56 57 inline path & operator=(const std::string & str) { 58 return (pathstr = str, check(), *this); 59 } 60 61 inline path & operator=(const char * str) { 62 return (pathstr = str, check(), *this); 63 } 64 65 path operator/(const path & other) const; 66 67 path & operator/=(const path & other); 68 string()69 inline const std::string & string() const { 70 return pathstr; 71 } 72 73 /*! 74 * If pathstr contains a slash, return everything preceding it. 75 * Otherwise, return path(). 76 */ parent()77 inline path parent() const { 78 if(has_info()) { 79 size_t dirpos = pathstr.find_last_of(dir_sep); 80 return (dirpos == std::string::npos) ? path() : path(pathstr.substr(0, dirpos)); 81 } else { 82 return empty() ? path("..") : path(pathstr + dir_sep + ".."); 83 } 84 } 85 86 /*! 87 * return *this = parent() 88 */ up()89 path & up() { 90 if(has_info()) { 91 size_t dirpos = pathstr.find_last_of(dir_sep); 92 return (((dirpos != std::string::npos) ? pathstr.resize(dirpos) : pathstr.clear()), *this); 93 } else { 94 return ((empty() ? pathstr = ".." : (pathstr += dir_sep).append("..")), *this); 95 } 96 } 97 98 /*! 99 * If pathstr contains a slash, return everything following it. 100 * Otherwise, return pathstr. 101 */ filename()102 inline std::string filename() const { 103 size_t dirpos = pathstr.find_last_of(dir_sep); 104 return (dirpos == std::string::npos) ? pathstr : pathstr.substr(dirpos + 1); 105 } 106 107 /*! 108 * If filename() constains a dot, return everything in filename() preceeding the dot. 109 * Otherwise, return filename(). 110 */ 111 std::string basename() const; 112 113 /*! 114 * If filename() constains a dot, return dot and everything folowing it. 115 * Otherwise, return std::string(). 116 */ 117 std::string ext() const; 118 empty()119 inline bool empty() const { 120 return pathstr.empty(); 121 } 122 123 //! @return pathstr == other.pathstr 124 inline bool operator==(const path & other) const { 125 return (pathstr == other.pathstr); 126 } 127 128 //! @return pathstr == str 129 inline bool operator==(const std::string & str) const { 130 return (pathstr == str); 131 } 132 133 /*! 134 * @return pathstr == str 135 * This overload is neccessary so comparing with string constants isn't ambigous 136 */ 137 inline bool operator==(const char * str) const { 138 return !pathstr.compare(0, pathstr.length(), str); 139 } 140 141 //! @return pathstr != other.pathstr 142 inline bool operator!=(const path & other) const { 143 return (pathstr != other.pathstr); 144 } 145 146 //! @return pathstr != str 147 inline bool operator!=(const std::string & str) const { 148 return (pathstr != str); 149 } 150 151 /*! 152 * @return pathstr != str 153 * This overload is neccessary so comparing with string constants isn't ambigous 154 */ 155 inline bool operator!=(const char * str) const { 156 return pathstr.compare(0, pathstr.length(), str) != 0; 157 } 158 159 /*! 160 * To allow path being used in std::map, etc 161 * @return pathstr < other.pathstr 162 */ 163 inline bool operator<(const path & other) const { 164 return (pathstr < other.pathstr); 165 } 166 167 /*! 168 * If ext starts with a dot, return *this = remove_ext().append(ext). 169 * Otherwise, return *this = remove_ext().append('.').append(ext). 170 */ 171 path & set_ext(const std::string & ext); 172 173 /*! 174 * If pathstr constains a dot after the last slash, return everything preceeding the last dot 175 * @return *this 176 */ 177 path & remove_ext(); 178 179 //! *this = parent() / filename; 180 path & set_filename(const std::string & filename); 181 182 path & set_basename(const std::string & basename); 183 184 //! @return set_basename(get_basename() + basename_part) 185 path & append_basename(const std::string & basename_part); 186 swap(path & other)187 inline void swap(path & other) { 188 pathstr.swap(other.pathstr); 189 } 190 191 //! return str.empty() ? !ext().empty() : ext() == str || ext.substr(1) == str(); 192 bool has_ext(const std::string & str = std::string()) const; 193 is_up()194 inline bool is_up() const { 195 return (pathstr.length() == 2 && pathstr[0] == '.' && pathstr[1] == '.') 196 || (pathstr.length() >= 3 && pathstr[0] == '.' && pathstr[1] == '.' && pathstr[2] == dir_sep); 197 } 198 has_info()199 inline bool has_info() const { 200 return !pathstr.empty() && !(pathstr.length() == 2 && pathstr[0] == '.' && pathstr[1] == '.') 201 && !(pathstr.length() >= 3 && pathstr[pathstr.length() - 1] == '.' 202 && pathstr[pathstr.length() - 2] == '.' && pathstr[pathstr.length() - 3] == dir_sep); 203 } 204 205 static path load(const std::string & str); 206 207 /*! 208 * Append a string to the paths filename component 209 * 210 * The appended string must not contain a path seperator or be "." or "..". 211 */ 212 path & append(const std::string & str); 213 214 //! @return append(str) 215 path & operator+=(const std::string & str) { append(str); return *this; } 216 217 //! @return path(*this).append(str) 218 path operator+(const std::string & str) const { 219 return path(*this) += str; 220 } 221 clear()222 inline void clear() { pathstr.clear(); } 223 224 }; 225 226 inline path operator/(const char * a, const path & b) { 227 return path(a) / b; 228 } 229 230 inline path operator/(const std::string & a, const path & b) { 231 return path(a) / b; 232 } 233 234 inline bool operator==(const std::string & a, const path & b) { 235 return (b == a); 236 } 237 238 inline bool operator==(const char * a, const path & b) { 239 return (b == a); 240 } 241 242 inline bool operator!=(const std::string & a, const path & b) { 243 return (b != a); 244 } 245 246 inline bool operator!=(const char * a, const path & b) { 247 return (b != a); 248 } 249 250 inline std::ostream & operator<<(std::ostream & strm, const path & path) { 251 return strm << '"' << path.string() << '"'; 252 } 253 254 } // namespace fs 255 256 #endif // ARX_IO_RESOURCE_RESOURCEPATH_H 257