util/UriExtract: uri_get_suffix() returns std::string_view

No need to copy it to a buffer.
This commit is contained in:
Max Kellermann 2020-11-04 20:39:06 +01:00
parent 19dd1a25d7
commit 35a232105e
14 changed files with 72 additions and 115 deletions

View File

@ -36,10 +36,10 @@
gcc_pure gcc_pure
static bool static bool
CheckDecoderPlugin(const DecoderPlugin &plugin, CheckDecoderPlugin(const DecoderPlugin &plugin,
const char *suffix, const char *mime) noexcept std::string_view suffix, const char *mime) noexcept
{ {
return (mime != nullptr && plugin.SupportsMimeType(mime)) || return (mime != nullptr && plugin.SupportsMimeType(mime)) ||
(suffix != nullptr && plugin.SupportsSuffix(suffix)); (!suffix.empty() && plugin.SupportsSuffix(suffix));
} }
bool bool
@ -47,11 +47,10 @@ tag_stream_scan(InputStream &is, TagHandler &handler)
{ {
assert(is.IsReady()); assert(is.IsReady());
UriSuffixBuffer suffix_buffer; const auto suffix = uri_get_suffix(is.GetURI());
const char *const suffix = uri_get_suffix(is.GetURI(), suffix_buffer);
const char *mime = is.GetMimeType(); const char *mime = is.GetMimeType();
if (suffix == nullptr && mime == nullptr) if (suffix.empty() && mime == nullptr)
return false; return false;
std::string mime_base; std::string mime_base;

View File

@ -72,12 +72,12 @@ protected:
private: private:
void DecodeStream(InputStream &is, const DecoderPlugin &plugin); void DecodeStream(InputStream &is, const DecoderPlugin &plugin);
bool DecodeStream(InputStream &is, const char *suffix, bool DecodeStream(InputStream &is, std::string_view suffix,
const DecoderPlugin &plugin); const DecoderPlugin &plugin);
void DecodeStream(InputStream &is); void DecodeStream(InputStream &is);
bool DecodeContainer(const char *suffix, const DecoderPlugin &plugin); bool DecodeContainer(std::string_view suffix, const DecoderPlugin &plugin);
bool DecodeContainer(const char *suffix); bool DecodeContainer(std::string_view suffix);
bool DecodeFile(const char *suffix, InputStream &is, bool DecodeFile(std::string_view suffix, InputStream &is,
const DecoderPlugin &plugin); const DecoderPlugin &plugin);
void DecodeFile(); void DecodeFile();
@ -130,17 +130,17 @@ decoder_check_plugin_mime(const DecoderPlugin &plugin,
gcc_pure gcc_pure
static bool static bool
decoder_check_plugin_suffix(const DecoderPlugin &plugin, decoder_check_plugin_suffix(const DecoderPlugin &plugin,
const char *suffix) noexcept std::string_view suffix) noexcept
{ {
assert(plugin.stream_decode != nullptr); assert(plugin.stream_decode != nullptr);
return suffix != nullptr && plugin.SupportsSuffix(suffix); return !suffix.empty() && plugin.SupportsSuffix(suffix);
} }
gcc_pure gcc_pure
static bool static bool
decoder_check_plugin(const DecoderPlugin &plugin, const InputStream &is, decoder_check_plugin(const DecoderPlugin &plugin, const InputStream &is,
const char *suffix) noexcept std::string_view suffix) noexcept
{ {
return plugin.stream_decode != nullptr && return plugin.stream_decode != nullptr &&
(decoder_check_plugin_mime(plugin, is) || (decoder_check_plugin_mime(plugin, is) ||
@ -149,7 +149,7 @@ decoder_check_plugin(const DecoderPlugin &plugin, const InputStream &is,
inline bool inline bool
GetChromaprintCommand::DecodeStream(InputStream &is, GetChromaprintCommand::DecodeStream(InputStream &is,
const char *suffix, std::string_view suffix,
const DecoderPlugin &plugin) const DecoderPlugin &plugin)
{ {
if (!decoder_check_plugin(plugin, is, suffix)) if (!decoder_check_plugin(plugin, is, suffix))
@ -164,8 +164,7 @@ GetChromaprintCommand::DecodeStream(InputStream &is,
inline void inline void
GetChromaprintCommand::DecodeStream(InputStream &is) GetChromaprintCommand::DecodeStream(InputStream &is)
{ {
UriSuffixBuffer suffix_buffer; const auto suffix = uri_get_suffix(uri.c_str());
const char *const suffix = uri_get_suffix(uri.c_str(), suffix_buffer);
decoder_plugins_try([this, &is, suffix](const DecoderPlugin &plugin){ decoder_plugins_try([this, &is, suffix](const DecoderPlugin &plugin){
return DecodeStream(is, suffix, plugin); return DecodeStream(is, suffix, plugin);
@ -173,7 +172,7 @@ GetChromaprintCommand::DecodeStream(InputStream &is)
} }
inline bool inline bool
GetChromaprintCommand::DecodeContainer(const char *suffix, GetChromaprintCommand::DecodeContainer(std::string_view suffix,
const DecoderPlugin &plugin) const DecoderPlugin &plugin)
{ {
if (plugin.container_scan == nullptr || if (plugin.container_scan == nullptr ||
@ -188,7 +187,7 @@ GetChromaprintCommand::DecodeContainer(const char *suffix,
} }
inline bool inline bool
GetChromaprintCommand::DecodeContainer(const char *suffix) GetChromaprintCommand::DecodeContainer(std::string_view suffix)
{ {
return decoder_plugins_try([this, suffix](const DecoderPlugin &plugin){ return decoder_plugins_try([this, suffix](const DecoderPlugin &plugin){
return DecodeContainer(suffix, plugin); return DecodeContainer(suffix, plugin);
@ -196,7 +195,7 @@ GetChromaprintCommand::DecodeContainer(const char *suffix)
} }
inline bool inline bool
GetChromaprintCommand::DecodeFile(const char *suffix, InputStream &is, GetChromaprintCommand::DecodeFile(std::string_view suffix, InputStream &is,
const DecoderPlugin &plugin) const DecoderPlugin &plugin)
{ {
if (!plugin.SupportsSuffix(suffix)) if (!plugin.SupportsSuffix(suffix))
@ -223,8 +222,8 @@ GetChromaprintCommand::DecodeFile(const char *suffix, InputStream &is,
inline void inline void
GetChromaprintCommand::DecodeFile() GetChromaprintCommand::DecodeFile()
{ {
const char *suffix = uri_get_suffix(uri.c_str()); const auto suffix = uri_get_suffix(uri.c_str());
if (suffix == nullptr) if (suffix.empty())
return; return;
InputStreamPtr input_stream; InputStreamPtr input_stream;

View File

@ -157,7 +157,7 @@ UpdateWalk::UpdateArchiveFile(Directory &parent, std::string_view name,
bool bool
UpdateWalk::UpdateArchiveFile(Directory &directory, UpdateWalk::UpdateArchiveFile(Directory &directory,
std::string_view name, const char *suffix, std::string_view name, std::string_view suffix,
const StorageFileInfo &info) noexcept const StorageFileInfo &info) noexcept
{ {
const ArchivePlugin *plugin = archive_plugin_from_suffix(suffix); const ArchivePlugin *plugin = archive_plugin_from_suffix(suffix);

View File

@ -32,7 +32,7 @@
bool bool
UpdateWalk::UpdateContainerFile(Directory &directory, UpdateWalk::UpdateContainerFile(Directory &directory,
std::string_view name, const char *suffix, std::string_view name, std::string_view suffix,
const StorageFileInfo &info) noexcept const StorageFileInfo &info) noexcept
{ {
const DecoderPlugin *_plugin = decoder_plugins_find([suffix](const DecoderPlugin &plugin){ const DecoderPlugin *_plugin = decoder_plugins_find([suffix](const DecoderPlugin &plugin){

View File

@ -88,7 +88,7 @@ UpdateWalk::UpdatePlaylistFile(Directory &parent, std::string_view name,
bool bool
UpdateWalk::UpdatePlaylistFile(Directory &directory, UpdateWalk::UpdatePlaylistFile(Directory &directory,
std::string_view name, const char *suffix, std::string_view name, std::string_view suffix,
const StorageFileInfo &info) noexcept const StorageFileInfo &info) noexcept
{ {
const auto *const plugin = FindPlaylistPluginBySuffix(suffix); const auto *const plugin = FindPlaylistPluginBySuffix(suffix);

View File

@ -31,7 +31,7 @@
inline void inline void
UpdateWalk::UpdateSongFile2(Directory &directory, UpdateWalk::UpdateSongFile2(Directory &directory,
const char *name, const char *suffix, const char *name, std::string_view suffix,
const StorageFileInfo &info) noexcept const StorageFileInfo &info) noexcept
try { try {
Song *song; Song *song;
@ -98,7 +98,7 @@ try {
bool bool
UpdateWalk::UpdateSongFile(Directory &directory, UpdateWalk::UpdateSongFile(Directory &directory,
const char *name, const char *suffix, const char *name, std::string_view suffix,
const StorageFileInfo &info) noexcept const StorageFileInfo &info) noexcept
{ {
if (!decoder_plugins_supports_suffix(suffix)) if (!decoder_plugins_supports_suffix(suffix))

View File

@ -189,8 +189,8 @@ UpdateWalk::UpdateRegularFile(Directory &directory,
const char *name, const char *name,
const StorageFileInfo &info) noexcept const StorageFileInfo &info) noexcept
{ {
const char *suffix = uri_get_suffix(name); const auto suffix = uri_get_suffix(name);
if (suffix == nullptr) if (suffix.empty())
return false; return false;
return UpdateSongFile(directory, name, suffix, info) || return UpdateSongFile(directory, name, suffix, info) ||

View File

@ -86,15 +86,15 @@ private:
void PurgeDeletedFromDirectory(Directory &directory) noexcept; void PurgeDeletedFromDirectory(Directory &directory) noexcept;
void UpdateSongFile2(Directory &directory, void UpdateSongFile2(Directory &directory,
const char *name, const char *suffix, const char *name, std::string_view suffix,
const StorageFileInfo &info) noexcept; const StorageFileInfo &info) noexcept;
bool UpdateSongFile(Directory &directory, bool UpdateSongFile(Directory &directory,
const char *name, const char *suffix, const char *name, std::string_view suffix,
const StorageFileInfo &info) noexcept; const StorageFileInfo &info) noexcept;
bool UpdateContainerFile(Directory &directory, bool UpdateContainerFile(Directory &directory,
std::string_view name, const char *suffix, std::string_view name, std::string_view suffix,
const StorageFileInfo &info) noexcept; const StorageFileInfo &info) noexcept;
@ -103,7 +103,7 @@ private:
const char *name) noexcept; const char *name) noexcept;
bool UpdateArchiveFile(Directory &directory, bool UpdateArchiveFile(Directory &directory,
std::string_view name, const char *suffix, std::string_view name, std::string_view suffix,
const StorageFileInfo &info) noexcept; const StorageFileInfo &info) noexcept;
void UpdateArchiveFile(Directory &directory, std::string_view name, void UpdateArchiveFile(Directory &directory, std::string_view name,
@ -114,7 +114,7 @@ private:
#else #else
bool UpdateArchiveFile([[maybe_unused]] Directory &directory, bool UpdateArchiveFile([[maybe_unused]] Directory &directory,
[[maybe_unused]] const char *name, [[maybe_unused]] const char *name,
[[maybe_unused]] const char *suffix, [[maybe_unused]] std::string_view suffix,
[[maybe_unused]] const StorageFileInfo &info) noexcept { [[maybe_unused]] const StorageFileInfo &info) noexcept {
return false; return false;
} }
@ -125,7 +125,7 @@ private:
const PlaylistPlugin &plugin) noexcept; const PlaylistPlugin &plugin) noexcept;
bool UpdatePlaylistFile(Directory &directory, bool UpdatePlaylistFile(Directory &directory,
std::string_view name, const char *suffix, std::string_view name, std::string_view suffix,
const StorageFileInfo &info) noexcept; const StorageFileInfo &info) noexcept;
bool UpdateRegularFile(Directory &directory, bool UpdateRegularFile(Directory &directory,

View File

@ -178,17 +178,17 @@ decoder_check_plugin_mime(const DecoderPlugin &plugin,
gcc_pure gcc_pure
static bool static bool
decoder_check_plugin_suffix(const DecoderPlugin &plugin, decoder_check_plugin_suffix(const DecoderPlugin &plugin,
const char *suffix) noexcept std::string_view suffix) noexcept
{ {
assert(plugin.stream_decode != nullptr); assert(plugin.stream_decode != nullptr);
return suffix != nullptr && plugin.SupportsSuffix(suffix); return !suffix.empty() && plugin.SupportsSuffix(suffix);
} }
gcc_pure gcc_pure
static bool static bool
decoder_check_plugin(const DecoderPlugin &plugin, const InputStream &is, decoder_check_plugin(const DecoderPlugin &plugin, const InputStream &is,
const char *suffix) noexcept std::string_view suffix) noexcept
{ {
return plugin.stream_decode != nullptr && return plugin.stream_decode != nullptr &&
(decoder_check_plugin_mime(plugin, is) || (decoder_check_plugin_mime(plugin, is) ||
@ -198,7 +198,7 @@ decoder_check_plugin(const DecoderPlugin &plugin, const InputStream &is,
static bool static bool
decoder_run_stream_plugin(DecoderBridge &bridge, InputStream &is, decoder_run_stream_plugin(DecoderBridge &bridge, InputStream &is,
std::unique_lock<Mutex> &lock, std::unique_lock<Mutex> &lock,
const char *suffix, std::string_view suffix,
const DecoderPlugin &plugin, const DecoderPlugin &plugin,
bool &tried_r) bool &tried_r)
{ {
@ -216,8 +216,7 @@ decoder_run_stream_locked(DecoderBridge &bridge, InputStream &is,
std::unique_lock<Mutex> &lock, std::unique_lock<Mutex> &lock,
const char *uri, bool &tried_r) const char *uri, bool &tried_r)
{ {
UriSuffixBuffer suffix_buffer; const auto suffix = uri_get_suffix(uri);
const char *const suffix = uri_get_suffix(uri, suffix_buffer);
const auto f = [&,suffix](const auto &plugin) const auto f = [&,suffix](const auto &plugin)
{ return decoder_run_stream_plugin(bridge, is, lock, suffix, plugin, tried_r); }; { return decoder_run_stream_plugin(bridge, is, lock, suffix, plugin, tried_r); };
@ -326,7 +325,7 @@ decoder_run_stream(DecoderBridge &bridge, const char *uri)
* DecoderControl::mutex is not locked by caller. * DecoderControl::mutex is not locked by caller.
*/ */
static bool static bool
TryDecoderFile(DecoderBridge &bridge, Path path_fs, const char *suffix, TryDecoderFile(DecoderBridge &bridge, Path path_fs, std::string_view suffix,
InputStream &input_stream, InputStream &input_stream,
const DecoderPlugin &plugin) const DecoderPlugin &plugin)
{ {
@ -354,7 +353,8 @@ TryDecoderFile(DecoderBridge &bridge, Path path_fs, const char *suffix,
* DecoderControl::mutex is not locked by caller. * DecoderControl::mutex is not locked by caller.
*/ */
static bool static bool
TryContainerDecoder(DecoderBridge &bridge, Path path_fs, const char *suffix, TryContainerDecoder(DecoderBridge &bridge, Path path_fs,
std::string_view suffix,
const DecoderPlugin &plugin) const DecoderPlugin &plugin)
{ {
if (plugin.container_scan == nullptr || if (plugin.container_scan == nullptr ||
@ -375,7 +375,8 @@ TryContainerDecoder(DecoderBridge &bridge, Path path_fs, const char *suffix,
* DecoderControl::mutex is not locked by caller. * DecoderControl::mutex is not locked by caller.
*/ */
static bool static bool
TryContainerDecoder(DecoderBridge &bridge, Path path_fs, const char *suffix) TryContainerDecoder(DecoderBridge &bridge, Path path_fs,
std::string_view suffix)
{ {
return decoder_plugins_try([&bridge, path_fs, return decoder_plugins_try([&bridge, path_fs,
suffix](const DecoderPlugin &plugin){ suffix](const DecoderPlugin &plugin){
@ -394,8 +395,8 @@ TryContainerDecoder(DecoderBridge &bridge, Path path_fs, const char *suffix)
static bool static bool
decoder_run_file(DecoderBridge &bridge, const char *uri_utf8, Path path_fs) decoder_run_file(DecoderBridge &bridge, const char *uri_utf8, Path path_fs)
{ {
const char *suffix = uri_get_suffix(uri_utf8); const auto suffix = uri_get_suffix(uri_utf8);
if (suffix == nullptr) if (suffix.empty())
return false; return false;
InputStreamPtr input_stream; InputStreamPtr input_stream;

View File

@ -157,9 +157,8 @@ playlist_list_open_uri_suffix(const char *uri, Mutex &mutex,
{ {
assert(uri != nullptr); assert(uri != nullptr);
UriSuffixBuffer suffix_buffer; const auto suffix = uri_get_suffix(uri);
const char *const suffix = uri_get_suffix(uri, suffix_buffer); if (suffix.empty())
if (suffix == nullptr)
return nullptr; return nullptr;
for (unsigned i = 0; playlist_plugins[i] != nullptr; ++i) { for (unsigned i = 0; playlist_plugins[i] != nullptr; ++i) {
@ -272,15 +271,14 @@ playlist_list_open_stream(InputStreamPtr &&is, const char *uri)
return playlist; return playlist;
} }
UriSuffixBuffer suffix_buffer; if (uri != nullptr) {
const char *suffix = uri != nullptr const auto suffix = uri_get_suffix(uri);
? uri_get_suffix(uri, suffix_buffer) if (!suffix.empty()) {
: nullptr; auto playlist = playlist_list_open_stream_suffix(std::move(is),
if (suffix != nullptr) { suffix);
auto playlist = playlist_list_open_stream_suffix(std::move(is), if (playlist != nullptr)
suffix); return playlist;
if (playlist != nullptr) }
return playlist;
} }
return nullptr; return nullptr;

View File

@ -121,37 +121,21 @@ uri_get_path(std::string_view uri) noexcept
} }
/* suffixes should be ascii only characters */ /* suffixes should be ascii only characters */
const char * std::string_view
uri_get_suffix(const char *uri) noexcept uri_get_suffix(const char *uri) noexcept
{ {
const char *suffix = std::strrchr(uri, '.'); const char *suffix = std::strrchr(uri, '.');
if (suffix == nullptr || suffix == uri || if (suffix == nullptr || suffix == uri ||
suffix[-1] == '/' || suffix[-1] == '\\') suffix[-1] == '/' || suffix[-1] == '\\')
return nullptr; return {};
++suffix; ++suffix;
if (strpbrk(suffix, "/\\") != nullptr) if (strpbrk(suffix, "/\\") != nullptr)
return nullptr; return {};
return suffix; /* remove the query string */
} return StringView(suffix).Split('?').first;
const char *
uri_get_suffix(const char *uri, UriSuffixBuffer &buffer) noexcept
{
const char *suffix = uri_get_suffix(uri);
if (suffix == nullptr)
return nullptr;
const char *q = std::strchr(suffix, '?');
if (q != nullptr && size_t(q - suffix) < sizeof(buffer.data)) {
memcpy(buffer.data, suffix, q - suffix);
buffer.data[q - suffix] = 0;
suffix = buffer.data;
}
return suffix;
} }
const char * const char *

View File

@ -62,20 +62,9 @@ std::string_view
uri_get_path(std::string_view uri) noexcept; uri_get_path(std::string_view uri) noexcept;
gcc_pure gcc_pure
const char * std::string_view
uri_get_suffix(const char *uri) noexcept; uri_get_suffix(const char *uri) noexcept;
struct UriSuffixBuffer {
char data[8];
};
/**
* Returns the file name suffix, ignoring the query string.
*/
gcc_pure
const char *
uri_get_suffix(const char *uri, UriSuffixBuffer &buffer) noexcept;
/** /**
* Returns the URI fragment, i.e. the portion after the '#', but * Returns the URI fragment, i.e. the portion after the '#', but
* without the '#'. If there is no '#', this function returns * without the '#'. If there is no '#', this function returns

View File

@ -37,7 +37,7 @@
#include <stdio.h> #include <stdio.h>
static const DecoderPlugin * static const DecoderPlugin *
FindContainerDecoderPlugin(const char *suffix) FindContainerDecoderPlugin(std::string_view suffix)
{ {
return decoder_plugins_find([suffix](const DecoderPlugin &plugin){ return decoder_plugins_find([suffix](const DecoderPlugin &plugin){
return plugin.container_scan != nullptr && return plugin.container_scan != nullptr &&
@ -48,10 +48,8 @@ FindContainerDecoderPlugin(const char *suffix)
static const DecoderPlugin * static const DecoderPlugin *
FindContainerDecoderPlugin(Path path) FindContainerDecoderPlugin(Path path)
{ {
UriSuffixBuffer suffix_buffer; const auto suffix = uri_get_suffix(path.ToUTF8Throw().c_str());
const char *const suffix = uri_get_suffix(path.ToUTF8Throw().c_str(), if (suffix.empty())
suffix_buffer);
if (suffix == nullptr)
return nullptr; return nullptr;
return FindContainerDecoderPlugin(suffix); return FindContainerDecoderPlugin(suffix);

View File

@ -6,28 +6,17 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
using std::string_view_literals::operator""sv;
TEST(UriExtract, Suffix) TEST(UriExtract, Suffix)
{ {
EXPECT_EQ((const char *)nullptr, uri_get_suffix("/foo/bar")); EXPECT_EQ((const char *)nullptr, uri_get_suffix("/foo/bar").data());
EXPECT_EQ((const char *)nullptr, uri_get_suffix("/foo.jpg/bar")); EXPECT_EQ((const char *)nullptr, uri_get_suffix("/foo.jpg/bar").data());
EXPECT_STREQ(uri_get_suffix("/foo/bar.jpg"), "jpg"); EXPECT_EQ(uri_get_suffix("/foo/bar.jpg"), "jpg"sv);
EXPECT_STREQ(uri_get_suffix("/foo.png/bar.jpg"), "jpg"); EXPECT_EQ(uri_get_suffix("/foo.png/bar.jpg"), "jpg"sv);
EXPECT_EQ((const char *)nullptr, uri_get_suffix(".jpg")); EXPECT_EQ((const char *)nullptr, uri_get_suffix(".jpg").data());
EXPECT_EQ((const char *)nullptr, uri_get_suffix("/foo/.jpg")); EXPECT_EQ((const char *)nullptr, uri_get_suffix("/foo/.jpg").data());
/* the first overload does not eliminate the query /* eliminate the query string */
string */ EXPECT_EQ(uri_get_suffix("/foo/bar.jpg?query_string"), "jpg"sv);
EXPECT_STREQ(uri_get_suffix("/foo/bar.jpg?query_string"),
"jpg?query_string");
/* ... but the second one does */
UriSuffixBuffer buffer;
EXPECT_STREQ(uri_get_suffix("/foo/bar.jpg?query_string", buffer),
"jpg");
/* repeat some of the above tests with the second overload */
EXPECT_EQ((const char *)nullptr, uri_get_suffix("/foo/bar", buffer));
EXPECT_EQ((const char *)nullptr,
uri_get_suffix("/foo.jpg/bar", buffer));
EXPECT_STREQ(uri_get_suffix("/foo/bar.jpg", buffer), "jpg");
} }