input/Plugin: migrate open() from class Error to C++ exceptions

This commit is contained in:
Max Kellermann 2016-09-09 15:37:06 +02:00
parent 63ab7767a3
commit fc7d3f64c0
44 changed files with 359 additions and 461 deletions

View File

@ -28,26 +28,28 @@
bool bool
tag_archive_scan(ArchiveFile &archive, const char *path_utf8, tag_archive_scan(ArchiveFile &archive, const char *path_utf8,
const TagHandler &handler, void *handler_ctx) const TagHandler &handler, void *handler_ctx)
{ try {
Mutex mutex; Mutex mutex;
Cond cond; Cond cond;
InputStreamPtr is(archive.OpenStream(path_utf8, mutex, cond, InputStreamPtr is(archive.OpenStream(path_utf8, mutex, cond));
IgnoreError()));
if (!is) if (!is)
return false; return false;
return tag_stream_scan(*is, handler, handler_ctx); return tag_stream_scan(*is, handler, handler_ctx);
} catch (const std::exception &e) {
return false;
} }
bool bool
tag_archive_scan(ArchiveFile &archive, const char *path_utf8, tag_archive_scan(ArchiveFile &archive, const char *path_utf8,
TagBuilder &builder) TagBuilder &builder)
{ try {
Mutex mutex; Mutex mutex;
Cond cond; Cond cond;
InputStreamPtr is(archive.OpenStream(path_utf8, mutex, cond, InputStreamPtr is(archive.OpenStream(path_utf8, mutex, cond));
IgnoreError()));
return is && tag_stream_scan(*is, builder); return is && tag_stream_scan(*is, builder);
} catch (const std::exception &e) {
return false;
} }

View File

@ -30,6 +30,8 @@
#include "input/LocalOpen.hxx" #include "input/LocalOpen.hxx"
#include "thread/Cond.hxx" #include "thread/Cond.hxx"
#include <stdexcept>
#include <assert.h> #include <assert.h>
class TagFileScan { class TagFileScan {
@ -60,11 +62,12 @@ public:
/* open the InputStream (if not already open) */ /* open the InputStream (if not already open) */
if (is == nullptr) { if (is == nullptr) {
try {
is = OpenLocalInputStream(path_fs, is = OpenLocalInputStream(path_fs,
mutex, cond, mutex, cond);
IgnoreError()); } catch (const std::runtime_error &) {
if (is == nullptr)
return false; return false;
}
} else } else
is->LockRewind(IgnoreError()); is->LockRewind(IgnoreError());

View File

@ -72,13 +72,14 @@ tag_stream_scan(InputStream &is, const TagHandler &handler, void *ctx)
bool bool
tag_stream_scan(const char *uri, const TagHandler &handler, void *ctx) tag_stream_scan(const char *uri, const TagHandler &handler, void *ctx)
{ try {
Mutex mutex; Mutex mutex;
Cond cond; Cond cond;
auto is = InputStream::OpenReady(uri, mutex, cond, auto is = InputStream::OpenReady(uri, mutex, cond);
IgnoreError()); return tag_stream_scan(*is, handler, ctx);
return is && tag_stream_scan(*is, handler, ctx); } catch (const std::exception &e) {
return false;
} }
bool bool
@ -97,11 +98,12 @@ tag_stream_scan(InputStream &is, TagBuilder &builder)
bool bool
tag_stream_scan(const char *uri, TagBuilder &builder) tag_stream_scan(const char *uri, TagBuilder &builder)
{ try {
Mutex mutex; Mutex mutex;
Cond cond; Cond cond;
auto is = InputStream::OpenReady(uri, mutex, cond, auto is = InputStream::OpenReady(uri, mutex, cond);
IgnoreError()); return tag_stream_scan(*is, builder);
return is && tag_stream_scan(*is, builder); } catch (const std::exception &e) {
return false;
} }

View File

@ -51,11 +51,12 @@ public:
/** /**
* Opens an InputStream of a file within the archive. * Opens an InputStream of a file within the archive.
* *
* Throws std::runtime_error on error.
*
* @param path the path within the archive * @param path the path within the archive
*/ */
virtual InputStream *OpenStream(const char *path, virtual InputStream *OpenStream(const char *path,
Mutex &mutex, Cond &cond, Mutex &mutex, Cond &cond) = 0;
Error &error) = 0;
}; };
#endif #endif

View File

