input/Plugin: pass URI as std::string_view

This commit is contained in:
Max Kellermann 2025-01-30 11:20:52 +01:00
parent aee49d1c1c
commit 715ef846b6
35 changed files with 85 additions and 92 deletions

@ -36,7 +36,7 @@ RemoteTagCache::Lookup(const std::string &uri) noexcept
lock.unlock();
try {
item->scanner = InputScanTags(uri.c_str(), *item);
item->scanner = InputScanTags(uri, *item);
if (!item->scanner) {
/* unsupported */
lock.lock();

@ -146,7 +146,7 @@ find_stream_art(std::string_view directory, Mutex &mutex)
std::string art_file = PathTraitsUTF8::Build(directory, name);
try {
return InputStream::OpenReady(art_file.c_str(), mutex);
return InputStream::OpenReady(art_file, mutex);
} catch (...) {
auto e = std::current_exception();
if (!IsFileNotFound(e))

@ -68,7 +68,7 @@ private:
void DecodeFile();
/* virtual methods from class DecoderClient */
InputStreamPtr OpenUri(const char *uri) override;
InputStreamPtr OpenUri(std::string_view uri) override;
size_t Read(InputStream &is,
std::span<std::byte> dest) noexcept override;
@ -246,14 +246,14 @@ try {
if (!path.IsNull())
DecodeFile();
else
DecodeStream(*OpenUri(uri.c_str()));
DecodeStream(*OpenUri(uri));
ChromaprintDecoderClient::Finish();
} catch (StopDecoder) {
}
InputStreamPtr
GetChromaprintCommand::OpenUri(const char *uri2)
GetChromaprintCommand::OpenUri(std::string_view uri2)
{
if (cancel)
throw StopDecoder();

@ -372,7 +372,7 @@ DecoderBridge::SeekError() noexcept
}
InputStreamPtr
DecoderBridge::OpenUri(const char *uri)
DecoderBridge::OpenUri(std::string_view uri)
{
assert(dc.state == DecoderState::START ||
dc.state == DecoderState::DECODE);

@ -158,7 +158,7 @@ public:
SongTime GetSeekTime() noexcept override;
uint64_t GetSeekFrame() noexcept override;
void SeekError() noexcept override;
InputStreamPtr OpenUri(const char *uri) override;
InputStreamPtr OpenUri(std::string_view uri) override;
size_t Read(InputStream &is,
std::span<std::byte> dest) noexcept override;
void SubmitTimestamp(FloatDuration t) noexcept override;

@ -10,6 +10,7 @@
#include <cstddef>
#include <cstdint>
#include <span>
#include <string_view>
struct AudioFormat;
struct Tag;
@ -80,7 +81,7 @@ public:
*
* Throws std::runtime_error on error.
*/
virtual InputStreamPtr OpenUri(const char *uri) = 0;
virtual InputStreamPtr OpenUri(std::string_view uri) = 0;
/**
* Blocking read from the input stream.

@ -227,7 +227,7 @@ decoder_run_stream_plugin(DecoderBridge &bridge, InputStream &is,
static DecodeResult
decoder_run_stream_locked(DecoderBridge &bridge, InputStream &is,
std::unique_lock<Mutex> &lock,
const char *uri)
std::string_view uri)
{
const auto suffix = uri_get_suffix(uri);

@ -11,7 +11,6 @@
#include "fs/Path.hxx"
#include "lib/fmt/PathFormatter.hxx"
#include "lib/fmt/RuntimeError.hxx"
#include "util/AllocatedString.hxx"
#include "util/Math.hxx"
#include "util/ScopeExit.hxx"
@ -407,10 +406,8 @@ static constexpr WavpackStreamReader64 mpd_is_reader = {
static InputStreamPtr
wavpack_open_wvc(DecoderClient &client, std::string_view uri)
{
const AllocatedString wvc_url{uri, "c"sv};
try {
return client.OpenUri(wvc_url.c_str());
return client.OpenUri(fmt::format("{}c", uri));
} catch (...) {
return nullptr;
}

@ -9,7 +9,7 @@
#include <iterator>
bool
InputPlugin::SupportsUri(const char *uri) const noexcept
InputPlugin::SupportsUri(std::string_view uri) const noexcept
{
assert(prefixes || protocols);
if (prefixes != nullptr) {

@ -47,7 +47,7 @@ struct InputPlugin {
*
* Throws std::runtime_error on error.
*/
InputStreamPtr (*open)(const char *uri, Mutex &mutex);
InputStreamPtr (*open)(std::string_view uri, Mutex &mutex);
/**
* return a set of supported protocols
@ -63,11 +63,11 @@ struct InputPlugin {
*
* @return nullptr if the given URI is not supported.
*/
std::unique_ptr<RemoteTagScanner> (*scan_tags)(const char *uri,
std::unique_ptr<RemoteTagScanner> (*scan_tags)(std::string_view uri,
RemoteTagHandler &handler) = nullptr;
[[gnu::pure]]
bool SupportsUri(const char *uri) const noexcept;
bool SupportsUri(std::string_view uri) const noexcept;
template<typename F>
void ForeachSupportedUri(F lambda) const noexcept {

@ -4,7 +4,7 @@
#include "InputStream.hxx"
#include "Handler.hxx"
#include "tag/Tag.hxx"
#include "util/ASCII.hxx"
#include "util/StringCompare.hxx"
#include <cassert>
#include <stdexcept>
@ -38,17 +38,17 @@ InputStream::SetReady() noexcept
*/
[[gnu::pure]]
static bool
ExpensiveSeeking(const char *uri) noexcept
ExpensiveSeeking(std::string_view uri) noexcept
{
return StringStartsWithCaseASCII(uri, "http://") ||
StringStartsWithCaseASCII(uri, "qobuz://") ||
StringStartsWithCaseASCII(uri, "https://");
return StringStartsWithIgnoreCase(uri, "http://") ||
StringStartsWithIgnoreCase(uri, "qobuz://") ||
StringStartsWithIgnoreCase(uri, "https://");
}
bool
InputStream::CheapSeeking() const noexcept
{
return IsSeekable() && !ExpensiveSeeking(uri.c_str());
return IsSeekable() && !ExpensiveSeeking(uri);
}
//[[noreturn]]

@ -111,14 +111,14 @@ public:
* @return an #InputStream object on success
*/
[[nodiscard]]
static InputStreamPtr Open(const char *uri, Mutex &mutex);
static InputStreamPtr Open(std::string_view uri, Mutex &mutex);
/**
* Just like Open(), but waits for the stream to become ready.
* It is a wrapper for Open(), WaitReady() and Check().
*/
[[nodiscard]]
static InputStreamPtr OpenReady(const char *uri, Mutex &mutex);
static InputStreamPtr OpenReady(std::string_view uri, Mutex &mutex);
/**
* Install a new handler.

@ -13,7 +13,7 @@
#include <stdexcept>
InputStreamPtr
InputStream::Open(const char *url, Mutex &mutex)
InputStream::Open(std::string_view url, Mutex &mutex)
{
if (PathTraitsUTF8::IsAbsolute(url)) {
const auto path = AllocatedPath::FromUTF8Throw(url);
@ -32,7 +32,7 @@ InputStream::Open(const char *url, Mutex &mutex)
}
InputStreamPtr
InputStream::OpenReady(const char *uri, Mutex &mutex)
InputStream::OpenReady(std::string_view uri, Mutex &mutex)
{
auto is = Open(uri, mutex);
LockWaitReady(*is);

@ -1,8 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright The Music Player Daemon Project
#ifndef MPD_PROXY_INPUT_STREAM_HXX
#define MPD_PROXY_INPUT_STREAM_HXX
#pragma once
#include "InputStream.hxx"
#include "Ptr.hxx"
@ -26,15 +25,17 @@ protected:
InputStreamPtr input;
public:
[[nodiscard]]
explicit ProxyInputStream(InputStreamPtr _input) noexcept;
/**
* Construct an instance without an #InputStream instance.
* Once that instance becomes available, call SetInput().
*/
ProxyInputStream(const char *_uri,
Mutex &_mutex) noexcept
:InputStream(_uri, _mutex) {}
template<typename U>
[[nodiscard]]
ProxyInputStream(U &&_uri, Mutex &_mutex) noexcept
:InputStream(std::forward<U>(_uri), _mutex) {}
~ProxyInputStream() noexcept override;
@ -78,5 +79,3 @@ protected:
InvokeOnAvailable();
}
};
#endif

@ -70,7 +70,7 @@ static constexpr std::size_t n_input_plugins = std::size(input_plugins) - 1;
bool input_plugins_enabled[std::max(n_input_plugins, std::size_t(1))];
bool
HasRemoteTagScanner(const char *uri) noexcept
HasRemoteTagScanner(std::string_view uri) noexcept
{
for (const auto &plugin : GetEnabledInputPlugins()) {
if (plugin.scan_tags != nullptr &&

@ -7,6 +7,8 @@
#include "util/FilteredContainer.hxx"
#include "util/TerminatedArray.hxx"
#include <string_view>
/**
* NULL terminated list of all input plugins which were enabled at
* compile time.
@ -30,4 +32,4 @@ GetEnabledInputPlugins() noexcept
[[gnu::pure]]
bool
HasRemoteTagScanner(const char *uri) noexcept;
HasRemoteTagScanner(std::string_view uri) noexcept;

@ -7,7 +7,7 @@
#include "Registry.hxx"
std::unique_ptr<RemoteTagScanner>
InputScanTags(const char *uri, RemoteTagHandler &handler)
InputScanTags(std::string_view uri, RemoteTagHandler &handler)
{
for (const auto &plugin : GetEnabledInputPlugins()) {
if (plugin.scan_tags == nullptr || !plugin.SupportsUri(uri))

@ -1,10 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright The Music Player Daemon Project
#ifndef MPD_INPUT_SCAN_TAGS_HXX
#define MPD_INPUT_SCAN_TAGS_HXX
#pragma once
#include <memory>
#include <string_view>
class RemoteTagScanner;
class RemoteTagHandler;
@ -19,6 +19,4 @@ class RemoteTagHandler;
* by any (enabled) plugin
*/
std::unique_ptr<RemoteTagScanner>
InputScanTags(const char *uri, RemoteTagHandler &handler);
#endif
InputScanTags(std::string_view uri, RemoteTagHandler &handler);

@ -9,7 +9,7 @@
#include <string.h>
ThreadInputStream::ThreadInputStream(const char *_plugin,
const char *_uri,
std::string_view _uri,
Mutex &_mutex,
size_t _buffer_size) noexcept
:InputStream(_uri, _mutex),

@ -62,7 +62,7 @@ class ThreadInputStream : public InputStream {
public:
ThreadInputStream(const char *_plugin,
const char *_uri, Mutex &_mutex,
std::string_view _uri, Mutex &_mutex,
size_t _buffer_size) noexcept;
#ifndef NDEBUG

@ -90,7 +90,7 @@ public:
AlsaInputStream(const AlsaInputStream &) = delete;
AlsaInputStream &operator=(const AlsaInputStream &) = delete;
static InputStreamPtr Create(EventLoop &event_loop, const char *uri,
static InputStreamPtr Create(EventLoop &event_loop, std::string_view uri,
Mutex &mutex);
protected:
@ -194,11 +194,9 @@ AlsaInputStream::AlsaInputStream(EventLoop &_loop,
}
inline InputStreamPtr
AlsaInputStream::Create(EventLoop &event_loop, const char *uri,
AlsaInputStream::Create(EventLoop &event_loop, std::string_view uri,
Mutex &mutex)
{
assert(uri != nullptr);
AlsaInputStream::SourceSpec spec(uri);
if (!spec.IsValidScheme())
return nullptr;
@ -451,7 +449,7 @@ alsa_input_init(EventLoop &event_loop, const ConfigBlock &block)
}
static InputStreamPtr
alsa_input_open(const char *uri, Mutex &mutex)
alsa_input_open(std::string_view uri, Mutex &mutex)
{
return AlsaInputStream::Create(*global_config.event_loop, uri,
mutex);

@ -47,7 +47,7 @@ class CdioParanoiaInputStream final : public InputStream {
lsn_t buffer_lsn;
public:
CdioParanoiaInputStream(const char *_uri, Mutex &_mutex,
CdioParanoiaInputStream(std::string_view _uri, Mutex &_mutex,
cdrom_drive_t *_drv, CdIo_t *_cdio,
bool reverse_endian,
lsn_t _lsn_from, lsn_t lsn_to)
@ -171,7 +171,7 @@ cdio_detect_device()
}
static InputStreamPtr
input_cdio_open(const char *uri,
input_cdio_open(std::string_view uri,
Mutex &mutex)
{
const auto parsed_uri = parse_cdio_uri(uri);

@ -19,9 +19,9 @@
#include "lib/fmt/ToBuffer.hxx"
#include "event/Call.hxx"
#include "event/Loop.hxx"
#include "util/ASCII.hxx"
#include "util/CNumberParser.hxx"
#include "util/Domain.hxx"
#include "util/StringCompare.hxx"
#include "Log.hxx"
#include "PluginUnavailable.hxx"
#include "config.h"
@ -42,6 +42,8 @@
#include <curl/curl.h>
using std::string_view_literals::operator""sv;
/**
* Do not buffer more than this number of bytes. It should be a
* reasonable limit that doesn't make low-end machines suffer too
@ -596,10 +598,10 @@ OpenCurlInputStream(std::string_view uri, const Curl::Headers &headers,
}
static InputStreamPtr
input_curl_open(const char *url, Mutex &mutex)
input_curl_open(std::string_view url, Mutex &mutex)
{
if (!StringStartsWithCaseASCII(url, "http://") &&
!StringStartsWithCaseASCII(url, "https://"))
if (!StringStartsWithIgnoreCase(url, "http://"sv) &&
!StringStartsWithIgnoreCase(url, "https://"sv))
return nullptr;
return CurlInputStream::Open(url, {}, mutex);

@ -18,7 +18,7 @@ class FfmpegInputStream final : public ThreadInputStream {
Ffmpeg::IOContext io;
public:
FfmpegInputStream(const char *_uri, Mutex &_mutex)
FfmpegInputStream(std::string_view _uri, Mutex &_mutex)
:ThreadInputStream("ffmpeg", _uri, _mutex, BUFFER_SIZE)
{
Start();
@ -82,8 +82,7 @@ input_ffmpeg_protocols() noexcept
}
static InputStreamPtr
input_ffmpeg_open(const char *uri,
Mutex &mutex)
input_ffmpeg_open(std::string_view uri, Mutex &mutex)
{
return std::make_unique<FfmpegInputStream>(uri, mutex);
}

@ -16,7 +16,7 @@ class MmsInputStream final : public ThreadInputStream {
mmsx_t *mms;
public:
MmsInputStream(const char *_uri, Mutex &_mutex)
MmsInputStream(std::string_view _uri, Mutex &_mutex)
:ThreadInputStream(input_plugin_mms.name, _uri, _mutex,
BUFFER_SIZE)
{
@ -56,8 +56,7 @@ MmsInputStream::Open()
}
static InputStreamPtr
input_mms_open(const char *url,
Mutex &mutex)
input_mms_open(std::string_view url, Mutex &mutex)
{
return std::make_unique<MmsInputStream>(url, mutex);
}

@ -213,7 +213,7 @@ input_nfs_finish() noexcept
}
static InputStreamPtr
input_nfs_open(const char *uri,
input_nfs_open(std::string_view uri,
Mutex &mutex)
{
auto is = std::make_unique<NfsInputStream>(uri, mutex);

@ -17,6 +17,8 @@
#include <memory>
using std::string_view_literals::operator""sv;
static QobuzClient *qobuz_client;
class QobuzInputStream final
@ -29,7 +31,7 @@ class QobuzInputStream final
std::exception_ptr error;
public:
QobuzInputStream(const char *_uri, const char *_track_id,
QobuzInputStream(std::string_view _uri, std::string_view _track_id,
Mutex &_mutex) noexcept
:ProxyInputStream(_uri, _mutex),
track_id(_track_id)
@ -151,27 +153,23 @@ FinishQobuzInput() noexcept
}
[[gnu::pure]]
static const char *
ExtractQobuzTrackId(const char *uri)
static std::string_view
ExtractQobuzTrackId(std::string_view uri) noexcept
{
// TODO: what's the standard "qobuz://" URI syntax?
const char *track_id = StringAfterPrefix(uri, "qobuz://track/");
if (track_id == nullptr)
return nullptr;
if (SkipPrefix(uri, "qobuz://track/"sv))
return uri;
if (*track_id == 0)
return nullptr;
return track_id;
return {};
}
static InputStreamPtr
OpenQobuzInput(const char *uri, Mutex &mutex)
OpenQobuzInput(std::string_view uri, Mutex &mutex)
{
assert(qobuz_client != nullptr);
const char *track_id = ExtractQobuzTrackId(uri);
if (track_id == nullptr)
const auto track_id = ExtractQobuzTrackId(uri);
if (track_id.empty())
return nullptr;
// TODO: validate track_id
@ -180,12 +178,12 @@ OpenQobuzInput(const char *uri, Mutex &mutex)
}
static std::unique_ptr<RemoteTagScanner>
ScanQobuzTags(const char *uri, RemoteTagHandler &handler)
ScanQobuzTags(std::string_view uri, RemoteTagHandler &handler)
{
assert(qobuz_client != nullptr);
const char *track_id = ExtractQobuzTrackId(uri);
if (track_id == nullptr)
const auto track_id = ExtractQobuzTrackId(uri);
if (track_id.empty())
return nullptr;
return std::make_unique<QobuzTagScanner>(*qobuz_client, track_id,

@ -61,16 +61,16 @@ public:
};
static std::string
MakeTrackUrl(QobuzClient &client, const char *track_id)
MakeTrackUrl(QobuzClient &client, std::string_view track_id)
{
return client.MakeUrl("track", "get",
{
{"track_id", track_id},
{"track_id", std::string{track_id}},
});
}
QobuzTagScanner::QobuzTagScanner(QobuzClient &client,
const char *track_id,
std::string_view track_id,
RemoteTagHandler &_handler)
:request(client.GetCurl(),
MakeTrackUrl(client, track_id).c_str(),

@ -21,7 +21,7 @@ public:
class ResponseParser;
QobuzTagScanner(QobuzClient &client,
const char *track_id,
std::string_view track_id,
RemoteTagHandler &_handler);
~QobuzTagScanner() noexcept override;

@ -17,7 +17,7 @@ class SmbclientInputStream final : public InputStream {
SMBCFILE *const handle;
public:
SmbclientInputStream(const char *_uri,
SmbclientInputStream(std::string &&_uri,
Mutex &_mutex,
SmbclientContext &&_ctx,
SMBCFILE *_handle, const struct stat &st)
@ -64,12 +64,13 @@ input_smbclient_init(EventLoop &, const ConfigBlock &)
}
static InputStreamPtr
input_smbclient_open(const char *uri,
input_smbclient_open(std::string_view _uri,
Mutex &mutex)
{
auto ctx = SmbclientContext::New();
SMBCFILE *handle = ctx.OpenReadOnly(uri);
std::string uri{_uri};
SMBCFILE *handle = ctx.OpenReadOnly(uri.c_str());
if (handle == nullptr)
throw MakeErrno("smbc_open() failed");
@ -81,7 +82,7 @@ input_smbclient_open(const char *uri,
}
return std::make_unique<MaybeBufferedInputStream>
(std::make_unique<SmbclientInputStream>(uri, mutex,
(std::make_unique<SmbclientInputStream>(std::move(uri), mutex,
std::move(ctx),
handle, st));
}

@ -71,7 +71,7 @@ public:
void SeekError() noexcept override {}
//InputStreamPtr OpenUri(const char *) override;
//InputStreamPtr OpenUri(std::string_view uri) override;
size_t Read(InputStream &is,
std::span<std::byte> dest) noexcept override;

@ -119,8 +119,7 @@ SmbclientStorage::GetInfo(std::string_view uri_utf8, [[maybe_unused]] bool follo
InputStreamPtr
SmbclientStorage::OpenFile(std::string_view uri_utf8, Mutex &file_mutex)
{
auto uri = MapUTF8(uri_utf8);
return InputStream::Open(uri.c_str(), file_mutex);
return InputStream::Open(MapUTF8(uri_utf8), file_mutex);
}
std::unique_ptr<StorageDirectoryReader>

@ -54,7 +54,7 @@ DumpDecoderClient::SeekError() noexcept
}
InputStreamPtr
DumpDecoderClient::OpenUri(const char *uri)
DumpDecoderClient::OpenUri(std::string_view uri)
{
return InputStream::OpenReady(uri, mutex);
}

@ -31,7 +31,7 @@ public:
SongTime GetSeekTime() noexcept override;
uint64_t GetSeekFrame() noexcept override;
void SeekError() noexcept override;
InputStreamPtr OpenUri(const char *uri) override;
InputStreamPtr OpenUri(std::string_view uri) override;
size_t Read(InputStream &is,
std::span<std::byte> dest) noexcept override;
void SubmitTimestamp(FloatDuration t) noexcept override;

@ -90,7 +90,7 @@ public:
class MyChromaprintDecoderClient final : public ChromaprintDecoderClient {
public:
InputStreamPtr OpenUri(const char *) override {
InputStreamPtr OpenUri(std::string_view) override {
throw std::runtime_error("Not implemented");
}
};