diff --git a/src/Mapper.cxx b/src/Mapper.cxx index c1e508b05..2ccc36961 100644 --- a/src/Mapper.cxx +++ b/src/Mapper.cxx @@ -251,17 +251,11 @@ map_song_fs(const Song *song) std::string map_fs_to_utf8(const char *path_fs) { - if (!music_dir_fs.IsNull() && - memcmp(path_fs, music_dir_fs.data(), music_dir_fs_length) == 0 && - G_IS_DIR_SEPARATOR(path_fs[music_dir_fs_length])) - /* remove musicDir prefix */ - path_fs += music_dir_fs_length + 1; - else if (G_IS_DIR_SEPARATOR(path_fs[0])) - /* not within musicDir */ - return NULL; - - while (path_fs[0] == G_DIR_SEPARATOR) - ++path_fs; + if (G_IS_DIR_SEPARATOR(path_fs[0])) { + path_fs = music_dir_fs.RelativeFS(path_fs); + if (path_fs == nullptr || *path_fs == 0) + return std::string(); + } return Path::ToUTF8(path_fs); } diff --git a/src/fs/Path.cxx b/src/fs/Path.cxx index 09616c9f4..1a1f133d0 100644 --- a/src/fs/Path.cxx +++ b/src/fs/Path.cxx @@ -184,3 +184,25 @@ void Path::GlobalInit() SetFSCharset("ISO-8859-1"); } } + +const char * +Path::RelativeFS(const char *other_fs) const +{ + const size_t l = length(); + if (memcmp(data(), other_fs, l) != 0) + return nullptr; + + other_fs += l; + if (*other_fs != 0) { + if (!G_IS_DIR_SEPARATOR(*other_fs)) + /* mismatch */ + return nullptr; + + /* skip remaining path separators */ + do { + ++other_fs; + } while (G_IS_DIR_SEPARATOR(*other_fs)); + } + + return other_fs; +} diff --git a/src/fs/Path.hxx b/src/fs/Path.hxx index 9bbedeeab..52a62ae76 100644 --- a/src/fs/Path.hxx +++ b/src/fs/Path.hxx @@ -223,6 +223,15 @@ public: */ gcc_pure Path GetDirectoryName() const; + + /** + * Determine the relative part of the given path to this + * object, not including the directory separator. Returns an + * empty string if the given path equals this object or + * nullptr on mismatch. + */ + gcc_pure + const char *RelativeFS(const char *other_fs) const; }; #endif