@ -36,6 +36,8 @@
#include <bzlib.h> #include <bzlib.h>
#include <stdexcept>
#include <stddef.h> #include <stddef.h>
class Bzip2ArchiveFile final : public ArchiveFile { class Bzip2ArchiveFile final : public ArchiveFile {
@ -74,9 +76,8 @@ public:
visitor.VisitArchiveEntry(name.c_str()); visitor.VisitArchiveEntry(name.c_str());
} }
virtual InputStream *OpenStream(const char *path, InputStream *OpenStream(const char *path,
Mutex &mutex, Cond &cond, Mutex &mutex, Cond &cond) override;
Error &error) override;
}; };
class Bzip2InputStream final : public InputStream { class Bzip2InputStream final : public InputStream {
@ -93,13 +94,12 @@ public:
Mutex &mutex, Cond &cond); Mutex &mutex, Cond &cond);
~Bzip2InputStream(); ~Bzip2InputStream();
bool Open(Error &error);
/* virtual methods from InputStream */ /* virtual methods from InputStream */
bool IsEOF() override; bool IsEOF() override;
size_t Read(void *ptr, size_t size, Error &error) override; size_t Read(void *ptr, size_t size, Error &error) override;
private: private:
void Open();
bool FillBuffer(Error &error); bool FillBuffer(Error &error);
}; };
@ -107,8 +107,8 @@ static constexpr Domain bz2_domain("bz2");
/* single archive handling allocation helpers */ /* single archive handling allocation helpers */
inline bool inline void
Bzip2InputStream::Open(Error &error) Bzip2InputStream::Open()
{ {
bzstream.bzalloc = nullptr; bzstream.bzalloc = nullptr;
bzstream.bzfree = nullptr; bzstream.bzfree = nullptr;
@ -118,27 +118,20 @@ Bzip2InputStream::Open(Error &error)
bzstream.avail_in = 0; bzstream.avail_in = 0;
int ret = BZ2_bzDecompressInit(&bzstream, 0, 0); int ret = BZ2_bzDecompressInit(&bzstream, 0, 0);
if (ret != BZ_OK) { if (ret != BZ_OK)
error.Set(bz2_domain, ret, throw std::runtime_error("BZ2_bzDecompressInit() has failed");
"BZ2_bzDecompressInit() has failed");
return false;
}
SetReady(); SetReady();
return true;
} }
/* archive open && listing routine */ /* archive open && listing routine */
static ArchiveFile * static ArchiveFile *
bz2_open(Path pathname, Error &error) bz2_open(Path pathname, gcc_unused Error &error)
{ {
static Mutex mutex; static Mutex mutex;
static Cond cond; static Cond cond;
auto is = OpenLocalInputStream(pathname, mutex, cond, error); auto is = OpenLocalInputStream(pathname, mutex, cond);
if (is == nullptr)
return nullptr;
return new Bzip2ArchiveFile(pathname, std::move(is)); return new Bzip2ArchiveFile(pathname, std::move(is));
} }
@ -150,6 +143,7 @@ Bzip2InputStream::Bzip2InputStream(Bzip2ArchiveFile &_context,
:InputStream(_uri, _mutex, _cond), :InputStream(_uri, _mutex, _cond),
archive(&_context) archive(&_context)
{ {
Open();
archive->Ref(); archive->Ref();
} }
@ -161,16 +155,9 @@ Bzip2InputStream::~Bzip2InputStream()
InputStream * InputStream *
Bzip2ArchiveFile::OpenStream(const char *path, Bzip2ArchiveFile::OpenStream(const char *path,
Mutex &mutex, Cond &cond, Mutex &mutex, Cond &cond)
Error &error)
{ {
Bzip2InputStream *bis = new Bzip2InputStream(*this, path, mutex, cond); return new Bzip2InputStream(*this, path, mutex, cond);
if (!bis->Open(error)) {
delete bis;
return nullptr;
}
return bis;
} }
inline bool inline bool

View File

@ -29,6 +29,7 @@
#include "input/InputStream.hxx" #include "input/InputStream.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "util/RefCount.hxx" #include "util/RefCount.hxx"
#include "util/RuntimeError.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
@ -77,9 +78,8 @@ public:
virtual void Visit(ArchiveVisitor &visitor) override; virtual void Visit(ArchiveVisitor &visitor) override;
virtual InputStream *OpenStream(const char *path, InputStream *OpenStream(const char *path,
Mutex &mutex, Cond &cond, Mutex &mutex, Cond &cond) override;
Error &error) override;
}; };
static constexpr Domain iso9660_domain("iso9660"); static constexpr Domain iso9660_domain("iso9660");
@ -175,15 +175,12 @@ public:
InputStream * InputStream *
Iso9660ArchiveFile::OpenStream(const char *pathname, Iso9660ArchiveFile::OpenStream(const char *pathname,
Mutex &mutex, Cond &cond, Mutex &mutex, Cond &cond)
Error &error)
{ {
auto statbuf = iso9660_ifs_stat_translate(iso, pathname); auto statbuf = iso9660_ifs_stat_translate(iso, pathname);
if (statbuf == nullptr) { if (statbuf == nullptr)
error.Format(iso9660_domain, throw FormatRuntimeError("not found in the ISO file: %s",
"not found in the ISO file: %s", pathname); pathname);
return nullptr;
}
return new Iso9660InputStream(*this, pathname, mutex, cond, return new Iso9660InputStream(*this, pathname, mutex, cond,
statbuf); statbuf);

View File

@ -29,6 +29,7 @@
#include "input/InputStream.hxx" #include "input/InputStream.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "util/RefCount.hxx" #include "util/RefCount.hxx"
#include "util/RuntimeError.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
@ -58,9 +59,8 @@ public:
virtual void Visit(ArchiveVisitor &visitor) override; virtual void Visit(ArchiveVisitor &visitor) override;
virtual InputStream *OpenStream(const char *path, InputStream *OpenStream(const char *path,
Mutex &mutex, Cond &cond, Mutex &mutex, Cond &cond) override;
Error &error) override;
}; };
static constexpr Domain zzip_domain("zzip"); static constexpr Domain zzip_domain("zzip");
@ -129,15 +129,12 @@ struct ZzipInputStream final : public InputStream {
InputStream * InputStream *
ZzipArchiveFile::OpenStream(const char *pathname, ZzipArchiveFile::OpenStream(const char *pathname,
Mutex &mutex, Cond &cond, Mutex &mutex, Cond &cond)
Error &error)
{ {
ZZIP_FILE *_file = zzip_file_open(dir, pathname, 0); ZZIP_FILE *_file = zzip_file_open(dir, pathname, 0);
if (_file == nullptr) { if (_file == nullptr)
error.Format(zzip_domain, "not found in the ZIP file: %s", throw FormatRuntimeError("not found in the ZIP file: %s",
pathname); pathname);
return nullptr;
}
return new ZzipInputStream(*this, pathname, return new ZzipInputStream(*this, pathname,
mutex, cond, mutex, cond,

View File

@ -258,7 +258,7 @@ void decoder_seek_error(Decoder & decoder)
} }
InputStreamPtr InputStreamPtr
decoder_open_uri(Decoder &decoder, const char *uri, Error &error) decoder_open_uri(Decoder &decoder, const char *uri)
{ {
assert(decoder.dc.state == DecoderState::START || assert(decoder.dc.state == DecoderState::START ||
decoder.dc.state == DecoderState::DECODE); decoder.dc.state == DecoderState::DECODE);
@ -267,9 +267,7 @@ decoder_open_uri(Decoder &decoder, const char *uri, Error &error)
Mutex &mutex = dc.mutex; Mutex &mutex = dc.mutex;
Cond &cond = dc.cond; Cond &cond = dc.cond;
auto is = InputStream::Open(uri, mutex, cond, error); auto is = InputStream::Open(uri, mutex, cond);
if (!is)
return nullptr;
const ScopeLock lock(mutex); const ScopeLock lock(mutex);
while (true) { while (true) {

View File

@ -121,11 +121,12 @@ decoder_seek_error(Decoder &decoder);
/** /**
* Open a new #InputStream and wait until it's ready. Can get * Open a new #InputStream and wait until it's ready. Can get
* cancelled by DecoderCommand::STOP (returns nullptr without setting * cancelled by DecoderCommand::STOP (returns nullptr).
* #Error). *
* Throws std::runtime_error on error.
*/ */
InputStreamPtr InputStreamPtr
decoder_open_uri(Decoder &decoder, const char *uri, Error &error); decoder_open_uri(Decoder &decoder, const char *uri);
/** /**
* Blocking read from the input stream. * Blocking read from the input stream.

View File

@ -56,10 +56,7 @@ static constexpr Domain decoder_thread_domain("decoder_thread");
static InputStreamPtr static InputStreamPtr
decoder_input_stream_open(DecoderControl &dc, const char *uri) decoder_input_stream_open(DecoderControl &dc, const char *uri)
{ {
Error error; auto is = InputStream::Open(uri, dc.mutex, dc.cond);
auto is = InputStream::Open(uri, dc.mutex, dc.cond, error);
if (is == nullptr)
throw error;
/* wait for the input stream to become ready; its metadata /* wait for the input stream to become ready; its metadata
will be available then */ will be available then */
@ -76,6 +73,7 @@ decoder_input_stream_open(DecoderControl &dc, const char *uri)
is->Update(); is->Update();
} }
Error error;
if (!is->Check(error)) if (!is->Check(error))
throw error; throw error;
@ -85,10 +83,7 @@ decoder_input_stream_open(DecoderControl &dc, const char *uri)
static InputStreamPtr static InputStreamPtr
decoder_input_stream_open(DecoderControl &dc, Path path) decoder_input_stream_open(DecoderControl &dc, Path path)
{ {
Error error; auto is = OpenLocalInputStream(path, dc.mutex, dc.cond);
auto is = OpenLocalInputStream(path, dc.mutex, dc.cond, error);
if (is == nullptr)
throw error;
assert(is->IsReady()); assert(is->IsReady());

View File

@ -34,6 +34,8 @@
#include <wavpack/wavpack.h> #include <wavpack/wavpack.h>
#include <stdexcept>
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -490,7 +492,11 @@ wavpack_open_wvc(Decoder &decoder, const char *uri)
free(wvc_url); free(wvc_url);
}; };
return decoder_open_uri(decoder, uri, IgnoreError()); try {
return decoder_open_uri(decoder, uri);
} catch (const std::runtime_error &) {
return nullptr;
}
} }
/* /*

View File

@ -81,6 +81,7 @@ AsyncInputStream::Resume()
if (paused) { if (paused) {
paused = false; paused = false;
DoResume(); DoResume();
} }
} }
@ -264,7 +265,12 @@ AsyncInputStream::DeferredResume()
{ {
const ScopeLock protect(mutex); const ScopeLock protect(mutex);
try {
Resume(); Resume();
} catch (...) {
postponed_exception = std::current_exception();
cond.broadcast();
}
} }
void void
@ -274,10 +280,16 @@ AsyncInputStream::DeferredSeek()
if (seek_state != SeekState::SCHEDULED) if (seek_state != SeekState::SCHEDULED)
return; return;
try {
Resume(); Resume();
seek_state = SeekState::PENDING; seek_state = SeekState::PENDING;
buffer.Clear(); buffer.Clear();
paused = false; paused = false;
DoSeek(seek_offset); DoSeek(seek_offset);
} catch (...) {
postponed_exception = std::current_exception();
cond.broadcast();
}
} }

View File

@ -36,7 +36,6 @@
struct ConfigBlock; struct ConfigBlock;
class InputStream; class InputStream;
class Error;
struct Tag; struct Tag;
struct InputPlugin { struct InputPlugin {
@ -58,9 +57,11 @@ struct InputPlugin {
*/ */
void (*finish)(); void (*finish)();
/**
* Throws std::runtime_error on error.
*/
InputStream *(*open)(const char *uri, InputStream *(*open)(const char *uri,
Mutex &mutex, Cond &cond, Mutex &mutex, Cond &cond);
Error &error);
}; };
#endif #endif

View File

@ -115,16 +115,17 @@ public:
* Opens a new input stream. You may not access it until the "ready" * Opens a new input stream. You may not access it until the "ready"
* flag is set. * flag is set.
* *
* Throws std::runtime_error on error.
*
* @param mutex a mutex that is used to protect this object; must be * @param mutex a mutex that is used to protect this object; must be
* locked before calling any of the public methods * locked before calling any of the public methods
* @param cond a cond that gets signalled when the state of * @param cond a cond that gets signalled when the state of
* this object changes; may be nullptr if the caller doesn't want to get * this object changes; may be nullptr if the caller doesn't want to get
* notifications * notifications
* @return an #InputStream object on success, nullptr on error * @return an #InputStream object on success
*/ */
gcc_nonnull_all gcc_nonnull_all
static InputStreamPtr Open(const char *uri, Mutex &mutex, Cond &cond, static InputStreamPtr Open(const char *uri, Mutex &mutex, Cond &cond);
Error &error);
/** /**
* Just like Open(), but waits for the stream to become ready. * Just like Open(), but waits for the stream to become ready.
@ -132,8 +133,7 @@ public:
*/ */
gcc_nonnull_all gcc_nonnull_all
static InputStreamPtr OpenReady(const char *uri, static InputStreamPtr OpenReady(const char *uri,
Mutex &mutex, Cond &cond, Mutex &mutex, Cond &cond);
Error &error);
/** /**
* The absolute URI which was used to open this stream. * The absolute URI which was used to open this stream.

View File

@ -27,7 +27,7 @@
#endif #endif
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "util/Error.hxx" #include "system/Error.hxx"
#include <assert.h> #include <assert.h>
@ -36,20 +36,24 @@
#endif #endif
InputStreamPtr InputStreamPtr
OpenLocalInputStream(Path path, Mutex &mutex, Cond &cond, Error &error) OpenLocalInputStream(Path path, Mutex &mutex, Cond &cond)
{ {
assert(!error.IsDefined()); InputStreamPtr is;
InputStreamPtr is(OpenFileInputStream(path, mutex, cond, error));
#ifdef ENABLE_ARCHIVE #ifdef ENABLE_ARCHIVE
if (is == nullptr && error.IsDomain(errno_domain) && try {
error.GetCode() == ENOTDIR) { #endif
is = OpenFileInputStream(path, mutex, cond);
#ifdef ENABLE_ARCHIVE
} catch (const std::system_error &e) {
if (IsPathNotFound(e)) {
/* ENOTDIR means this may be a path inside an archive /* ENOTDIR means this may be a path inside an archive
file */ file */
Error error2; is = OpenArchiveInputStream(path, mutex, cond);
is.reset(OpenArchiveInputStream(path, mutex, cond, error2)); if (!is)
if (is == nullptr && error2.IsDefined()) throw;
error = std::move(error2); } else
throw;
} }
#endif #endif

