reapack

Package manager for REAPER
Log | Files | Refs | Submodules | README | LICENSE

commit 6d9059656c08bff714b51d4ed0b56893d17b5d36
parent 1b2d79ede5f7001e98607dd35f440eef487e16e2
Author: cfillion <cfillion@users.noreply.github.com>
Date:   Tue, 26 Nov 2019 15:34:02 -0800

win32: add support for UNC paths [p=2207357]

Diffstat:
Msrc/path.cpp | 106+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/path.hpp | 10++++++++--
Mtest/path.cpp | 37++++++++++++++++++++++++++++---------
3 files changed, 94 insertions(+), 59 deletions(-)

diff --git a/src/path.cpp b/src/path.cpp @@ -40,50 +40,54 @@ const Path Path::REGISTRY = Path::DATA + "registry.db"; Path Path::s_root; -static std::vector<std::string> Split(const std::string &input, bool *absolute) +static std::vector<std::string> Split(const std::string &input, int *attributes) { std::vector<std::string> list; + *attributes = 0; - const auto append = [&list, absolute] (const std::string &part) { - if(part.empty() || part == DOT) - return; + size_t last = 0; -#ifdef _WIN32 - if(list.empty() && part.size() == 2 && isalpha(part[0]) && part[1] == ':') - *absolute = true; -#else - (void)absolute; -#endif - - list.push_back(part); - }; - - size_t last = 0, size = input.size(); - - while(last < size) { + while(last < input.size()) { const size_t pos = input.find_first_of("\\/", last); - if(pos == std::string::npos) { - append(input.substr(last)); - break; - } - else if(last + pos == 0) { + if(last + pos == 0) { #ifndef _WIN32 - *absolute = true; + *attributes |= Path::Absolute; #endif last++; continue; } + else if(last == pos) { +#ifdef _WIN32 + if(pos == 1) + *attributes |= Path::UNC | Path::Absolute; +#endif + last++; + continue; + } + + std::string part; - append(input.substr(last, pos - last)); + if(pos == std::string::npos) + part = input.substr(last); + else + part = input.substr(last, pos - last); + +#ifdef _WIN32 + if(list.empty() && part.size() == 2 && part[1] == ':' && isalpha(part[0])) + *attributes |= Path::Absolute; +#endif - last = pos + 1; + if(part != DOT) + list.push_back(part); + + last += part.size() + 1; } return list; } -Path::Path(const std::string &path) : m_absolute(false) +Path::Path(const std::string &path) : m_attributes{} { append(path); } @@ -93,11 +97,11 @@ void Path::append(const std::string &input, const bool traversal) if(input.empty()) return; - bool absolute = false; - const auto &parts = Split(input, &absolute); + int attributes; + const auto &parts = Split(input, &attributes); - if(m_parts.empty() && absolute) - m_absolute = true; + if(m_parts.empty() && attributes) + m_attributes = attributes; for(const std::string &part : parts) { if(part == DOTDOT) { @@ -111,8 +115,8 @@ void Path::append(const std::string &input, const bool traversal) void Path::append(const Path &o) { - if(m_parts.empty() && o.absolute()) - m_absolute = true; + if(m_parts.empty()) + m_attributes = o.attributes(); m_parts.insert(m_parts.end(), o.m_parts.begin(), o.m_parts.end()); } @@ -137,8 +141,8 @@ void Path::remove(const size_t pos, size_t count) m_parts.erase(begin, end); - if(!pos && m_absolute) - m_absolute = false; + if(!pos) + m_attributes = 0; } void Path::removeLast() @@ -177,27 +181,33 @@ std::string Path::join(const bool nativeSeparator) const { const char sep = nativeSeparator ? NATIVE_SEPARATOR : UNIX_SEPARATOR; -#ifdef _WIN32 - constexpr bool absoluteSlash = false; -#else - const bool absoluteSlash = m_absolute; -#endif - std::string path; +#ifndef _WIN32 + if(test(Absolute)) + path += sep; +#endif + for(const std::string &part : m_parts) { - if(!path.empty() || absoluteSlash) +#ifdef _WIN32 + if(!path.empty()) +#else + if(path.size() > test(Absolute)) +#endif path += sep; path += part; } - if(m_parts.empty() && absoluteSlash) - path += sep; - #ifdef _WIN32 - if(m_absolute && path.size() > MAX_PATH) + if(test(Absolute) && path.size() > MAX_PATH) { path.insert(0, "\\\\?\\"); + + if(test(UNC)) + path.insert(4, "UNC\\"); + } + else if(test(UNC)) + path.insert(0, "\\\\"); #endif return path; @@ -205,7 +215,7 @@ std::string Path::join(const bool nativeSeparator) const bool Path::startsWith(const Path &o) const { - if(size() < o.size() || absolute() != o.absolute()) + if(m_parts.size() < o.size() || m_attributes != o.attributes()) return false; for(size_t i = 0; i < o.size(); i++) { @@ -218,7 +228,7 @@ bool Path::startsWith(const Path &o) const Path Path::prependRoot() const { - return m_absolute ? *this : s_root + *this; + return m_attributes & Absolute ? *this : s_root + *this; } Path Path::removeRoot() const @@ -233,7 +243,7 @@ Path Path::removeRoot() const bool Path::operator==(const Path &o) const { - return m_absolute == o.absolute() && m_parts == o.m_parts; + return m_attributes == o.attributes() && m_parts == o.m_parts; } bool Path::operator!=(const Path &o) const diff --git a/src/path.hpp b/src/path.hpp @@ -26,6 +26,11 @@ class UseRootPath; class Path { public: + enum Attribute { + Absolute = 1<<0, + UNC = 1<<1, + }; + static const Path DATA; static const Path CACHE; static const Path CONFIG; @@ -43,7 +48,8 @@ public: bool empty() const { return m_parts.empty(); } size_t size() const { return m_parts.size(); } - bool absolute() const { return m_absolute; } + int attributes() const { return m_attributes; } + bool test(Attribute f) const { return (m_attributes & f) != 0; } Path dirname() const; std::string front() const; @@ -74,7 +80,7 @@ private: const std::string &at(size_t) const; std::list<std::string> m_parts; - bool m_absolute; + int m_attributes; }; inline std::ostream &operator<<(std::ostream &os, const Path &p) diff --git a/test/path.cpp b/test/path.cpp @@ -157,7 +157,7 @@ TEST_CASE("split input", M) { } TEST_CASE("absolute path", M) { - CHECK_FALSE(Path("a/b").absolute()); + CHECK_FALSE(Path("a/b").test(Path::Absolute)); #ifdef _WIN32 const Path a("C:\\Windows\\System32"); @@ -165,7 +165,7 @@ TEST_CASE("absolute path", M) { const Path a("/usr/bin/zsh"); #endif - REQUIRE(a.absolute()); + REQUIRE(a.test(Path::Absolute)); CHECK(a.size() == 3); #ifdef _WIN32 @@ -184,7 +184,7 @@ TEST_CASE("absolute path (root only)", M) { const Path a("/"); #endif - REQUIRE(a.absolute()); + REQUIRE(a.test(Path::Absolute)); #ifdef _WIN32 CHECK(a.size() == 1); @@ -207,7 +207,7 @@ TEST_CASE("append absolute path to empty path", M) { path += abs; CHECK(path == abs); - REQUIRE(path.absolute()); + REQUIRE(path.test(Path::Absolute)); } TEST_CASE("extended absolute paths", M) { @@ -215,11 +215,11 @@ TEST_CASE("extended absolute paths", M) { Path abs("C:\\"); abs.append(std::string(260, 'a')); - CHECK(abs.absolute()); + CHECK(abs.test(Path::Absolute)); REQUIRE_THAT(abs.join(), StartsWith("\\\\?\\")); const Path path(std::string(500, 'a')); - CHECK_FALSE(path.absolute()); + CHECK_FALSE(path.test(Path::Absolute)); #else Path path("/hello"); path.append(std::string(260, 'a')); @@ -228,7 +228,26 @@ TEST_CASE("extended absolute paths", M) { REQUIRE_THAT(path.join(), !StartsWith("\\\\?\\")); } -#ifndef _WIN32 +#ifdef _WIN32 +TEST_CASE("UNC path", M) { + const Path unc("\\\\FOO\\bar"); + REQUIRE(unc.test(Path::Absolute)); + REQUIRE(unc.test(Path::UNC)); + CHECK(unc.size() == 2); + + CHECK(unc[0] == "FOO"); + CHECK(unc.join() == "\\\\FOO\\bar"); +} + +TEST_CASE("UNC path extended", M) { + Path unc("\\\\FOO"); + unc.append(std::string(260, 'a')); + + CHECK(unc.test(Path::Absolute)); + CHECK(unc.test(Path::UNC)); + REQUIRE_THAT(unc.join(), StartsWith("\\\\?\\UNC\\FOO")); +} +#else TEST_CASE("compare absolute to relative path (unix)", M) { REQUIRE(Path("/a/b") != Path("a/b")); } @@ -350,14 +369,14 @@ TEST_CASE("remove path segments", M) { SECTION("remove from start") { path.remove(0, 1); REQUIRE(path == Path("b/c/d/e")); - REQUIRE_FALSE(path.absolute()); + REQUIRE_FALSE(path.test(Path::Absolute)); } SECTION("remove from middle") { path.remove(1, 2); REQUIRE(path == Path("/a/d/e")); #ifndef _WIN32 - REQUIRE(path.absolute()); + REQUIRE(path.test(Path::Absolute)); #endif }