| 1 | |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | |
|---|
| 13 | #include <stdlib.h> |
|---|
| 14 | #include <string.h> |
|---|
| 15 | #include <limits.h> |
|---|
| 16 | |
|---|
| 17 | #include <osgDB/ConvertUTF> |
|---|
| 18 | #include <osgDB/FileNameUtils> |
|---|
| 19 | #include <osgDB/FileUtils> |
|---|
| 20 | |
|---|
| 21 | #ifdef WIN32 |
|---|
| 22 | #define _WIN32_WINNT 0x0500 |
|---|
| 23 | #include <windows.h> |
|---|
| 24 | #endif |
|---|
| 25 | |
|---|
| 26 | #if defined(__sgi) |
|---|
| 27 | #include <ctype.h> |
|---|
| 28 | #elif defined(__GNUC__) || !defined(WIN32) || defined(__MWERKS__) |
|---|
| 29 | #include <cctype> |
|---|
| 30 | using std::tolower; |
|---|
| 31 | #endif |
|---|
| 32 | |
|---|
| 33 | using namespace std; |
|---|
| 34 | |
|---|
| 35 | static const char * const PATH_SEPARATORS = "/\\"; |
|---|
| 36 | static unsigned int PATH_SEPARATORS_LEN = 2; |
|---|
| 37 | |
|---|
| 38 | |
|---|
| 39 | std::string osgDB::getFilePath(const std::string& fileName) |
|---|
| 40 | { |
|---|
| 41 | std::string::size_type slash = fileName.find_last_of(PATH_SEPARATORS); |
|---|
| 42 | if (slash==std::string::npos) return std::string(); |
|---|
| 43 | else return std::string(fileName, 0, slash); |
|---|
| 44 | } |
|---|
| 45 | |
|---|
| 46 | |
|---|
| 47 | std::string osgDB::getSimpleFileName(const std::string& fileName) |
|---|
| 48 | { |
|---|
| 49 | std::string::size_type slash = fileName.find_last_of(PATH_SEPARATORS); |
|---|
| 50 | if (slash==std::string::npos) return fileName; |
|---|
| 51 | else return std::string(fileName.begin()+slash+1,fileName.end()); |
|---|
| 52 | } |
|---|
| 53 | |
|---|
| 54 | |
|---|
| 55 | std::string osgDB::getFileExtension(const std::string& fileName) |
|---|
| 56 | { |
|---|
| 57 | std::string::size_type dot = fileName.find_last_of('.'); |
|---|
| 58 | std::string::size_type slash = fileName.find_last_of(PATH_SEPARATORS); |
|---|
| 59 | if (dot==std::string::npos || (slash!=std::string::npos && dot<slash)) return std::string(""); |
|---|
| 60 | return std::string(fileName.begin()+dot+1,fileName.end()); |
|---|
| 61 | } |
|---|
| 62 | |
|---|
| 63 | std::string osgDB::getFileExtensionIncludingDot(const std::string& fileName) |
|---|
| 64 | { |
|---|
| 65 | std::string::size_type dot = fileName.find_last_of('.'); |
|---|
| 66 | std::string::size_type slash = fileName.find_last_of(PATH_SEPARATORS); |
|---|
| 67 | if (dot==std::string::npos || (slash!=std::string::npos && dot<slash)) return std::string(""); |
|---|
| 68 | return std::string(fileName.begin()+dot,fileName.end()); |
|---|
| 69 | } |
|---|
| 70 | |
|---|
| 71 | std::string osgDB::convertFileNameToWindowsStyle(const std::string& fileName) |
|---|
| 72 | { |
|---|
| 73 | std::string new_fileName(fileName); |
|---|
| 74 | |
|---|
| 75 | std::string::size_type slash = 0; |
|---|
| 76 | while( (slash=new_fileName.find_first_of(UNIX_PATH_SEPARATOR,slash)) != std::string::npos) |
|---|
| 77 | { |
|---|
| 78 | new_fileName[slash]=WINDOWS_PATH_SEPARATOR; |
|---|
| 79 | } |
|---|
| 80 | return new_fileName; |
|---|
| 81 | } |
|---|
| 82 | |
|---|
| 83 | std::string osgDB::convertFileNameToUnixStyle(const std::string& fileName) |
|---|
| 84 | { |
|---|
| 85 | std::string new_fileName(fileName); |
|---|
| 86 | |
|---|
| 87 | std::string::size_type slash = 0; |
|---|
| 88 | while( (slash=new_fileName.find_first_of(WINDOWS_PATH_SEPARATOR,slash)) != std::string::npos) |
|---|
| 89 | { |
|---|
| 90 | new_fileName[slash]=UNIX_PATH_SEPARATOR; |
|---|
| 91 | } |
|---|
| 92 | |
|---|
| 93 | return new_fileName; |
|---|
| 94 | } |
|---|
| 95 | |
|---|
| 96 | char osgDB::getNativePathSeparator() |
|---|
| 97 | { |
|---|
| 98 | #if defined(WIN32) && !defined(__CYGWIN__) |
|---|
| 99 | return WINDOWS_PATH_SEPARATOR; |
|---|
| 100 | #else |
|---|
| 101 | return UNIX_PATH_SEPARATOR; |
|---|
| 102 | #endif |
|---|
| 103 | } |
|---|
| 104 | |
|---|
| 105 | bool osgDB::isFileNameNativeStyle(const std::string& fileName) |
|---|
| 106 | { |
|---|
| 107 | #if defined(WIN32) && !defined(__CYGWIN__) |
|---|
| 108 | return fileName.find(UNIX_PATH_SEPARATOR) == std::string::npos; |
|---|
| 109 | #else |
|---|
| 110 | return fileName.find(WINDOWS_PATH_SEPARATOR) == std::string::npos; |
|---|
| 111 | #endif |
|---|
| 112 | } |
|---|
| 113 | |
|---|
| 114 | std::string osgDB::convertFileNameToNativeStyle(const std::string& fileName) |
|---|
| 115 | { |
|---|
| 116 | #if defined(WIN32) && !defined(__CYGWIN__) |
|---|
| 117 | return convertFileNameToWindowsStyle(fileName); |
|---|
| 118 | #else |
|---|
| 119 | return convertFileNameToUnixStyle(fileName); |
|---|
| 120 | #endif |
|---|
| 121 | } |
|---|
| 122 | |
|---|
| 123 | |
|---|
| 124 | |
|---|
| 125 | std::string osgDB::getLowerCaseFileExtension(const std::string& filename) |
|---|
| 126 | { |
|---|
| 127 | return convertToLowerCase(osgDB::getFileExtension(filename)); |
|---|
| 128 | } |
|---|
| 129 | |
|---|
| 130 | std::string osgDB::convertToLowerCase(const std::string& str) |
|---|
| 131 | { |
|---|
| 132 | std::string lowcase_str(str); |
|---|
| 133 | for(std::string::iterator itr=lowcase_str.begin(); |
|---|
| 134 | itr!=lowcase_str.end(); |
|---|
| 135 | ++itr) |
|---|
| 136 | { |
|---|
| 137 | *itr = tolower(*itr); |
|---|
| 138 | } |
|---|
| 139 | return lowcase_str; |
|---|
| 140 | } |
|---|
| 141 | |
|---|
| 142 | |
|---|
| 143 | std::string osgDB::getNameLessExtension(const std::string& fileName) |
|---|
| 144 | { |
|---|
| 145 | std::string::size_type dot = fileName.find_last_of('.'); |
|---|
| 146 | std::string::size_type slash = fileName.find_last_of(PATH_SEPARATORS); |
|---|
| 147 | if (dot==std::string::npos || (slash!=std::string::npos && dot<slash)) return fileName; |
|---|
| 148 | return std::string(fileName.begin(),fileName.begin()+dot); |
|---|
| 149 | } |
|---|
| 150 | |
|---|
| 151 | |
|---|
| 152 | |
|---|
| 153 | std::string osgDB::getNameLessAllExtensions(const std::string& fileName) |
|---|
| 154 | { |
|---|
| 155 | |
|---|
| 156 | std::string::size_type startPos = fileName.find_last_of(PATH_SEPARATORS); |
|---|
| 157 | if (startPos == std::string::npos) startPos = 0; |
|---|
| 158 | std::string::size_type dot = fileName.find_first_of('.', startPos); |
|---|
| 159 | if (dot==std::string::npos) return fileName; |
|---|
| 160 | return std::string(fileName.begin(),fileName.begin()+dot); |
|---|
| 161 | } |
|---|
| 162 | |
|---|
| 163 | std::string osgDB::getStrippedName(const std::string& fileName) |
|---|
| 164 | { |
|---|
| 165 | std::string simpleName = getSimpleFileName(fileName); |
|---|
| 166 | return getNameLessExtension( simpleName ); |
|---|
| 167 | } |
|---|
| 168 | |
|---|
| 169 | |
|---|
| 170 | bool osgDB::equalCaseInsensitive(const std::string& lhs,const std::string& rhs) |
|---|
| 171 | { |
|---|
| 172 | if (lhs.size()!=rhs.size()) return false; |
|---|
| 173 | std::string::const_iterator litr = lhs.begin(); |
|---|
| 174 | std::string::const_iterator ritr = rhs.begin(); |
|---|
| 175 | while (litr!=lhs.end()) |
|---|
| 176 | { |
|---|
| 177 | if (tolower(*litr)!=tolower(*ritr)) return false; |
|---|
| 178 | ++litr; |
|---|
| 179 | ++ritr; |
|---|
| 180 | } |
|---|
| 181 | return true; |
|---|
| 182 | } |
|---|
| 183 | |
|---|
| 184 | bool osgDB::equalCaseInsensitive(const std::string& lhs,const char* rhs) |
|---|
| 185 | { |
|---|
| 186 | if (rhs==NULL || lhs.size()!=strlen(rhs)) return false; |
|---|
| 187 | std::string::const_iterator litr = lhs.begin(); |
|---|
| 188 | const char* cptr = rhs; |
|---|
| 189 | while (litr!=lhs.end()) |
|---|
| 190 | { |
|---|
| 191 | if (tolower(*litr)!=tolower(*cptr)) return false; |
|---|
| 192 | ++litr; |
|---|
| 193 | ++cptr; |
|---|
| 194 | } |
|---|
| 195 | return true; |
|---|
| 196 | } |
|---|
| 197 | |
|---|
| 198 | |
|---|
| 199 | |
|---|
| 200 | bool osgDB::containsServerAddress(const std::string& filename) |
|---|
| 201 | { |
|---|
| 202 | |
|---|
| 203 | std::string::size_type pos(filename.find("://")); |
|---|
| 204 | if (pos == std::string::npos) |
|---|
| 205 | return false; |
|---|
| 206 | std::string proto(filename.substr(0, pos)); |
|---|
| 207 | |
|---|
| 208 | return Registry::instance()->isProtocolRegistered(proto); |
|---|
| 209 | } |
|---|
| 210 | |
|---|
| 211 | std::string osgDB::getServerProtocol(const std::string& filename) |
|---|
| 212 | { |
|---|
| 213 | std::string::size_type pos(filename.find("://")); |
|---|
| 214 | if (pos != std::string::npos) |
|---|
| 215 | return filename.substr(0,pos); |
|---|
| 216 | |
|---|
| 217 | return ""; |
|---|
| 218 | } |
|---|
| 219 | |
|---|
| 220 | std::string osgDB::getServerAddress(const std::string& filename) |
|---|
| 221 | { |
|---|
| 222 | std::string::size_type pos(filename.find("://")); |
|---|
| 223 | |
|---|
| 224 | if (pos != std::string::npos) |
|---|
| 225 | { |
|---|
| 226 | std::string::size_type pos_slash = filename.find_first_of('/',pos+3); |
|---|
| 227 | if (pos_slash!=std::string::npos) |
|---|
| 228 | { |
|---|
| 229 | return filename.substr(pos+3,pos_slash-pos-3); |
|---|
| 230 | } |
|---|
| 231 | else |
|---|
| 232 | { |
|---|
| 233 | return filename.substr(pos+3,std::string::npos); |
|---|
| 234 | } |
|---|
| 235 | } |
|---|
| 236 | return ""; |
|---|
| 237 | } |
|---|
| 238 | |
|---|
| 239 | std::string osgDB::getServerFileName(const std::string& filename) |
|---|
| 240 | { |
|---|
| 241 | std::string::size_type pos(filename.find("://")); |
|---|
| 242 | |
|---|
| 243 | if (pos != std::string::npos) |
|---|
| 244 | { |
|---|
| 245 | std::string::size_type pos_slash = filename.find_first_of('/',pos+3); |
|---|
| 246 | if (pos_slash!=std::string::npos) |
|---|
| 247 | { |
|---|
| 248 | return filename.substr(pos_slash+1,std::string::npos); |
|---|
| 249 | } |
|---|
| 250 | else |
|---|
| 251 | { |
|---|
| 252 | return ""; |
|---|
| 253 | } |
|---|
| 254 | |
|---|
| 255 | } |
|---|
| 256 | return filename; |
|---|
| 257 | } |
|---|
| 258 | |
|---|
| 259 | std::string osgDB::concatPaths(const std::string& left, const std::string& right) |
|---|
| 260 | { |
|---|
| 261 | #if defined(WIN32) && !defined(__CYGWIN__) |
|---|
| 262 | const char delimiterNative = WINDOWS_PATH_SEPARATOR; |
|---|
| 263 | const char delimiterForeign = UNIX_PATH_SEPARATOR; |
|---|
| 264 | #else |
|---|
| 265 | const char delimiterNative = UNIX_PATH_SEPARATOR; |
|---|
| 266 | const char delimiterForeign = WINDOWS_PATH_SEPARATOR; |
|---|
| 267 | #endif |
|---|
| 268 | |
|---|
| 269 | if(left.empty()) |
|---|
| 270 | { |
|---|
| 271 | return(right); |
|---|
| 272 | } |
|---|
| 273 | char lastChar = left[left.size() - 1]; |
|---|
| 274 | |
|---|
| 275 | if(lastChar == delimiterNative) |
|---|
| 276 | { |
|---|
| 277 | return left + right; |
|---|
| 278 | } |
|---|
| 279 | else if(lastChar == delimiterForeign) |
|---|
| 280 | { |
|---|
| 281 | return left.substr(0, left.size() - 1) + delimiterNative + right; |
|---|
| 282 | } |
|---|
| 283 | else |
|---|
| 284 | { |
|---|
| 285 | return left + delimiterNative + right; |
|---|
| 286 | } |
|---|
| 287 | } |
|---|
| 288 | |
|---|
| 289 | std::string osgDB::getRealPath(const std::string& path) |
|---|
| 290 | { |
|---|
| 291 | #if defined(WIN32) && !defined(__CYGWIN__) |
|---|
| 292 | |
|---|
| 293 | #ifdef OSG_USE_UTF8_FILENAME |
|---|
| 294 | |
|---|
| 295 | std::wstring wpath = convertUTF8toUTF16(path); |
|---|
| 296 | wchar_t retbuf[MAX_PATH + 1]; |
|---|
| 297 | wchar_t tempbuf1[MAX_PATH + 1]; |
|---|
| 298 | if (GetFullPathNameW(wpath.c_str(), _countof(retbuf), retbuf, NULL)==0) { |
|---|
| 299 | return path; |
|---|
| 300 | } |
|---|
| 301 | |
|---|
| 302 | if ((retbuf[1] == ':') && iswlower(retbuf[0])) |
|---|
| 303 | retbuf[0] = towupper(retbuf[0]); |
|---|
| 304 | if (fileExists(convertUTF16toUTF8(retbuf))) |
|---|
| 305 | { |
|---|
| 306 | |
|---|
| 307 | GetShortPathNameW(retbuf, tempbuf1, _countof(tempbuf1)); |
|---|
| 308 | GetLongPathNameW(tempbuf1, retbuf, _countof(retbuf)); |
|---|
| 309 | return convertUTF16toUTF8(retbuf); |
|---|
| 310 | } |
|---|
| 311 | else |
|---|
| 312 | { |
|---|
| 313 | std::string retbuf8 = convertUTF16toUTF8(retbuf); |
|---|
| 314 | |
|---|
| 315 | std::string FilePath = getFilePath(retbuf8); |
|---|
| 316 | wchar_t tempbuf2[MAX_PATH + 1]; |
|---|
| 317 | if (0 == GetShortPathNameW(convertUTF8toUTF16(FilePath).c_str(), tempbuf1, _countof(tempbuf1))) |
|---|
| 318 | return retbuf8; |
|---|
| 319 | if (0 == GetLongPathNameW(tempbuf1, tempbuf2, _countof(tempbuf2))) |
|---|
| 320 | return retbuf8; |
|---|
| 321 | FilePath = convertUTF16toUTF8(tempbuf2); |
|---|
| 322 | FilePath += WINDOWS_PATH_SEPARATOR; |
|---|
| 323 | FilePath.append(getSimpleFileName(retbuf8)); |
|---|
| 324 | return FilePath; |
|---|
| 325 | } |
|---|
| 326 | |
|---|
| 327 | #else |
|---|
| 328 | |
|---|
| 329 | |
|---|
| 330 | char retbuf[MAX_PATH + 1]; |
|---|
| 331 | char tempbuf1[MAX_PATH + 1]; |
|---|
| 332 | GetFullPathName(path.c_str(), sizeof(retbuf), retbuf, NULL); |
|---|
| 333 | |
|---|
| 334 | if ((retbuf[1] == ':') && islower(retbuf[0])) |
|---|
| 335 | retbuf[0] = _toupper(retbuf[0]); |
|---|
| 336 | if (fileExists(std::string(retbuf))) |
|---|
| 337 | { |
|---|
| 338 | |
|---|
| 339 | GetShortPathName(retbuf, tempbuf1, sizeof(tempbuf1)); |
|---|
| 340 | GetLongPathName(tempbuf1, retbuf, sizeof(retbuf)); |
|---|
| 341 | return std::string(retbuf); |
|---|
| 342 | } |
|---|
| 343 | else |
|---|
| 344 | { |
|---|
| 345 | |
|---|
| 346 | std::string FilePath = getFilePath(retbuf); |
|---|
| 347 | char tempbuf2[MAX_PATH + 1]; |
|---|
| 348 | if (0 == GetShortPathName(FilePath.c_str(), tempbuf1, sizeof(tempbuf1))) |
|---|
| 349 | return std::string(retbuf); |
|---|
| 350 | if (0 == GetLongPathName(tempbuf1, tempbuf2, sizeof(tempbuf2))) |
|---|
| 351 | return std::string(retbuf); |
|---|
| 352 | FilePath = std::string(tempbuf2); |
|---|
| 353 | FilePath += WINDOWS_PATH_SEPARATOR; |
|---|
| 354 | FilePath.append(getSimpleFileName(std::string(retbuf))); |
|---|
| 355 | return FilePath; |
|---|
| 356 | } |
|---|
| 357 | #endif |
|---|
| 358 | |
|---|
| 359 | #else |
|---|
| 360 | char resolved_path[PATH_MAX]; |
|---|
| 361 | char* result = realpath(path.c_str(), resolved_path); |
|---|
| 362 | |
|---|
| 363 | if (result) return std::string(resolved_path); |
|---|
| 364 | else return path; |
|---|
| 365 | #endif |
|---|
| 366 | } |
|---|
| 367 | |
|---|
| 368 | namespace osgDB |
|---|
| 369 | { |
|---|
| 370 | |
|---|
| 371 | |
|---|
| 372 | class PathIterator { |
|---|
| 373 | public: |
|---|
| 374 | PathIterator(const std::string & v); |
|---|
| 375 | bool valid() const { return start!=end; } |
|---|
| 376 | PathIterator & operator++(); |
|---|
| 377 | std::string operator*(); |
|---|
| 378 | |
|---|
| 379 | protected: |
|---|
| 380 | std::string::const_iterator end; |
|---|
| 381 | std::string::const_iterator start; |
|---|
| 382 | std::string::const_iterator stop; |
|---|
| 383 | |
|---|
| 384 | |
|---|
| 385 | std::string::const_iterator skipSeparators(std::string::const_iterator it); |
|---|
| 386 | std::string::const_iterator next(std::string::const_iterator it); |
|---|
| 387 | }; |
|---|
| 388 | |
|---|
| 389 | } |
|---|
| 390 | |
|---|
| 391 | osgDB::PathIterator::PathIterator(const std::string & v) : end(v.end()), start(v.begin()), stop(v.begin()) { operator++(); } |
|---|
| 392 | osgDB::PathIterator & osgDB::PathIterator::operator++() |
|---|
| 393 | { |
|---|
| 394 | if (!valid()) return *this; |
|---|
| 395 | start = skipSeparators(stop); |
|---|
| 396 | if (start != end) stop = next(start); |
|---|
| 397 | return *this; |
|---|
| 398 | } |
|---|
| 399 | std::string osgDB::PathIterator::operator*() |
|---|
| 400 | { |
|---|
| 401 | if (!valid()) return std::string(); |
|---|
| 402 | return std::string(start, stop); |
|---|
| 403 | } |
|---|
| 404 | |
|---|
| 405 | std::string::const_iterator osgDB::PathIterator::skipSeparators(std::string::const_iterator it) |
|---|
| 406 | { |
|---|
| 407 | for (; it!=end && std::find_first_of(it, it+1, PATH_SEPARATORS, PATH_SEPARATORS+PATH_SEPARATORS_LEN) != it+1; ++it) {} |
|---|
| 408 | return it; |
|---|
| 409 | } |
|---|
| 410 | |
|---|
| 411 | std::string::const_iterator osgDB::PathIterator::next(std::string::const_iterator it) |
|---|
| 412 | { |
|---|
| 413 | return std::find_first_of(it, end, PATH_SEPARATORS, PATH_SEPARATORS+PATH_SEPARATORS_LEN); |
|---|
| 414 | } |
|---|
| 415 | |
|---|
| 416 | void osgDB::getPathElements(const std::string& path, std::vector<std::string> & out_elements) |
|---|
| 417 | { |
|---|
| 418 | out_elements.clear(); |
|---|
| 419 | for(osgDB::PathIterator it(path); it.valid(); ++it) out_elements.push_back(*it); |
|---|
| 420 | } |
|---|
| 421 | |
|---|
| 422 | |
|---|
| 423 | std::string osgDB::getPathRoot(const std::string& path) { |
|---|
| 424 | |
|---|
| 425 | if (path.empty()) return ""; |
|---|
| 426 | if (path[0] == '/') return "/"; |
|---|
| 427 | |
|---|
| 428 | if (path.length()<2) return ""; |
|---|
| 429 | if (path[1] == ':') return path.substr(0, 2); |
|---|
| 430 | return ""; |
|---|
| 431 | } |
|---|
| 432 | |
|---|
| 433 | bool osgDB::isAbsolutePath(const std::string& path) { |
|---|
| 434 | |
|---|
| 435 | if (path.empty()) return false; |
|---|
| 436 | if (path[0] == '/') return true; |
|---|
| 437 | |
|---|
| 438 | if (path.length()<2) return false; |
|---|
| 439 | return path[1] == ':'; |
|---|
| 440 | } |
|---|
| 441 | |
|---|
| 442 | std::string osgDB::getPathRelative(const std::string& from, const std::string& to) |
|---|
| 443 | { |
|---|
| 444 | |
|---|
| 445 | |
|---|
| 446 | |
|---|
| 447 | |
|---|
| 448 | |
|---|
| 449 | |
|---|
| 450 | |
|---|
| 451 | |
|---|
| 452 | |
|---|
| 453 | |
|---|
| 454 | |
|---|
| 455 | const std::string root = getPathRoot(from); |
|---|
| 456 | if (root != getPathRoot(to)) { |
|---|
| 457 | OSG_INFO << "Cannot relativise paths. From=" << from << ", To=" << to << ". Returning 'to' unchanged." << std::endl; |
|---|
| 458 | |
|---|
| 459 | return osgDB::getSimpleFileName(to); |
|---|
| 460 | } |
|---|
| 461 | |
|---|
| 462 | |
|---|
| 463 | PathIterator itFrom(from), itTo(to); |
|---|
| 464 | |
|---|
| 465 | |
|---|
| 466 | std::string res(root == "/" ? "/" : ""); |
|---|
| 467 | for(; itFrom.valid() && itTo.valid() && *itFrom==*itTo; ++itFrom, ++itTo) {} |
|---|
| 468 | |
|---|
| 469 | |
|---|
| 470 | for(; itFrom.valid(); ++itFrom) res += "../"; |
|---|
| 471 | |
|---|
| 472 | |
|---|
| 473 | for(; itTo.valid(); ++itTo) res += *itTo + "/"; |
|---|
| 474 | |
|---|
| 475 | |
|---|
| 476 | if (!res.empty() && std::find_first_of(res.rbegin(), res.rbegin()+1, PATH_SEPARATORS, PATH_SEPARATORS+PATH_SEPARATORS_LEN) != res.rbegin()+1) |
|---|
| 477 | { |
|---|
| 478 | return res.substr(0, res.length()-1); |
|---|
| 479 | } |
|---|
| 480 | return res; |
|---|
| 481 | } |
|---|
| 482 | |
|---|
| 483 | |
|---|
| 484 | |
|---|
| 485 | |
|---|
| 486 | |
|---|
| 487 | |
|---|
| 488 | |
|---|
| 489 | |
|---|
| 490 | |
|---|
| 491 | |
|---|