* perform path simplifications for . and .. */
| 2527 | * perform path simplifications for . and .. |
| 2528 | */ |
| 2529 | std::string simplifyPath(std::string path) |
| 2530 | { |
| 2531 | if (path.empty()) |
| 2532 | return path; |
| 2533 | |
| 2534 | std::string::size_type pos; |
| 2535 | |
| 2536 | // replace backslash separators |
| 2537 | std::replace(path.begin(), path.end(), '\\', '/'); |
| 2538 | |
| 2539 | const bool unc(path.compare(0,2,"//") == 0); |
| 2540 | |
| 2541 | // replace "//" with "/" |
| 2542 | pos = 0; |
| 2543 | while ((pos = path.find("//",pos)) != std::string::npos) { |
| 2544 | path.erase(pos,1); |
| 2545 | } |
| 2546 | |
| 2547 | // remove "./" |
| 2548 | pos = 0; |
| 2549 | while ((pos = path.find("./",pos)) != std::string::npos) { |
| 2550 | if (pos == 0 || path[pos - 1U] == '/') |
| 2551 | path.erase(pos,2); |
| 2552 | else |
| 2553 | pos += 2; |
| 2554 | } |
| 2555 | |
| 2556 | // remove trailing dot if path ends with "/." |
| 2557 | if (endsWith(path,"/.")) |
| 2558 | path.erase(path.size()-1); |
| 2559 | |
| 2560 | // simplify ".." |
| 2561 | pos = 1; // don't simplify ".." if path starts with that |
| 2562 | while ((pos = path.find("/..", pos)) != std::string::npos) { |
| 2563 | // not end of path, then string must be "/../" |
| 2564 | if (pos + 3 < path.size() && path[pos + 3] != '/') { |
| 2565 | ++pos; |
| 2566 | continue; |
| 2567 | } |
| 2568 | // get previous subpath |
| 2569 | std::string::size_type pos1 = path.rfind('/', pos - 1U); |
| 2570 | if (pos1 == std::string::npos) { |
| 2571 | pos1 = 0; |
| 2572 | } else { |
| 2573 | pos1 += 1U; |
| 2574 | } |
| 2575 | const std::string previousSubPath = path.substr(pos1, pos - pos1); |
| 2576 | if (previousSubPath == "..") { |
| 2577 | // don't simplify |
| 2578 | ++pos; |
| 2579 | } else { |
| 2580 | // remove previous subpath and ".." |
| 2581 | path.erase(pos1, pos - pos1 + 4); |
| 2582 | if (path.empty()) |
| 2583 | path = "."; |
| 2584 | // update pos |
| 2585 | pos = (pos1 == 0) ? 1 : (pos1 - 1); |
| 2586 | } |