Skip to content

Commit

Permalink
fix: issues with importing with absolute paths from different root path
Browse files Browse the repository at this point in the history
and implements missing lexically_proximate(), that actually do what
old ETL relative() did.
relative() returns empty path if path isn't relative to base path.

fix synfig#3212
  • Loading branch information
rodolforg committed Sep 27, 2023
1 parent 3f490e5 commit a329cc4
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 4 deletions.
2 changes: 1 addition & 1 deletion synfig-core/src/synfig/canvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ Canvas::_get_relative_id(etl::loose_handle<const Canvas> x)const

if(x && get_root()!=x->get_root())
{
String file_name = filesystem::Path(get_file_name()).relative_to(x->get_file_path()).u8string();
String file_name = filesystem::Path(get_file_name()).proximate_to(x->get_file_path()).u8string();

id=file_name+'#'+id;
}
Expand Down
2 changes: 1 addition & 1 deletion synfig-core/src/synfig/canvasfilenaming.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ CanvasFileNaming::make_short_filename(const String &canvas_filename, const Strin
String canvas_path = filesystem::Path::dirname(canvas_absolute_filename);
String canvas_basename = filename_base(canvas_absolute_filename);
String absolute_filename = filesystem::Path::absolute_path(canvas_path, clean_filename);
String relative_filename = filesystem::Path(absolute_filename).relative_to(canvas_path).u8string();
String relative_filename = filesystem::Path(absolute_filename).proximate_to(canvas_path).u8string();

// convert "mycanvas.sfg#images/filename.png" to "#filename.png"
String prefix = canvas_basename + container_prefix;
Expand Down
21 changes: 19 additions & 2 deletions synfig-core/src/synfig/filesystem_path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,8 @@ filesystem::Path::lexically_normal() const
return normalize(path_);
}

filesystem::Path filesystem::Path::cleanup() const
filesystem::Path
filesystem::Path::cleanup() const
{
return lexically_normal();
}
Expand Down Expand Up @@ -400,11 +401,27 @@ filesystem::Path::lexically_relative(const Path& base) const
return q;
}

filesystem::Path filesystem::Path::relative_to(const Path& base) const
filesystem::Path
filesystem::Path::relative_to(const Path& base) const
{
return lexically_relative(base).lexically_normal();
}

filesystem::Path
filesystem::Path::lexically_proximate(const Path& base) const
{
Path rel(lexically_relative(base));
if (rel.empty())
return *this;
return rel;
}
#include <synfig/general.h>
filesystem::Path
filesystem::Path::proximate_to(const Path& base) const
{
return /*absolute*/(*this).lexically_normal().lexically_proximate(/*absolute*/(base)).lexically_normal();
}

