diff --git a/NEWS b/NEWS index 3e81a3389..cc13617b9 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,6 @@ ver 0.21.12 (not yet released) +* Windows + - support backslash in relative URIs loaded from playlists ver 0.21.11 (2019/07/03) * input diff --git a/src/playlist/PlaylistSong.cxx b/src/playlist/PlaylistSong.cxx index 7d63fe76c..543d8d96f 100644 --- a/src/playlist/PlaylistSong.cxx +++ b/src/playlist/PlaylistSong.cxx @@ -66,6 +66,22 @@ playlist_check_translate_song(DetachedSong &song, const char *base_uri, base_uri = nullptr; const char *uri = song.GetURI(); + +#ifdef _WIN32 + if (!PathTraitsUTF8::IsAbsolute(uri) && strchr(uri, '\\') != nullptr) { + /* Windows uses the backslash as path separator, but + the MPD protocol uses the (forward) slash by + definition; to allow backslashes in relative URIs + loaded from playlist files, this step converts all + backslashes to (forward) slashes */ + + std::string new_uri(uri); + std::replace(new_uri.begin(), new_uri.end(), '\\', '/'); + song.SetURI(std::move(new_uri)); + uri = song.GetURI(); + } +#endif + if (base_uri != nullptr && !uri_has_scheme(uri) && !PathTraitsUTF8::IsAbsolute(uri)) song.SetURI(PathTraitsUTF8::Build(base_uri, uri)); diff --git a/test/test_translate_song.cxx b/test/test_translate_song.cxx index 604e0c59b..cac712785 100644 --- a/test/test_translate_song.cxx +++ b/test/test_translate_song.cxx @@ -270,3 +270,23 @@ TEST_F(TranslateSongTest, Relative) insecure_loader)); EXPECT_EQ(se, ToString(song4)); } + +TEST_F(TranslateSongTest, Backslash) +{ + const SongLoader loader(reinterpret_cast(1), + storage); + + DetachedSong song1("foo\\bar.ogg", MakeTag2b()); +#ifdef _WIN32 + /* on Windows, all backslashes are converted to slashes in + relative paths from playlists */ + auto se = ToString(DetachedSong(uri2, MakeTag2c())); + EXPECT_TRUE(playlist_check_translate_song(song1, nullptr, + loader)); + EXPECT_EQ(se, ToString(song1)); +#else + /* backslash only supported on Windows */ + EXPECT_FALSE(playlist_check_translate_song(song1, nullptr, + loader)); +#endif +}