View File

@ -26,13 +26,14 @@
class Path; class Path;
class Mutex; class Mutex;
class Cond; class Cond;
class Error;
/** /**
* Open a "local" file. This is a wrapper for the input plugins * Open a "local" file. This is a wrapper for the input plugins
* "file" and "archive". * "file" and "archive".
*
* Throws std::runtime_error on error.
*/ */
InputStreamPtr InputStreamPtr
OpenLocalInputStream(Path path, Mutex &mutex, Cond &cond, Error &error); OpenLocalInputStream(Path path, Mutex &mutex, Cond &cond);
#endif #endif

View File

@ -28,51 +28,51 @@
#include "fs/AllocatedPath.hxx" #include "fs/AllocatedPath.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include <stdexcept>
InputStreamPtr InputStreamPtr
InputStream::Open(const char *url, InputStream::Open(const char *url,
Mutex &mutex, Cond &cond, Mutex &mutex, Cond &cond)
Error &error)
{ {
if (PathTraitsUTF8::IsAbsolute(url)) { if (PathTraitsUTF8::IsAbsolute(url)) {
Error error;
const auto path = AllocatedPath::FromUTF8(url, error); const auto path = AllocatedPath::FromUTF8(url, error);
if (path.IsNull()) if (path.IsNull())
return nullptr; throw std::runtime_error(error.GetMessage());
return OpenLocalInputStream(path, return OpenLocalInputStream(path, mutex, cond);
mutex, cond, error);
} }
input_plugins_for_each_enabled(plugin) { input_plugins_for_each_enabled(plugin) {
InputStream *is; InputStream *is;
is = plugin->open(url, mutex, cond, error); is = plugin->open(url, mutex, cond);
if (is != nullptr) { if (is != nullptr) {
is = input_rewind_open(is); is = input_rewind_open(is);
return InputStreamPtr(is); return InputStreamPtr(is);
} else if (error.IsDefined()) }
return nullptr;
} }
error.Set(input_domain, "Unrecognized URI"); throw std::runtime_error("Unrecognized URI");
return nullptr;
} }
InputStreamPtr InputStreamPtr
InputStream::OpenReady(const char *uri, InputStream::OpenReady(const char *uri,
Mutex &mutex, Cond &cond, Mutex &mutex, Cond &cond)
Error &error)
{ {
auto is = Open(uri, mutex, cond, error); auto is = Open(uri, mutex, cond);
if (is == nullptr)
return nullptr;
bool success; bool success;
{ {
const ScopeLock protect(mutex); const ScopeLock protect(mutex);
is->WaitReady(); is->WaitReady();
Error error;
success = is->Check(error); success = is->Check(error);
if (!success)
throw std::runtime_error(error.GetMessage());
} }
if (!success) if (!success)

View File

@ -30,6 +30,7 @@
#include "../AsyncInputStream.hxx" #include "../AsyncInputStream.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include "util/RuntimeError.hxx"
#include "util/StringCompare.hxx" #include "util/StringCompare.hxx"
#include "util/ReusableArray.hxx" #include "util/ReusableArray.hxx"
#include "util/ScopeExit.hxx" #include "util/ScopeExit.hxx"
@ -102,8 +103,7 @@ public:
snd_pcm_close(capture_handle); snd_pcm_close(capture_handle);
} }
static InputStream *Create(const char *uri, Mutex &mutex, Cond &cond, static InputStream *Create(const char *uri, Mutex &mutex, Cond &cond);
Error &error);
protected: protected:
/* virtual methods from AsyncInputStream */ /* virtual methods from AsyncInputStream */
@ -120,8 +120,7 @@ protected:
private: private:
static snd_pcm_t *OpenDevice(const char *device, int rate, static snd_pcm_t *OpenDevice(const char *device, int rate,
snd_pcm_format_t format, int channels, snd_pcm_format_t format, int channels);
Error &error);
void Pause() { void Pause() {
AsyncInputStream::Pause(); AsyncInputStream::Pause();
@ -143,8 +142,7 @@ private:
}; };
inline InputStream * inline InputStream *
AlsaInputStream::Create(const char *uri, Mutex &mutex, Cond &cond, AlsaInputStream::Create(const char *uri, Mutex &mutex, Cond &cond)
Error &error)
{ {
const char *device = StringAfterPrefix(uri, "alsa://"); const char *device = StringAfterPrefix(uri, "alsa://");
if (device == nullptr) if (device == nullptr)
@ -160,10 +158,7 @@ AlsaInputStream::Create(const char *uri, Mutex &mutex, Cond &cond,
snd_pcm_format_t format = default_format; snd_pcm_format_t format = default_format;
int channels = default_channels; int channels = default_channels;
snd_pcm_t *handle = OpenDevice(device, rate, format, channels, snd_pcm_t *handle = OpenDevice(device, rate, format, channels);
error);
if (handle == nullptr)
return nullptr;
int frame_size = snd_pcm_format_width(format) / 8 * channels; int frame_size = snd_pcm_format_width(format) / 8 * channels;
return new AlsaInputStream(io_thread_get(), return new AlsaInputStream(io_thread_get(),
@ -242,47 +237,40 @@ AlsaInputStream::Recover(int err)
return err; return err;
} }
static bool static void
ConfigureCapture(snd_pcm_t *capture_handle, ConfigureCapture(snd_pcm_t *capture_handle,
int rate, snd_pcm_format_t format, int channels, int rate, snd_pcm_format_t format, int channels)
Error &error)
{ {
int err; int err;
snd_pcm_hw_params_t *hw_params; snd_pcm_hw_params_t *hw_params;
if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) { if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0)
error.Format(alsa_input_domain, "Cannot allocate hardware parameter structure (%s)", snd_strerror(err)); throw FormatRuntimeError("Cannot allocate hardware parameter structure (%s)",
return false; snd_strerror(err));
}
AtScopeExit(hw_params) { AtScopeExit(hw_params) {
snd_pcm_hw_params_free(hw_params); snd_pcm_hw_params_free(hw_params);
}; };
if ((err = snd_pcm_hw_params_any(capture_handle, hw_params)) < 0) { if ((err = snd_pcm_hw_params_any(capture_handle, hw_params)) < 0)
error.Format(alsa_input_domain, "Cannot initialize hardware parameter structure (%s)", snd_strerror(err)); throw FormatRuntimeError("Cannot initialize hardware parameter structure (%s)",
return false; snd_strerror(err));
}
if ((err = snd_pcm_hw_params_set_access(capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { if ((err = snd_pcm_hw_params_set_access(capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
error.Format(alsa_input_domain, "Cannot set access type (%s)", snd_strerror (err)); throw FormatRuntimeError("Cannot set access type (%s)",
return false; snd_strerror(err));
}
if ((err = snd_pcm_hw_params_set_format(capture_handle, hw_params, format)) < 0) { if ((err = snd_pcm_hw_params_set_format(capture_handle, hw_params, format)) < 0)
error.Format(alsa_input_domain, "Cannot set sample format (%s)", snd_strerror (err)); throw FormatRuntimeError("Cannot set sample format (%s)",
return false; snd_strerror(err));
}
if ((err = snd_pcm_hw_params_set_channels(capture_handle, hw_params, channels)) < 0) { if ((err = snd_pcm_hw_params_set_channels(capture_handle, hw_params, channels)) < 0)
error.Format(alsa_input_domain, "Cannot set channels (%s)", snd_strerror (err)); throw FormatRuntimeError("Cannot set channels (%s)",
return false; snd_strerror(err));
}
if ((err = snd_pcm_hw_params_set_rate(capture_handle, hw_params, rate, 0)) < 0) { if ((err = snd_pcm_hw_params_set_rate(capture_handle, hw_params, rate, 0)) < 0)
error.Format(alsa_input_domain, "Cannot set sample rate (%s)", snd_strerror (err)); throw FormatRuntimeError("Cannot set sample rate (%s)",
return false; snd_strerror(err));
}
/* period needs to be big enough so that poll() doesn't fire too often, /* period needs to be big enough so that poll() doesn't fire too often,
* but small enough that buffer overruns don't occur if Read() is not * but small enough that buffer overruns don't occur if Read() is not
@ -293,17 +281,13 @@ ConfigureCapture(snd_pcm_t *capture_handle,
snd_pcm_uframes_t period = read_buffer_size * 2; snd_pcm_uframes_t period = read_buffer_size * 2;
int direction = -1; int direction = -1;
if ((err = snd_pcm_hw_params_set_period_size_near(capture_handle, hw_params, if ((err = snd_pcm_hw_params_set_period_size_near(capture_handle, hw_params,
&period, &direction)) < 0) { &period, &direction)) < 0)
error.Format(alsa_input_domain, "Cannot set period size (%s)", throw FormatRuntimeError("Cannot set period size (%s)",
snd_strerror(err)); snd_strerror(err));
return false;
}
if ((err = snd_pcm_hw_params(capture_handle, hw_params)) < 0) { if ((err = snd_pcm_hw_params(capture_handle, hw_params)) < 0)
error.Format(alsa_input_domain, "Cannot set parameters (%s)", throw FormatRuntimeError("Cannot set parameters (%s)",
snd_strerror(err)); snd_strerror(err));
return false;
}
snd_pcm_sw_params_t *sw_params; snd_pcm_sw_params_t *sw_params;
@ -315,37 +299,31 @@ ConfigureCapture(snd_pcm_t *capture_handle,
}; };
if ((err = snd_pcm_sw_params_set_start_threshold(capture_handle, sw_params, if ((err = snd_pcm_sw_params_set_start_threshold(capture_handle, sw_params,
period)) < 0) { period)) < 0)
error.Format(alsa_input_domain, throw FormatRuntimeError("unable to set start threshold (%s)",
"unable to set start threshold (%s)", snd_strerror(err)); snd_strerror(err));
return false;
}
if ((err = snd_pcm_sw_params(capture_handle, sw_params)) < 0) { if ((err = snd_pcm_sw_params(capture_handle, sw_params)) < 0)
error.Format(alsa_input_domain, throw FormatRuntimeError("unable to install sw params (%s)",
"unable to install sw params (%s)", snd_strerror(err)); snd_strerror(err));
return false;
}
return true;
} }
inline snd_pcm_t * inline snd_pcm_t *
AlsaInputStream::OpenDevice(const char *device, AlsaInputStream::OpenDevice(const char *device,
int rate, snd_pcm_format_t format, int channels, int rate, snd_pcm_format_t format, int channels)
Error &error)
{ {
snd_pcm_t *capture_handle; snd_pcm_t *capture_handle;
int err; int err;
if ((err = snd_pcm_open(&capture_handle, device, if ((err = snd_pcm_open(&capture_handle, device,
SND_PCM_STREAM_CAPTURE, 0)) < 0) { SND_PCM_STREAM_CAPTURE, 0)) < 0)
error.Format(alsa_input_domain, "Failed to open device: %s (%s)", device, snd_strerror(err)); throw FormatRuntimeError("Failed to open device: %s (%s)",
return nullptr; device, snd_strerror(err));
}
if (!ConfigureCapture(capture_handle, rate, format, channels, error)) { try {
ConfigureCapture(capture_handle, rate, format, channels);
} catch (...) {
snd_pcm_close(capture_handle); snd_pcm_close(capture_handle);
return nullptr; throw;
} }
snd_pcm_prepare(capture_handle); snd_pcm_prepare(capture_handle);
@ -356,9 +334,9 @@ AlsaInputStream::OpenDevice(const char *device,
/*######################### Plugin Functions ##############################*/ /*######################### Plugin Functions ##############################*/
static InputStream * static InputStream *
alsa_input_open(const char *uri, Mutex &mutex, Cond &cond, Error &error) alsa_input_open(const char *uri, Mutex &mutex, Cond &cond)
{ {
return AlsaInputStream::Create(uri, mutex, cond, error); return AlsaInputStream::Create(uri, mutex, cond);
} }
const struct InputPlugin input_plugin_alsa = { const struct InputPlugin input_plugin_alsa = {

View File

@ -25,14 +25,18 @@
#include "archive/ArchivePlugin.hxx" #include "archive/ArchivePlugin.hxx"
#include "archive/ArchiveFile.hxx" #include "archive/ArchiveFile.hxx"
#include "../InputPlugin.hxx" #include "../InputPlugin.hxx"
#include "../InputStream.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "Log.hxx" #include "Log.hxx"
#include "util/ScopeExit.hxx" #include "util/ScopeExit.hxx"
#include "util/Error.hxx"
#include <stdexcept>
#include <stdlib.h> #include <stdlib.h>
InputStream * InputStreamPtr
OpenArchiveInputStream(Path path, Mutex &mutex, Cond &cond, Error &error) OpenArchiveInputStream(Path path, Mutex &mutex, Cond &cond)
{ {
const ArchivePlugin *arplug; const ArchivePlugin *arplug;
@ -57,22 +61,21 @@ OpenArchiveInputStream(Path path, Mutex &mutex, Cond &cond, Error &error)
return nullptr; return nullptr;
} }
Error error;
auto file = archive_file_open(arplug, Path::FromFS(archive), error); auto file = archive_file_open(arplug, Path::FromFS(archive), error);
if (file == nullptr) { if (file == nullptr)
return nullptr; throw std::runtime_error(error.GetMessage());
}
AtScopeExit(file) { AtScopeExit(file) {
file->Close(); file->Close();
}; };
return file->OpenStream(filename, mutex, cond, error); return InputStreamPtr(file->OpenStream(filename, mutex, cond));
} }
static InputStream * static InputStream *
input_archive_open(gcc_unused const char *filename, input_archive_open(gcc_unused const char *filename,
gcc_unused Mutex &mutex, gcc_unused Cond &cond, gcc_unused Mutex &mutex, gcc_unused Cond &cond)
gcc_unused Error &error)
{ {
/* dummy method; use OpenArchiveInputStream() instead */ /* dummy method; use OpenArchiveInputStream() instead */

View File

@ -20,15 +20,15 @@
#ifndef MPD_INPUT_ARCHIVE_HXX #ifndef MPD_INPUT_ARCHIVE_HXX
#define MPD_INPUT_ARCHIVE_HXX #define MPD_INPUT_ARCHIVE_HXX
class InputStream; #include "input/Ptr.hxx"
class Path; class Path;
class Mutex; class Mutex;
class Cond; class Cond;
class Error;
extern const struct InputPlugin input_plugin_archive; extern const struct InputPlugin input_plugin_archive;
InputStream * InputStreamPtr
OpenArchiveInputStream(Path path, Mutex &mutex, Cond &cond, Error &error); OpenArchiveInputStream(Path path, Mutex &mutex, Cond &cond);
#endif #endif

View File

@ -127,7 +127,7 @@ struct cdio_uri {
}; };
static bool static bool
parse_cdio_uri(struct cdio_uri *dest, const char *src, Error &error) parse_cdio_uri(struct cdio_uri *dest, const char *src)
{ {
if (!StringStartsWith(src, "cdda://")) if (!StringStartsWith(src, "cdda://"))
return false; return false;
@ -160,10 +160,8 @@ parse_cdio_uri(struct cdio_uri *dest, const char *src, Error &error)
char *endptr; char *endptr;
dest->track = strtoul(track, &endptr, 10); dest->track = strtoul(track, &endptr, 10);
if (*endptr != 0) { if (*endptr != 0)
error.Set(cdio_domain, "Malformed track number"); throw std::runtime_error("Malformed track number");
return false;
}
if (endptr == track) if (endptr == track)
/* play the whole CD */ /* play the whole CD */
@ -187,35 +185,28 @@ cdio_detect_device(void)
static InputStream * static InputStream *
input_cdio_open(const char *uri, input_cdio_open(const char *uri,
Mutex &mutex, Cond &cond, Mutex &mutex, Cond &cond)
Error &error)
{ {
struct cdio_uri parsed_uri; struct cdio_uri parsed_uri;
if (!parse_cdio_uri(&parsed_uri, uri, error)) if (!parse_cdio_uri(&parsed_uri, uri))
return nullptr; return nullptr;
/* get list of CD's supporting CD-DA */ /* get list of CD's supporting CD-DA */
const AllocatedPath device = parsed_uri.device[0] != 0 const AllocatedPath device = parsed_uri.device[0] != 0
? AllocatedPath::FromFS(parsed_uri.device) ? AllocatedPath::FromFS(parsed_uri.device)
: cdio_detect_device(); : cdio_detect_device();
if (device.IsNull()) { if (device.IsNull())
error.Set(cdio_domain, throw std::runtime_error("Unable find or access a CD-ROM drive with an audio CD in it.");
"Unable find or access a CD-ROM drive with an audio CD in it.");
return nullptr;
}
/* Found such a CD-ROM with a CD-DA loaded. Use the first drive in the list. */ /* Found such a CD-ROM with a CD-DA loaded. Use the first drive in the list. */
const auto cdio = cdio_open(device.c_str(), DRIVER_UNKNOWN); const auto cdio = cdio_open(device.c_str(), DRIVER_UNKNOWN);
if (cdio == nullptr) { if (cdio == nullptr)
error.Set(cdio_domain, "Failed to open CD drive"); throw std::runtime_error("Failed to open CD drive");
return nullptr;
}
const auto drv = cdio_cddap_identify_cdio(cdio, 1, nullptr); const auto drv = cdio_cddap_identify_cdio(cdio, 1, nullptr);
if (drv == nullptr) { if (drv == nullptr) {
error.Set(cdio_domain, "Unable to identify audio CD disc.");
cdio_destroy(cdio); cdio_destroy(cdio);
return nullptr; throw std::runtime_error("Unable to identify audio CD disc.");
} }
cdda_verbose_set(drv, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT); cdda_verbose_set(drv, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT);
@ -223,12 +214,12 @@ input_cdio_open(const char *uri,
if (0 != cdio_cddap_open(drv)) { if (0 != cdio_cddap_open(drv)) {
cdio_cddap_close_no_free_cdio(drv); cdio_cddap_close_no_free_cdio(drv);
cdio_destroy(cdio); cdio_destroy(cdio);
error.Set(cdio_domain, "Unable to open disc."); throw std::runtime_error("Unable to open disc.");
return nullptr;
} }
bool reverse_endian; bool reverse_endian;
switch (data_bigendianp(drv)) { const int be = data_bigendianp(drv);
switch (be) {
case -1: case -1:
LogDebug(cdio_domain, "drive returns unknown audio data"); LogDebug(cdio_domain, "drive returns unknown audio data");
reverse_endian = default_reverse_endian; reverse_endian = default_reverse_endian;
@ -245,11 +236,10 @@ input_cdio_open(const char *uri,
break; break;
default: default:
error.Format(cdio_domain, "Drive returns unknown data type %d",
data_bigendianp(drv));
cdio_cddap_close_no_free_cdio(drv); cdio_cddap_close_no_free_cdio(drv);
cdio_destroy(cdio); cdio_destroy(cdio);
return nullptr; throw FormatRuntimeError("Drive returns unknown data type %d",
be);
} }
lsn_t lsn_from, lsn_to; lsn_t lsn_from, lsn_to;

View File

@ -32,6 +32,7 @@
#include "util/ASCII.hxx" #include "util/ASCII.hxx"
#include "util/StringUtil.hxx" #include "util/StringUtil.hxx"
#include "util/NumberParser.hxx" #include "util/NumberParser.hxx"
#include "util/RuntimeError.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
#include "Log.hxx" #include "Log.hxx"
@ -78,17 +79,18 @@ struct CurlInputStream final : public AsyncInputStream {
CURL_MAX_BUFFERED, CURL_MAX_BUFFERED,
CURL_RESUME_AT), CURL_RESUME_AT),
request_headers(nullptr), request_headers(nullptr),
icy(new IcyInputStream(this)) {} icy(new IcyInputStream(this)) {
InitEasy();
}
~CurlInputStream(); ~CurlInputStream();
CurlInputStream(const CurlInputStream &) = delete; CurlInputStream(const CurlInputStream &) = delete;
CurlInputStream &operator=(const CurlInputStream &) = delete; CurlInputStream &operator=(const CurlInputStream &) = delete;
static InputStream *Open(const char *url, Mutex &mutex, Cond &cond, static InputStream *Open(const char *url, Mutex &mutex, Cond &cond);
Error &error);
bool InitEasy(Error &error); void InitEasy();
/** /**
* Frees the current "libcurl easy" handle, and everything * Frees the current "libcurl easy" handle, and everything
@ -201,7 +203,7 @@ public:
curl_multi_cleanup(multi); curl_multi_cleanup(multi);
} }
bool Add(CurlInputStream *c, Error &error); void Add(CurlInputStream *c);
void Remove(CurlInputStream *c); void Remove(CurlInputStream *c);
/** /**
@ -355,41 +357,39 @@ CurlSocket::OnSocketReady(unsigned flags)
/** /**
* Runs in the I/O thread. No lock needed. * Runs in the I/O thread. No lock needed.
*
* Throws std::runtime_error on error.
*/ */
inline bool inline void
CurlMulti::Add(CurlInputStream *c, Error &error) CurlMulti::Add(CurlInputStream *c)
{ {
assert(io_thread_inside()); assert(io_thread_inside());
assert(c != nullptr); assert(c != nullptr);
assert(c->easy != nullptr); assert(c->easy != nullptr);
CURLMcode mcode = curl_multi_add_handle(multi, c->easy); CURLMcode mcode = curl_multi_add_handle(multi, c->easy);
if (mcode != CURLM_OK) { if (mcode != CURLM_OK)
error.Format(curlm_domain, mcode, throw FormatRuntimeError("curl_multi_add_handle() failed: %s",
"curl_multi_add_handle() failed: %s",
curl_multi_strerror(mcode)); curl_multi_strerror(mcode));
return false;
}
InvalidateSockets(); InvalidateSockets();
return true;
} }
/** /**
* Call input_curl_easy_add() in the I/O thread. May be called from * Call input_curl_easy_add() in the I/O thread. May be called from
* any thread. Caller must not hold a mutex. * any thread. Caller must not hold a mutex.
*
* Throws std::runtime_error on error.
*/ */
static bool static void
input_curl_easy_add_indirect(CurlInputStream *c, Error &error) input_curl_easy_add_indirect(CurlInputStream *c)
{ {
assert(c != nullptr); assert(c != nullptr);
assert(c->easy != nullptr); assert(c->easy != nullptr);
bool result; BlockingCall(io_thread_get(), [c](){
BlockingCall(io_thread_get(), [c, &error, &result](){ curl_multi->Add(c);
result = curl_multi->Add(c, error);
}); });
return result;
} }
inline void inline void
@ -727,14 +727,12 @@ input_curl_writefunction(void *ptr, size_t size, size_t nmemb, void *stream)
return c.DataReceived(ptr, size); return c.DataReceived(ptr, size);
} }
bool void
CurlInputStream::InitEasy(Error &error) CurlInputStream::InitEasy()
{ {
easy = curl_easy_init(); easy = curl_easy_init();
if (easy == nullptr) { if (easy == nullptr)
error.Set(curl_domain, "curl_easy_init() failed"); throw std::runtime_error("curl_easy_init() failed");
return false;
}
curl_easy_setopt(easy, CURLOPT_PRIVATE, (void *)this); curl_easy_setopt(easy, CURLOPT_PRIVATE, (void *)this);
curl_easy_setopt(easy, CURLOPT_USERAGENT, curl_easy_setopt(easy, CURLOPT_USERAGENT,
@ -773,19 +771,14 @@ CurlInputStream::InitEasy(Error &error)
curl_easy_setopt(easy, CURLOPT_SSL_VERIFYHOST, verify_host ? 2l : 0l); curl_easy_setopt(easy, CURLOPT_SSL_VERIFYHOST, verify_host ? 2l : 0l);
CURLcode code = curl_easy_setopt(easy, CURLOPT_URL, GetURI()); CURLcode code = curl_easy_setopt(easy, CURLOPT_URL, GetURI());
if (code != CURLE_OK) { if (code != CURLE_OK)
error.Format(curl_domain, code, throw FormatRuntimeError("curl_easy_setopt() failed: %s",
"curl_easy_setopt() failed: %s",
curl_easy_strerror(code)); curl_easy_strerror(code));
return false;
}
request_headers = nullptr; request_headers = nullptr;
request_headers = curl_slist_append(request_headers, request_headers = curl_slist_append(request_headers,
"Icy-Metadata: 1"); "Icy-Metadata: 1");
curl_easy_setopt(easy, CURLOPT_HTTPHEADER, request_headers); curl_easy_setopt(easy, CURLOPT_HTTPHEADER, request_headers);
return true;
} }
void void
@ -809,11 +802,11 @@ CurlInputStream::DoSeek(offset_type new_offset)
return; return;
} }
Error error; try {
if (!InitEasy(postponed_error)) { InitEasy();
} catch (...) {
mutex.lock(); mutex.lock();
PostponeError(std::move(error)); throw;
return;
} }
/* send the "Range" header */ /* send the "Range" header */
@ -823,10 +816,11 @@ CurlInputStream::DoSeek(offset_type new_offset)
curl_easy_setopt(easy, CURLOPT_RANGE, range); curl_easy_setopt(easy, CURLOPT_RANGE, range);
} }
if (!input_curl_easy_add_indirect(this, error)) { try {
input_curl_easy_add_indirect(this);
} catch (...) {
mutex.lock(); mutex.lock();
PostponeError(std::move(error)); throw;
return;
} }
mutex.lock(); mutex.lock();
@ -834,27 +828,29 @@ CurlInputStream::DoSeek(offset_type new_offset)
} }
inline InputStream * inline InputStream *
CurlInputStream::Open(const char *url, Mutex &mutex, Cond &cond, CurlInputStream::Open(const char *url, Mutex &mutex, Cond &cond)
Error &error)
{ {
CurlInputStream *c = new CurlInputStream(url, mutex, cond); CurlInputStream *c = new CurlInputStream(url, mutex, cond);
if (!c->InitEasy(error) || !input_curl_easy_add_indirect(c, error)) {
try {
c->InitEasy();
input_curl_easy_add_indirect(c);
} catch (...) {
delete c; delete c;
return nullptr; throw;
} }
return c->icy; return c->icy;
} }
static InputStream * static InputStream *
input_curl_open(const char *url, Mutex &mutex, Cond &cond, input_curl_open(const char *url, Mutex &mutex, Cond &cond)
Error &error)
{ {
if (memcmp(url, "http://", 7) != 0 && if (memcmp(url, "http://", 7) != 0 &&
memcmp(url, "https://", 8) != 0) memcmp(url, "https://", 8) != 0)
return nullptr; return nullptr;
return CurlInputStream::Open(url, mutex, cond, error); return CurlInputStream::Open(url, mutex, cond);
} }
const struct InputPlugin input_plugin_curl = { const struct InputPlugin input_plugin_curl = {

View File

@ -84,8 +84,7 @@ input_ffmpeg_init(gcc_unused const ConfigBlock &block)
static InputStream * static InputStream *
input_ffmpeg_open(const char *uri, input_ffmpeg_open(const char *uri,
Mutex &mutex, Cond &cond, Mutex &mutex, Cond &cond)
Error &error)
{ {
if (!StringStartsWith(uri, "gopher://") && if (!StringStartsWith(uri, "gopher://") &&
!StringStartsWith(uri, "rtp://") && !StringStartsWith(uri, "rtp://") &&
@ -97,10 +96,8 @@ input_ffmpeg_open(const char *uri,
AVIOContext *h; AVIOContext *h;
auto result = avio_open(&h, uri, AVIO_FLAG_READ); auto result = avio_open(&h, uri, AVIO_FLAG_READ);
if (result != 0) { if (result != 0)
SetFfmpegError(error, result); throw MakeFfmpegError(result);
return nullptr;
}
return new FfmpegInputStream(uri, mutex, cond, h); return new FfmpegInputStream(uri, mutex, cond, h);
} }

View File

@ -21,18 +21,15 @@
#include "FileInputPlugin.hxx" #include "FileInputPlugin.hxx"
#include "../InputStream.hxx" #include "../InputStream.hxx"
#include "../InputPlugin.hxx" #include "../InputPlugin.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "fs/FileInfo.hxx" #include "fs/FileInfo.hxx"
#include "fs/io/FileReader.hxx" #include "fs/io/FileReader.hxx"
#include "system/FileDescriptor.hxx" #include "system/FileDescriptor.hxx"
#include "util/RuntimeError.hxx"
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
static constexpr Domain file_domain("file");
class FileInputStream final : public InputStream { class FileInputStream final : public InputStream {
FileReader reader; FileReader reader;
@ -56,38 +53,31 @@ public:
bool Seek(offset_type offset, Error &error) override; bool Seek(offset_type offset, Error &error) override;
}; };
InputStream * InputStreamPtr
OpenFileInputStream(Path path, OpenFileInputStream(Path path,
Mutex &mutex, Cond &cond, Mutex &mutex, Cond &cond)
Error &error) {
try {
FileReader reader(path); FileReader reader(path);
const FileInfo info = reader.GetFileInfo(); const FileInfo info = reader.GetFileInfo();
if (!info.IsRegular()) { if (!info.IsRegular())
error.Format(file_domain, "Not a regular file: %s", throw FormatRuntimeError("Not a regular file: %s",
path.c_str()); path.c_str());
return nullptr;
}
#ifdef POSIX_FADV_SEQUENTIAL #ifdef POSIX_FADV_SEQUENTIAL
posix_fadvise(reader.GetFD().Get(), (off_t)0, info.GetSize(), posix_fadvise(reader.GetFD().Get(), (off_t)0, info.GetSize(),
POSIX_FADV_SEQUENTIAL); POSIX_FADV_SEQUENTIAL);
#endif #endif
return new FileInputStream(path.ToUTF8().c_str(), return InputStreamPtr(new FileInputStream(path.ToUTF8().c_str(),
std::move(reader), info.GetSize(), std::move(reader), info.GetSize(),
mutex, cond); mutex, cond));
} catch (const std::exception &e) {
error.Set(std::current_exception());
return nullptr;
} }
static InputStream * static InputStream *
input_file_open(gcc_unused const char *filename, input_file_open(gcc_unused const char *filename,
gcc_unused Mutex &mutex, gcc_unused Cond &cond, gcc_unused Mutex &mutex, gcc_unused Cond &cond)
gcc_unused Error &error)
{ {
/* dummy method; use OpenFileInputStream() instead */ /* dummy method; use OpenFileInputStream() instead */

View File

@ -20,17 +20,16 @@
#ifndef MPD_INPUT_FILE_HXX #ifndef MPD_INPUT_FILE_HXX
#define MPD_INPUT_FILE_HXX #define MPD_INPUT_FILE_HXX
class InputStream; #include "input/Ptr.hxx"
class Path; class Path;
class Mutex; class Mutex;
class Cond; class Cond;
class Error;
extern const struct InputPlugin input_plugin_file; extern const struct InputPlugin input_plugin_file;
InputStream * InputStreamPtr
OpenFileInputStream(Path path, OpenFileInputStream(Path path,
Mutex &mutex, Cond &cond, Mutex &mutex, Cond &cond);
Error &error);
#endif #endif

View File

@ -72,8 +72,7 @@ MmsInputStream::Open(Error &error)
static InputStream * static InputStream *
input_mms_open(const char *url, input_mms_open(const char *url,
Mutex &mutex, Cond &cond, Mutex &mutex, Cond &cond)
gcc_unused Error &error)
{ {
if (!StringStartsWith(url, "mms://") && if (!StringStartsWith(url, "mms://") &&
!StringStartsWith(url, "mmsh://") && !StringStartsWith(url, "mmsh://") &&

View File

@ -57,10 +57,10 @@ public:
DeferClose(); DeferClose();
} }
bool Open(Error &error) { void Open() {
assert(!IsReady()); assert(!IsReady());
return NfsFileReader::Open(GetURI(), error); NfsFileReader::Open(GetURI());
} }
private: private:
@ -119,17 +119,10 @@ NfsInputStream::DoResume()
reconnect_on_resume = false; reconnect_on_resume = false;
reconnecting = true; reconnecting = true;
mutex.unlock(); ScopeUnlock unlock(mutex);
NfsFileReader::Close(); NfsFileReader::Close();
NfsFileReader::Open(GetURI());
Error error;
bool success = NfsFileReader::Open(GetURI(), error);
mutex.lock();
if (!success) {
postponed_error = std::move(error);
cond.broadcast();
}
return; return;
} }
@ -229,16 +222,17 @@ input_nfs_finish()
static InputStream * static InputStream *
input_nfs_open(const char *uri, input_nfs_open(const char *uri,
Mutex &mutex, Cond &cond, Mutex &mutex, Cond &cond)
Error &error)
{ {
if (!StringStartsWith(uri, "nfs://")) if (!StringStartsWith(uri, "nfs://"))
return nullptr; return nullptr;
NfsInputStream *is = new NfsInputStream(uri, mutex, cond); NfsInputStream *is = new NfsInputStream(uri, mutex, cond);
if (!is->Open(error)) { try {
is->Open();
} catch (...) {
delete is; delete is;
return nullptr; throw;
} }
return is; return is;

View File

@ -24,6 +24,7 @@
#include "../InputStream.hxx" #include "../InputStream.hxx"
#include "../InputPlugin.hxx" #include "../InputPlugin.hxx"
#include "PluginUnavailable.hxx" #include "PluginUnavailable.hxx"
#include "system/Error.hxx"
#include "util/StringCompare.hxx" #include "util/StringCompare.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
@ -85,8 +86,7 @@ input_smbclient_init(gcc_unused const ConfigBlock &block)
static InputStream * static InputStream *
input_smbclient_open(const char *uri, input_smbclient_open(const char *uri,
Mutex &mutex, Cond &cond, Mutex &mutex, Cond &cond)
Error &error)
{ {
if (!StringStartsWith(uri, "smb://")) if (!StringStartsWith(uri, "smb://"))
return nullptr; return nullptr;
@ -94,33 +94,30 @@ input_smbclient_open(const char *uri,
const ScopeLock protect(smbclient_mutex); const ScopeLock protect(smbclient_mutex);
SMBCCTX *ctx = smbc_new_context(); SMBCCTX *ctx = smbc_new_context();
if (ctx == nullptr) { if (ctx == nullptr)
error.SetErrno("smbc_new_context() failed"); throw MakeErrno("smbc_new_context() failed");
return nullptr;
}
SMBCCTX *ctx2 = smbc_init_context(ctx); SMBCCTX *ctx2 = smbc_init_context(ctx);
if (ctx2 == nullptr) { if (ctx2 == nullptr) {
error.SetErrno("smbc_init_context() failed"); int e = errno;
smbc_free_context(ctx, 1); smbc_free_context(ctx, 1);
return nullptr; throw MakeErrno(e, "smbc_init_context() failed");
} }
ctx = ctx2; ctx = ctx2;
int fd = smbc_open(uri, O_RDONLY, 0); int fd = smbc_open(uri, O_RDONLY, 0);
if (fd < 0) { if (fd < 0) {
error.SetErrno("smbc_open() failed"); int e = errno;
smbc_free_context(ctx, 1); smbc_free_context(ctx, 1);
return nullptr; throw MakeErrno(e, "smbc_open() failed");
} }
struct stat st; struct stat st;
if (smbc_fstat(fd, &st) < 0) { if (smbc_fstat(fd, &st) < 0) {
error.SetErrno("smbc_fstat() failed"); int e = errno;
smbc_close(fd);
smbc_free_context(ctx, 1); smbc_free_context(ctx, 1);
return nullptr; throw MakeErrno(e, "smbc_fstat() failed");
} }
return new SmbclientInputStream(uri, mutex, cond, ctx, fd, st); return new SmbclientInputStream(uri, mutex, cond, ctx, fd, st);

View File

@ -26,6 +26,14 @@ extern "C" {
#include <libavutil/error.h> #include <libavutil/error.h>
} }
std::runtime_error
MakeFfmpegError(int errnum)
{
char msg[256];
av_strerror(errnum, msg, sizeof(msg));
return std::runtime_error(msg);
}
void void
SetFfmpegError(Error &error, int errnum) SetFfmpegError(Error &error, int errnum)
{ {

View File

@ -20,8 +20,13 @@
#ifndef MPD_FFMPEG_ERROR_HXX #ifndef MPD_FFMPEG_ERROR_HXX
#define MPD_FFMPEG_ERROR_HXX #define MPD_FFMPEG_ERROR_HXX
#include <stdexcept>
class Error; class Error;
std::runtime_error
MakeFfmpegError(int errnum);
void void
SetFfmpegError(Error &error, int errnum); SetFfmpegError(Error &error, int errnum);

View File

@ -91,23 +91,19 @@ NfsFileReader::DeferClose()
BlockingCall(io_thread_get(), [this](){ Close(); }); BlockingCall(io_thread_get(), [this](){ Close(); });
} }
bool void
NfsFileReader::Open(const char *uri, Error &error) NfsFileReader::Open(const char *uri)
{ {
assert(state == State::INITIAL); assert(state == State::INITIAL);
if (!StringStartsWith(uri, "nfs://")) { if (!StringStartsWith(uri, "nfs://"))
error.Set(nfs_domain, "Malformed nfs:// URI"); throw std::runtime_error("Malformed nfs:// URI");
return false;
}
uri += 6; uri += 6;
const char *slash = strchr(uri, '/'); const char *slash = strchr(uri, '/');
if (slash == nullptr) { if (slash == nullptr)
error.Set(nfs_domain, "Malformed nfs:// URI"); throw std::runtime_error("Malformed nfs:// URI");
return false;
}
server = std::string(uri, slash); server = std::string(uri, slash);
@ -121,10 +117,8 @@ NfsFileReader::Open(const char *uri, Error &error)
path = new_path; path = new_path;
} else { } else {
slash = strrchr(uri + 1, '/'); slash = strrchr(uri + 1, '/');
if (slash == nullptr || slash[1] == 0) { if (slash == nullptr || slash[1] == 0)
error.Set(nfs_domain, "Malformed nfs:// URI"); throw std::runtime_error("Malformed nfs:// URI");
return false;
}
export_name = std::string(uri, slash); export_name = std::string(uri, slash);
path = slash; path = slash;
@ -132,7 +126,6 @@ NfsFileReader::Open(const char *uri, Error &error)
state = State::DEFER; state = State::DEFER;
DeferredMonitor::Schedule(); DeferredMonitor::Schedule();
return true;
} }
bool bool

View File

@ -61,7 +61,11 @@ public:
void Close(); void Close();
void DeferClose(); void DeferClose();
bool Open(const char *uri, Error &error); /**
* Throws std::runtime_error on error.
*/
void Open(const char *uri);
bool Read(uint64_t offset, size_t size, Error &error); bool Read(uint64_t offset, size_t size, Error &error);
void CancelRead(); void CancelRead();

View File

@ -44,13 +44,7 @@ try {
if (!playlist_suffix_supported(suffix_utf8.c_str())) if (!playlist_suffix_supported(suffix_utf8.c_str()))
return nullptr; return nullptr;
Error error; auto is = OpenLocalInputStream(path, mutex, cond);
auto is = OpenLocalInputStream(path, mutex, cond, error);
if (is == nullptr) {
LogError(error);
return nullptr;
}
return playlist_list_open_stream_suffix(std::move(is), return playlist_list_open_stream_suffix(std::move(is),
suffix_utf8.c_str()); suffix_utf8.c_str());
} catch (const std::runtime_error &e) { } catch (const std::runtime_error &e) {
@ -85,15 +79,7 @@ try {
if (playlist != nullptr) if (playlist != nullptr)
return playlist; return playlist;
Error error; auto is = InputStream::OpenReady(uri, mutex, cond);
auto is = InputStream::OpenReady(uri, mutex, cond, error);
if (is == nullptr) {
if (error.IsDefined())
FormatError(error, "Failed to open %s", uri);
return nullptr;
}
return playlist_list_open_stream(std::move(is), uri); return playlist_list_open_stream(std::move(is), uri);
} catch (const std::runtime_error &e) { } catch (const std::runtime_error &e) {
LogError(e); LogError(e);

View File

@ -230,15 +230,9 @@ static constexpr yajl_callbacks parse_callbacks = {
static int static int
soundcloud_parse_json(const char *url, yajl_handle hand, soundcloud_parse_json(const char *url, yajl_handle hand,
Mutex &mutex, Cond &cond) Mutex &mutex, Cond &cond)
{ try {
Error error; Error error;
auto input_stream = InputStream::OpenReady(url, mutex, cond, auto input_stream = InputStream::OpenReady(url, mutex, cond);
error);
if (input_stream == nullptr) {
if (error.IsDefined())
LogError(error);
return -1;
}
const ScopeLock protect(mutex); const ScopeLock protect(mutex);
@ -275,6 +269,9 @@ soundcloud_parse_json(const char *url, yajl_handle hand,
} }
return 0; return 0;
} catch (const std::exception &e) {
LogError(e);
return -1;
} }
/** /**

View File

@ -140,6 +140,19 @@ IsFileNotFound(const std::system_error &e)
#endif #endif
} }
gcc_pure
static inline bool
IsPathNotFound(const std::system_error &e)
{
#ifdef WIN32
return e.code().category() == std::system_category() &&
e.code().value() == ERROR_PATH_NOT_FOUND;
#else
return e.code().category() == std::system_category() &&
e.code().value() == ENOTDIR;
#endif
}
gcc_pure gcc_pure
static inline bool static inline bool
IsAccessDenied(const std::system_error &e) IsAccessDenied(const std::system_error &e)

View File

@ -53,13 +53,7 @@ try {
Mutex mutex; Mutex mutex;
Cond cond; Cond cond;
Error error; auto is = OpenLocalInputStream(path, mutex, cond);
auto is = OpenLocalInputStream(path, mutex, cond, error);
if (!is) {
LogError(error);
return false;
}
return ScanGenericTags(*is, handler, ctx); return ScanGenericTags(*is, handler, ctx);
} catch (const std::runtime_error &e) { } catch (const std::runtime_error &e) {
LogError(e); LogError(e);

View File

@ -74,9 +74,9 @@ decoder_seek_error(gcc_unused Decoder &decoder)
} }
InputStreamPtr InputStreamPtr
decoder_open_uri(Decoder &decoder, const char *uri, Error &error) decoder_open_uri(Decoder &decoder, const char *uri)
{ {
return InputStream::OpenReady(uri, decoder.mutex, decoder.cond, error); return InputStream::OpenReady(uri, decoder.mutex, decoder.cond);
} }
size_t size_t

View File

@ -26,7 +26,6 @@
#include "input/InputStream.hxx" #include "input/InputStream.hxx"
#include "input/LocalOpen.hxx" #include "input/LocalOpen.hxx"
#include "util/StringView.hxx" #include "util/StringView.hxx"
#include "util/Error.hxx"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -49,7 +48,7 @@ MyApeTagCallback(gcc_unused unsigned long flags,
int int
main(int argc, char **argv) main(int argc, char **argv)
{ try {
#ifdef HAVE_LOCALE_H #ifdef HAVE_LOCALE_H
/* initialize locale */ /* initialize locale */
setlocale(LC_CTYPE,""); setlocale(LC_CTYPE,"");
@ -65,12 +64,7 @@ main(int argc, char **argv)
Mutex mutex; Mutex mutex;
Cond cond; Cond cond;
Error error; auto is = OpenLocalInputStream(path, mutex, cond);
auto is = OpenLocalInputStream(path, mutex, cond, error);
if (!is) {
LogError(error);
return EXIT_FAILURE;
}
if (!tag_ape_scan(*is, MyApeTagCallback)) { if (!tag_ape_scan(*is, MyApeTagCallback)) {
fprintf(stderr, "error\n"); fprintf(stderr, "error\n");
@ -78,4 +72,7 @@ main(int argc, char **argv)
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
} catch (const std::exception &e) {
LogError(e);
return EXIT_FAILURE;
} }

View File

@ -31,7 +31,6 @@
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "fs/io/BufferedOutputStream.hxx" #include "fs/io/BufferedOutputStream.hxx"
#include "fs/io/StdioOutputStream.hxx" #include "fs/io/StdioOutputStream.hxx"
#include "util/Error.hxx"
#include "thread/Cond.hxx" #include "thread/Cond.hxx"
#include "Log.hxx" #include "Log.hxx"
@ -63,7 +62,6 @@ try {
config_global_init(); config_global_init();
Error error;
ReadConfigFile(config_path); ReadConfigFile(config_path);
const ScopeIOThread io_thread; const ScopeIOThread io_thread;
@ -82,15 +80,7 @@ try {
if (playlist == NULL) { if (playlist == NULL) {
/* open the stream and wait until it becomes ready */ /* open the stream and wait until it becomes ready */
is = InputStream::OpenReady(uri, mutex, cond, error); is = InputStream::OpenReady(uri, mutex, cond);
if (!is) {
if (error.IsDefined())
LogError(error);
else
fprintf(stderr,
"InputStream::Open() failed\n");
return 2;
}
/* open the playlist */ /* open the playlist */

View File

@ -24,7 +24,6 @@
#include "config/ConfigGlobal.hxx" #include "config/ConfigGlobal.hxx"
#include "thread/Mutex.hxx" #include "thread/Mutex.hxx"
#include "thread/Cond.hxx" #include "thread/Cond.hxx"
#include "util/Error.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "input/InputStream.hxx" #include "input/InputStream.hxx"
#include "input/LocalOpen.hxx" #include "input/LocalOpen.hxx"
@ -47,7 +46,7 @@ config_get_string(gcc_unused enum ConfigOption option,
} }
int main(int argc, char **argv) int main(int argc, char **argv)
{ try {
#ifdef HAVE_LOCALE_H #ifdef HAVE_LOCALE_H
/* initialize locale */ /* initialize locale */
setlocale(LC_CTYPE,""); setlocale(LC_CTYPE,"");
@ -63,12 +62,7 @@ int main(int argc, char **argv)
Mutex mutex; Mutex mutex;
Cond cond; Cond cond;
Error error; auto is = OpenLocalInputStream(path, mutex, cond);
auto is = OpenLocalInputStream(path, mutex, cond, error);
if (!is) {
LogError(error);
return EXIT_FAILURE;
}
const auto tag = tag_id3_load(*is); const auto tag = tag_id3_load(*is);
if (tag == NULL) { if (tag == NULL) {
@ -96,4 +90,7 @@ int main(int argc, char **argv)
tuple->gain, tuple->peak); tuple->gain, tuple->peak);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} catch (const std::exception &e) {
LogError(e);
return EXIT_FAILURE;
} }

View File

@ -83,7 +83,6 @@ try {
archive_plugin_init_all(); archive_plugin_init_all();
#endif #endif
Error error;
input_stream_global_init(); input_stream_global_init();
/* open the stream and dump it */ /* open the stream and dump it */
@ -92,16 +91,8 @@ try {
Mutex mutex; Mutex mutex;
Cond cond; Cond cond;
auto is = InputStream::OpenReady(argv[1], mutex, cond, error); auto is = InputStream::OpenReady(argv[1], mutex, cond);
if (is) {
ret = dump_input_stream(std::move(is)); ret = dump_input_stream(std::move(is));
} else {
if (error.IsDefined())
LogError(error);
else
fprintf(stderr, "input_stream::Open() failed\n");
ret = EXIT_FAILURE;
}
} }
/* deinitialize everything */ /* deinitialize everything */

View File

@ -26,7 +26,6 @@
#include "AudioFormat.hxx" #include "AudioFormat.hxx"
#include "tag/TagHandler.hxx" #include "tag/TagHandler.hxx"
#include "tag/Generic.hxx" #include "tag/Generic.hxx"
#include "util/Error.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "thread/Cond.hxx" #include "thread/Cond.hxx"
#include "Log.hxx" #include "Log.hxx"
@ -89,7 +88,6 @@ try {
const ScopeIOThread io_thread; const ScopeIOThread io_thread;
Error error;
input_stream_global_init(); input_stream_global_init();
decoder_plugin_init_all(); decoder_plugin_init_all();
@ -105,13 +103,7 @@ try {
Cond cond; Cond cond;
auto is = InputStream::OpenReady(path.c_str(), auto is = InputStream::OpenReady(path.c_str(),
mutex, cond, mutex, cond);
error);
if (!is) {
FormatError(error, "Failed to open %s", path.c_str());
return EXIT_FAILURE;
}
success = plugin->ScanStream(*is, print_handler, nullptr); success = plugin->ScanStream(*is, print_handler, nullptr);
} }

View File

@ -26,7 +26,6 @@
#include "input/InputStream.hxx" #include "input/InputStream.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "AudioFormat.hxx" #include "AudioFormat.hxx"
#include "util/Error.hxx"
#include "Log.hxx" #include "Log.hxx"
#include <stdexcept> #include <stdexcept>
@ -49,7 +48,6 @@ try {
const ScopeIOThread io_thread; const ScopeIOThread io_thread;
Error error;
input_stream_global_init(); input_stream_global_init();
decoder_plugin_init_all(); decoder_plugin_init_all();
@ -64,16 +62,7 @@ try {
plugin->FileDecode(decoder, Path::FromFS(uri)); plugin->FileDecode(decoder, Path::FromFS(uri));
} else if (plugin->stream_decode != nullptr) { } else if (plugin->stream_decode != nullptr) {
auto is = InputStream::OpenReady(uri, decoder.mutex, auto is = InputStream::OpenReady(uri, decoder.mutex,
decoder.cond, error); decoder.cond);
if (!is) {
if (error.IsDefined())
LogError(error);
else
fprintf(stderr, "InputStream::Open() failed\n");
return EXIT_FAILURE;
}
plugin->StreamDecode(decoder, *is); plugin->StreamDecode(decoder, *is);
} else { } else {
fprintf(stderr, "Decoder plugin is not usable\n"); fprintf(stderr, "Decoder plugin is not usable\n");

View File

@ -118,16 +118,8 @@ try {
{ {
Mutex mutex; Mutex mutex;
Cond cond; Cond cond;
auto is = InputStream::OpenReady(argv[1], mutex, cond, error); auto is = InputStream::OpenReady(argv[1], mutex, cond);
if (is) {
ret = dump_input_stream(is.get()); ret = dump_input_stream(is.get());
} else {
if (error.IsDefined())
LogError(error);
else
fprintf(stderr, "input_stream::Open() failed\n");
ret = EXIT_FAILURE;
}
} }
/* deinitialize everything */ /* deinitialize everything */