filesystem::Path
filesystem::Path::root_name() const
{
Expand Down
22 changes: 22 additions & 0 deletions synfig-core/src/synfig/filesystem_path.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,28 @@ class Path {
*/
Path relative_to(const Path& base) const;

/**
* If the value of lexically_relative(@a base) is not an empty path, return it. Otherwise return *this.
*
* Examples:
* Path("a/b").lexically_relative("/a/b") returns empty
* Path("a/b").lexically_proximate("/a/b") returns "a/b"
*
* Path("/a/b").lexically_relative("c") returns empty
* Path("/a/b").lexically_proximate("c") returns "/a/b"
*
* @param base the reference path
* @return the path relative to base
*/
Path lexically_proximate(const Path& base) const;

/**
* Convenient method that calls lexically_proximate() followed by lexically_normal().
* @param base the reference path
* @return the normalized path proximate to base
*/
Path proximate_to(const Path& base) const;

// Decomposition ---------------------

/**
Expand Down
65 changes: 65 additions & 0 deletions synfig-core/test/filesystem_path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1333,6 +1333,65 @@ test_relative_ported_from_old_etl_stringf()
ASSERT_EQUAL("../../share", Path("/usr/share").lexically_relative(Path("/usr/local/bin/.")).u8string())
}

void
test_fake_relative_from_cpp_reference_dot_com()
{
// https://en.cppreference.com/w/cpp/filesystem/relative
#ifdef _WIN32
ASSERT_EQUAL("c", Path("C:/a/b/c").relative_to(Path("C:/a/b")).u8string());
ASSERT_EQUAL("../c", Path("C:/a/c").relative_to(Path("C:/a/b")).u8string());
ASSERT_EQUAL("", Path("c").relative_to(Path("C:/a/b")).u8string());
ASSERT_EQUAL("", Path("C:/a/b").relative_to(Path("c")).u8string());
#else
ASSERT_EQUAL("c", Path("/a/b/c").relative_to(Path("/a/b")).u8string());
ASSERT_EQUAL("../c", Path("/a/c").relative_to(Path("/a/b")).u8string());
ASSERT_EQUAL("", Path("c").relative_to(Path("/a/b")).u8string());
ASSERT_EQUAL("", Path("/a/b").relative_to(Path("c")).u8string());
#endif
}

void
test_relative_between_different_root_paths()
{
#ifdef _WIN32
ASSERT_EQUAL("", Path("D:/a/b/c").relative_to(Path("C:/a/b")).u8string());
ASSERT_EQUAL("", Path("D:/a/c").relative_to(Path("C:/a/b")).u8string());
#endif
}

void
test_lexically_proximate_from_cpp_reference_dot_com()
{
// https://en.cppreference.com/w/cpp/filesystem/path/lexically_normal
ASSERT_EQUAL("a/b", Path("a/b").lexically_proximate(Path("/a/b")).u8string());
}

void
test_fake_proximate_from_cpp_reference_dot_com()
{
// https://en.cppreference.com/w/cpp/filesystem/relative
#ifdef _WIN32
ASSERT_EQUAL("c", Path("C:/a/b/c").proximate_to(Path("C:/a/b")).u8string());
ASSERT_EQUAL("../c", Path("C:/a/c").proximate_to(Path("C:/a/b")).u8string());
ASSERT_EQUAL("c", Path("c").proximate_to(Path("C:/a/b")).u8string());
ASSERT_EQUAL("C:/a/b", Path("C:/a/b").proximate_to(Path("c")).u8string());
#else
ASSERT_EQUAL("c", Path("/a/b/c").proximate_to(Path("/a/b")).u8string());
ASSERT_EQUAL("../c", Path("/a/c").proximate_to(Path("/a/b")).u8string());
ASSERT_EQUAL("c", Path("c").proximate_to(Path("/a/b")).u8string());
ASSERT_EQUAL("/a/b", Path("/a/b").proximate_to(Path("c")).u8string());
#endif
}

void
test_proximate_between_different_root_paths()
{
#ifdef _WIN32
ASSERT_EQUAL("D:/a/b/c", Path("D:/a/b/c").proximate_to(Path("C:/a/b")).u8string());
ASSERT_EQUAL("D:/a/c", Path("D:/a/c").proximate_to(Path("C:/a/b")).u8string());
#endif
}

/* === E N T R Y P O I N T ================================================= */

int main() {
Expand Down Expand Up @@ -1453,6 +1512,12 @@ int main() {
TEST_FUNCTION(test_relative_to_empty_path_returns_itself)
TEST_FUNCTION(test_empty_path_relative_to_another_returns_as_it_was_special_dot_file)
TEST_FUNCTION(test_relative_ported_from_old_etl_stringf)
TEST_FUNCTION(test_fake_relative_from_cpp_reference_dot_com)
TEST_FUNCTION(test_relative_between_different_root_paths)

TEST_FUNCTION(test_lexically_proximate_from_cpp_reference_dot_com)
TEST_FUNCTION(test_fake_proximate_from_cpp_reference_dot_com)
TEST_FUNCTION(test_proximate_between_different_root_paths)

TEST_SUITE_END()

Expand Down

0 comments on commit a329cc4

Please sign in to comment.