diff options
Diffstat (limited to 'src')
36 files changed, 340 insertions, 390 deletions
diff --git a/src/TagArchive.cxx b/src/TagArchive.cxx index a5a849d7b..dd1b73a38 100644 --- a/src/TagArchive.cxx +++ b/src/TagArchive.cxx @@ -28,26 +28,28 @@ bool tag_archive_scan(ArchiveFile &archive, const char *path_utf8, const TagHandler &handler, void *handler_ctx) -{ +try { Mutex mutex; Cond cond; - InputStreamPtr is(archive.OpenStream(path_utf8, mutex, cond, - IgnoreError())); + InputStreamPtr is(archive.OpenStream(path_utf8, mutex, cond)); if (!is) return false; return tag_stream_scan(*is, handler, handler_ctx); +} catch (const std::exception &e) { + return false; } bool tag_archive_scan(ArchiveFile &archive, const char *path_utf8, TagBuilder &builder) -{ +try { Mutex mutex; Cond cond; - InputStreamPtr is(archive.OpenStream(path_utf8, mutex, cond, - IgnoreError())); + InputStreamPtr is(archive.OpenStream(path_utf8, mutex, cond)); return is && tag_stream_scan(*is, builder); +} catch (const std::exception &e) { + return false; } diff --git a/src/TagFile.cxx b/src/TagFile.cxx index 56e235462..8c6ccb61a 100644 --- a/src/TagFile.cxx +++ b/src/TagFile.cxx @@ -30,6 +30,8 @@ #include "input/LocalOpen.hxx" #include "thread/Cond.hxx" +#include <stdexcept> + #include <assert.h> class TagFileScan { @@ -60,11 +62,12 @@ public: /* open the InputStream (if not already open) */ if (is == nullptr) { - is = OpenLocalInputStream(path_fs, - mutex, cond, - IgnoreError()); - if (is == nullptr) + try { + is = OpenLocalInputStream(path_fs, + mutex, cond); + } catch (const std::runtime_error &) { return false; + } } else is->LockRewind(IgnoreError()); diff --git a/src/TagStream.cxx b/src/TagStream.cxx index 1ffeac128..45b18e60f 100644 --- a/src/TagStream.cxx +++ b/src/TagStream.cxx @@ -72,13 +72,14 @@ tag_stream_scan(InputStream &is, const TagHandler &handler, void *ctx) bool tag_stream_scan(const char *uri, const TagHandler &handler, void *ctx) -{ +try { Mutex mutex; Cond cond; - auto is = InputStream::OpenReady(uri, mutex, cond, - IgnoreError()); - return is && tag_stream_scan(*is, handler, ctx); + auto is = InputStream::OpenReady(uri, mutex, cond); + return tag_stream_scan(*is, handler, ctx); +} catch (const std::exception &e) { + return false; } bool @@ -97,11 +98,12 @@ tag_stream_scan(InputStream &is, TagBuilder &builder) bool tag_stream_scan(const char *uri, TagBuilder &builder) -{ +try { Mutex mutex; Cond cond; - auto is = InputStream::OpenReady(uri, mutex, cond, - IgnoreError()); - return is && tag_stream_scan(*is, builder); + auto is = InputStream::OpenReady(uri, mutex, cond); + return tag_stream_scan(*is, builder); +} catch (const std::exception &e) { + return false; } diff --git a/src/archive/ArchiveFile.hxx b/src/archive/ArchiveFile.hxx index 3e9e7a208..b7335072c 100644 --- a/src/archive/ArchiveFile.hxx +++ b/src/archive/ArchiveFile.hxx @@ -51,11 +51,12 @@ public: /** * Opens an InputStream of a file within the archive. * + * Throws std::runtime_error on error. + * * @param path the path within the archive */ virtual InputStream *OpenStream(const char *path, - Mutex &mutex, Cond &cond, - Error &error) = 0; + Mutex &mutex, Cond &cond) = 0; }; #endif diff --git a/src/archive/plugins/Bzip2ArchivePlugin.cxx b/src/archive/plugins/Bzip2ArchivePlugin.cxx index 63ff2841c..1601b8c42 100644 --- a/src/archive/plugins/Bzip2ArchivePlugin.cxx +++ b/src/archive/plugins/Bzip2ArchivePlugin.cxx @@ -36,6 +36,8 @@ #include <bzlib.h> +#include <stdexcept> + #include <stddef.h> class Bzip2ArchiveFile final : public ArchiveFile { @@ -74,9 +76,8 @@ public: visitor.VisitArchiveEntry(name.c_str()); } - virtual InputStream *OpenStream(const char *path, - Mutex &mutex, Cond &cond, - Error &error) override; + InputStream *OpenStream(const char *path, + Mutex &mutex, Cond &cond) override; }; class Bzip2InputStream final : public InputStream { @@ -93,13 +94,12 @@ public: Mutex &mutex, Cond &cond); ~Bzip2InputStream(); - bool Open(Error &error); - /* virtual methods from InputStream */ bool IsEOF() override; size_t Read(void *ptr, size_t size, Error &error) override; private: + void Open(); bool FillBuffer(Error &error); }; @@ -107,8 +107,8 @@ static constexpr Domain bz2_domain("bz2"); /* single archive handling allocation helpers */ -inline bool -Bzip2InputStream::Open(Error &error) +inline void +Bzip2InputStream::Open() { bzstream.bzalloc = nullptr; bzstream.bzfree = nullptr; @@ -118,27 +118,20 @@ Bzip2InputStream::Open(Error &error) bzstream.avail_in = 0; int ret = BZ2_bzDecompressInit(&bzstream, 0, 0); - if (ret != BZ_OK) { - error.Set(bz2_domain, ret, - "BZ2_bzDecompressInit() has failed"); - return false; - } + if (ret != BZ_OK) + throw std::runtime_error("BZ2_bzDecompressInit() has failed"); SetReady(); - return true; } /* archive open && listing routine */ static ArchiveFile * -bz2_open(Path pathname, Error &error) +bz2_open(Path pathname, gcc_unused Error &error) { static Mutex mutex; static Cond cond; - auto is = OpenLocalInputStream(pathname, mutex, cond, error); - if (is == nullptr) - return nullptr; - + auto is = OpenLocalInputStream(pathname, mutex, cond); return new Bzip2ArchiveFile(pathname, std::move(is)); } @@ -150,6 +143,7 @@ Bzip2InputStream::Bzip2InputStream(Bzip2ArchiveFile &_context, :InputStream(_uri, _mutex, _cond), archive(&_context) { + Open(); archive->Ref(); } @@ -161,16 +155,9 @@ Bzip2InputStream::~Bzip2InputStream() InputStream * Bzip2ArchiveFile::OpenStream(const char *path, - Mutex &mutex, Cond &cond, - Error &error) + Mutex &mutex, Cond &cond) { - Bzip2InputStream *bis = new Bzip2InputStream(*this, path, mutex, cond); - if (!bis->Open(error)) { - delete bis; - return nullptr; - } - - return bis; + return new Bzip2InputStream(*this, path, mutex, cond); } inline bool diff --git a/src/archive/plugins/Iso9660ArchivePlugin.cxx b/src/archive/plugins/Iso9660ArchivePlugin.cxx index d077e3aef..44e3ae71a 100644 --- a/src/archive/plugins/Iso9660ArchivePlugin.cxx +++ b/src/archive/plugins/Iso9660ArchivePlugin.cxx @@ -29,6 +29,7 @@ #include "input/InputStream.hxx" #include "fs/Path.hxx" #include "util/RefCount.hxx" +#include "util/RuntimeError.hxx" #include "util/Error.hxx" #include "util/Domain.hxx" @@ -77,9 +78,8 @@ public: virtual void Visit(ArchiveVisitor &visitor) override; - virtual InputStream *OpenStream(const char *path, - Mutex &mutex, Cond &cond, - Error &error) override; + InputStream *OpenStream(const char *path, + Mutex &mutex, Cond &cond) override; }; static constexpr Domain iso9660_domain("iso9660"); @@ -175,15 +175,12 @@ public: InputStream * Iso9660ArchiveFile::OpenStream(const char *pathname, - Mutex &mutex, Cond &cond, - Error &error) + Mutex &mutex, Cond &cond) { auto statbuf = iso9660_ifs_stat_translate(iso, pathname); - if (statbuf == nullptr) { - error.Format(iso9660_domain, - "not found in the ISO file: %s", pathname); - return nullptr; - } + if (statbuf == nullptr) + throw FormatRuntimeError("not found in the ISO file: %s", + pathname); return new Iso9660InputStream(*this, pathname, mutex, cond, statbuf); diff --git a/src/archive/plugins/ZzipArchivePlugin.cxx b/src/archive/plugins/ZzipArchivePlugin.cxx index e83edb09b..45ae02cc3 100644 --- a/src/archive/plugins/ZzipArchivePlugin.cxx +++ b/src/archive/plugins/ZzipArchivePlugin.cxx @@ -29,6 +29,7 @@ #include "input/InputStream.hxx" #include "fs/Path.hxx" #include "util/RefCount.hxx" +#include "util/RuntimeError.hxx" #include "util/Error.hxx" #include "util/Domain.hxx" @@ -58,9 +59,8 @@ public: virtual void Visit(ArchiveVisitor &visitor) override; - virtual InputStream *OpenStream(const char *path, - Mutex &mutex, Cond &cond, - Error &error) override; + InputStream *OpenStream(const char *path, + Mutex &mutex, Cond &cond) override; }; static constexpr Domain zzip_domain("zzip"); @@ -129,15 +129,12 @@ struct ZzipInputStream final : public InputStream { InputStream * ZzipArchiveFile::OpenStream(const char *pathname, - Mutex &mutex, Cond &cond, - Error &error) + Mutex &mutex, Cond &cond) { ZZIP_FILE *_file = zzip_file_open(dir, pathname, 0); - if (_file == nullptr) { - error.Format(zzip_domain, "not found in the ZIP file: %s", - pathname); - return nullptr; - } + if (_file == nullptr) + throw FormatRuntimeError("not found in the ZIP file: %s", + pathname); return new ZzipInputStream(*this, pathname, mutex, cond, diff --git a/src/decoder/DecoderAPI.cxx b/src/decoder/DecoderAPI.cxx index cfcb44766..aaba8fd37 100644 --- a/src/decoder/DecoderAPI.cxx +++ b/src/decoder/DecoderAPI.cxx @@ -258,7 +258,7 @@ void decoder_seek_error(Decoder & decoder) } 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 || decoder.dc.state == DecoderState::DECODE); @@ -267,9 +267,7 @@ decoder_open_uri(Decoder &decoder, const char *uri, Error &error) Mutex &mutex = dc.mutex; Cond &cond = dc.cond; - auto is = InputStream::Open(uri, mutex, cond, error); - if (!is) - return nullptr; + auto is = InputStream::Open(uri, mutex, cond); const ScopeLock lock(mutex); while (true) { diff --git a/src/decoder/DecoderAPI.hxx b/src/decoder/DecoderAPI.hxx index 3ca082a3b..1433e5fd4 100644 --- a/src/decoder/DecoderAPI.hxx +++ b/src/decoder/DecoderAPI.hxx @@ -121,11 +121,12 @@ decoder_seek_error(Decoder &decoder); /** * Open a new #InputStream and wait until it's ready. Can get - * cancelled by DecoderCommand::STOP (returns nullptr without setting - * #Error). + * cancelled by DecoderCommand::STOP (returns nullptr). + * + * Throws std::runtime_error on error. */ 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. diff --git a/src/decoder/DecoderThread.cxx b/src/decoder/DecoderThread.cxx index bb8ef13dc..71634724f 100644 --- a/src/decoder/DecoderThread.cxx +++ b/src/decoder/DecoderThread.cxx @@ -56,10 +56,7 @@ static constexpr Domain decoder_thread_domain("decoder_thread"); static InputStreamPtr decoder_input_stream_open(DecoderControl &dc, const char *uri) { - Error error; - auto is = InputStream::Open(uri, dc.mutex, dc.cond, error); - if (is == nullptr) - throw error; + auto is = InputStream::Open(uri, dc.mutex, dc.cond); /* wait for the input stream to become ready; its metadata will be available then */ @@ -76,6 +73,7 @@ decoder_input_stream_open(DecoderControl &dc, const char *uri) is->Update(); } + Error error; if (!is->Check(error)) throw error; @@ -85,10 +83,7 @@ decoder_input_stream_open(DecoderControl &dc, const char *uri) static InputStreamPtr decoder_input_stream_open(DecoderControl &dc, Path path) { - Error error; - auto is = OpenLocalInputStream(path, dc.mutex, dc.cond, error); - if (is == nullptr) - throw error; + auto is = OpenLocalInputStream(path, dc.mutex, dc.cond); assert(is->IsReady()); diff --git a/src/decoder/plugins/WavpackDecoderPlugin.cxx b/src/decoder/plugins/WavpackDecoderPlugin.cxx index 3a872ce29..8ab06a761 100644 --- a/src/decoder/plugins/WavpackDecoderPlugin.cxx +++ b/src/decoder/plugins/WavpackDecoderPlugin.cxx @@ -34,6 +34,8 @@ #include <wavpack/wavpack.h> +#include <stdexcept> + #include <assert.h> #include <stdio.h> #include <stdlib.h> @@ -490,7 +492,11 @@ wavpack_open_wvc(Decoder &decoder, const char *uri) free(wvc_url); }; - return decoder_open_uri(decoder, uri, IgnoreError()); + try { + return decoder_open_uri(decoder, uri); + } catch (const std::runtime_error &) { + return nullptr; + } } /* diff --git a/src/input/AsyncInputStream.cxx b/src/input/AsyncInputStream.cxx index d1445579a..d5092e42e 100644 --- a/src/input/AsyncInputStream.cxx +++ b/src/input/AsyncInputStream.cxx @@ -81,6 +81,7 @@ AsyncInputStream::Resume() if (paused) { paused = false; + DoResume(); } } @@ -264,7 +265,12 @@ AsyncInputStream::DeferredResume() { const ScopeLock protect(mutex); - Resume(); + try { + Resume(); + } catch (...) { + postponed_exception = std::current_exception(); + cond.broadcast(); + } } void @@ -274,10 +280,16 @@ AsyncInputStream::DeferredSeek() if (seek_state != SeekState::SCHEDULED) return; - Resume(); + try { + Resume(); - seek_state = SeekState::PENDING; - buffer.Clear(); - paused = false; - DoSeek(seek_offset); + seek_state = SeekState::PENDING; + buffer.Clear(); + paused = false; + + DoSeek(seek_offset); + } catch (...) { + postponed_exception = std::current_exception(); + cond.broadcast(); + } } diff --git a/src/input/InputPlugin.hxx b/src/input/InputPlugin.hxx index 08a9d42fd..d33161c93 100644 --- a/src/input/InputPlugin.hxx +++ b/src/input/InputPlugin.hxx @@ -36,7 +36,6 @@ struct ConfigBlock; class InputStream; -class Error; struct Tag; struct InputPlugin { @@ -58,9 +57,11 @@ struct InputPlugin { */ void (*finish)(); + /** + * Throws std::runtime_error on error. + */ InputStream *(*open)(const char *uri, - Mutex &mutex, Cond &cond, - Error &error); + Mutex &mutex, Cond &cond); }; #endif diff --git a/src/input/InputStream.hxx b/src/input/InputStream.hxx index aabbc8ef5..d93784991 100644 --- a/src/input/InputStream.hxx +++ b/src/input/InputStream.hxx @@ -115,16 +115,17 @@ public: * Opens a new input stream. You may not access it until the "ready" * flag is set. * + * Throws std::runtime_error on error. + * * @param mutex a mutex that is used to protect this object; must be * locked before calling any of the public methods * @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 * notifications - * @return an #InputStream object on success, nullptr on error + * @return an #InputStream object on success */ gcc_nonnull_all - static InputStreamPtr Open(const char *uri, Mutex &mutex, Cond &cond, - Error &error); + static InputStreamPtr Open(const char *uri, Mutex &mutex, Cond &cond); /** * Just like Open(), but waits for the stream to become ready. @@ -132,8 +133,7 @@ public: */ gcc_nonnull_all static InputStreamPtr OpenReady(const char *uri, - Mutex &mutex, Cond &cond, - Error &error); + Mutex &mutex, Cond &cond); /** * The absolute URI which was used to open this stream. diff --git a/src/input/LocalOpen.cxx b/src/input/LocalOpen.cxx index 58bf57ee2..f5b66e96d 100644 --- a/src/input/LocalOpen.cxx +++ b/src/input/LocalOpen.cxx @@ -27,7 +27,7 @@ #endif #include "fs/Path.hxx" -#include "util/Error.hxx" +#include "system/Error.hxx" #include <assert.h> @@ -36,20 +36,24 @@ #endif 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 - if (is == nullptr && error.IsDomain(errno_domain) && - error.GetCode() == ENOTDIR) { - /* ENOTDIR means this may be a path inside an archive - file */ - Error error2; - is.reset(OpenArchiveInputStream(path, mutex, cond, error2)); - if (is == nullptr && error2.IsDefined()) - error = std::move(error2); + try { +#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 + file */ + is = OpenArchiveInputStream(path, mutex, cond); + if (!is) + throw; + } else + throw; } #endif diff --git a/src/input/LocalOpen.hxx b/src/input/LocalOpen.hxx index 787c644b3..3b8e95997 100644 --- a/src/input/LocalOpen.hxx +++ b/src/input/LocalOpen.hxx @@ -26,13 +26,14 @@ class Path; class Mutex; class Cond; -class Error; /** * Open a "local" file. This is a wrapper for the input plugins * "file" and "archive". + * + * Throws std::runtime_error on error. */ InputStreamPtr -OpenLocalInputStream(Path path, Mutex &mutex, Cond &cond, Error &error); +OpenLocalInputStream(Path path, Mutex &mutex, Cond &cond); #endif diff --git a/src/input/Open.cxx b/src/input/Open.cxx index 9d52541bb..53afb5a7b 100644 --- a/src/input/Open.cxx +++ b/src/input/Open.cxx @@ -28,51 +28,51 @@ #include "fs/AllocatedPath.hxx" #include "util/Error.hxx" +#include <stdexcept> + InputStreamPtr InputStream::Open(const char *url, - Mutex &mutex, Cond &cond, - Error &error) + Mutex &mutex, Cond &cond) { if (PathTraitsUTF8::IsAbsolute(url)) { + Error error; const auto path = AllocatedPath::FromUTF8(url, error); if (path.IsNull()) - return nullptr; + throw std::runtime_error(error.GetMessage()); - return OpenLocalInputStream(path, - mutex, cond, error); + return OpenLocalInputStream(path, mutex, cond); } input_plugins_for_each_enabled(plugin) { InputStream *is; - is = plugin->open(url, mutex, cond, error); + is = plugin->open(url, mutex, cond); if (is != nullptr) { is = input_rewind_open(is); return InputStreamPtr(is); - } else if (error.IsDefined()) - return nullptr; + } } - error.Set(input_domain, "Unrecognized URI"); - return nullptr; + throw std::runtime_error("Unrecognized URI"); } InputStreamPtr InputStream::OpenReady(const char *uri, - Mutex &mutex, Cond &cond, - Error &error) + Mutex &mutex, Cond &cond) { - auto is = Open(uri, mutex, cond, error); - if (is == nullptr) - return nullptr; + auto is = Open(uri, mutex, cond); bool success; { const ScopeLock protect(mutex); is->WaitReady(); + + Error error; success = is->Check(error); + if (!success) + throw std::runtime_error(error.GetMessage()); } if (!success) diff --git a/src/input/plugins/AlsaInputPlugin.cxx b/src/input/plugins/AlsaInputPlugin.cxx index 05098966a..70c6979d5 100644 --- a/src/input/plugins/AlsaInputPlugin.cxx +++ b/src/input/plugins/AlsaInputPlugin.cxx @@ -30,6 +30,7 @@ #include "../AsyncInputStream.hxx" #include "util/Domain.hxx" #include "util/Error.hxx" +#include "util/RuntimeError.hxx" #include "util/StringCompare.hxx" #include "util/ReusableArray.hxx" #include "util/ScopeExit.hxx" @@ -102,8 +103,7 @@ public: snd_pcm_close(capture_handle); } - static InputStream *Create(const char *uri, Mutex &mutex, Cond &cond, - Error &error); + static InputStream *Create(const char *uri, Mutex &mutex, Cond &cond); protected: /* virtual methods from AsyncInputStream */ @@ -120,8 +120,7 @@ protected: private: static snd_pcm_t *OpenDevice(const char *device, int rate, - snd_pcm_format_t format, int channels, - Error &error); + snd_pcm_format_t format, int channels); void Pause() { AsyncInputStream::Pause(); @@ -143,8 +142,7 @@ private: }; inline InputStream * -AlsaInputStream::Create(const char *uri, Mutex &mutex, Cond &cond, - Error &error) +AlsaInputStream::Create(const char *uri, Mutex &mutex, Cond &cond) { const char *device = StringAfterPrefix(uri, "alsa://"); if (device == nullptr) @@ -160,10 +158,7 @@ AlsaInputStream::Create(const char *uri, Mutex &mutex, Cond &cond, snd_pcm_format_t format = default_format; int channels = default_channels; - snd_pcm_t *handle = OpenDevice(device, rate, format, channels, - error); - if (handle == nullptr) - return nullptr; + snd_pcm_t *handle = OpenDevice(device, rate, format, channels); int frame_size = snd_pcm_format_width(format) / 8 * channels; return new AlsaInputStream(io_thread_get(), @@ -242,47 +237,40 @@ AlsaInputStream::Recover(int err) return err; } -static bool +static void ConfigureCapture(snd_pcm_t *capture_handle, - int rate, snd_pcm_format_t format, int channels, - Error &error) + int rate, snd_pcm_format_t format, int channels) { int err; snd_pcm_hw_params_t *hw_params; - if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) { - error.Format(alsa_input_domain, "Cannot allocate hardware parameter structure (%s)", snd_strerror(err)); - return false; - } + if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) + throw FormatRuntimeError("Cannot allocate hardware parameter structure (%s)", + snd_strerror(err)); AtScopeExit(hw_params) { snd_pcm_hw_params_free(hw_params); }; - 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)); - return false; - } + if ((err = snd_pcm_hw_params_any(capture_handle, hw_params)) < 0) + throw FormatRuntimeError("Cannot initialize hardware parameter structure (%s)", + snd_strerror(err)); - 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)); - return false; - } + if ((err = snd_pcm_hw_params_set_access(capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) + throw FormatRuntimeError("Cannot set access type (%s)", + snd_strerror(err)); - 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)); - return false; - } + if ((err = snd_pcm_hw_params_set_format(capture_handle, hw_params, format)) < 0) + throw FormatRuntimeError("Cannot set sample format (%s)", + snd_strerror(err)); - 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)); - return false; - } + if ((err = snd_pcm_hw_params_set_channels(capture_handle, hw_params, channels)) < 0) + throw FormatRuntimeError("Cannot set channels (%s)", + snd_strerror(err)); - 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)); - return false; - } + if ((err = snd_pcm_hw_params_set_rate(capture_handle, hw_params, rate, 0)) < 0) + throw FormatRuntimeError("Cannot set sample rate (%s)", + snd_strerror(err)); /* 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 @@ -293,17 +281,13 @@ ConfigureCapture(snd_pcm_t *capture_handle, snd_pcm_uframes_t period = read_buffer_size * 2; int direction = -1; if ((err = snd_pcm_hw_params_set_period_size_near(capture_handle, hw_params, - &period, &direction)) < 0) { - error.Format(alsa_input_domain, "Cannot set period size (%s)", - snd_strerror(err)); - return false; - } + &period, &direction)) < 0) + throw FormatRuntimeError("Cannot set period size (%s)", + snd_strerror(err)); - if ((err = snd_pcm_hw_params(capture_handle, hw_params)) < 0) { - error.Format(alsa_input_domain, "Cannot set parameters (%s)", - snd_strerror(err)); - return false; - } + if ((err = snd_pcm_hw_params(capture_handle, hw_params)) < 0) + throw FormatRuntimeError("Cannot set parameters (%s)", + snd_strerror(err)); 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, - period)) < 0) { - error.Format(alsa_input_domain, - "unable to set start threshold (%s)", snd_strerror(err)); - return false; - } - - if ((err = snd_pcm_sw_params(capture_handle, sw_params)) < 0) { - error.Format(alsa_input_domain, - "unable to install sw params (%s)", snd_strerror(err)); - return false; - } + period)) < 0) + throw FormatRuntimeError("unable to set start threshold (%s)", + snd_strerror(err)); - return true; + if ((err = snd_pcm_sw_params(capture_handle, sw_params)) < 0) + throw FormatRuntimeError("unable to install sw params (%s)", + snd_strerror(err)); } inline snd_pcm_t * AlsaInputStream::OpenDevice(const char *device, - int rate, snd_pcm_format_t format, int channels, - Error &error) + int rate, snd_pcm_format_t format, int channels) { snd_pcm_t *capture_handle; int err; if ((err = snd_pcm_open(&capture_handle, device, - SND_PCM_STREAM_CAPTURE, 0)) < 0) { - error.Format(alsa_input_domain, "Failed to open device: %s (%s)", device, snd_strerror(err)); - return nullptr; - } + SND_PCM_STREAM_CAPTURE, 0)) < 0) + throw FormatRuntimeError("Failed to open device: %s (%s)", + 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); - return nullptr; + throw; } snd_pcm_prepare(capture_handle); @@ -356,9 +334,9 @@ AlsaInputStream::OpenDevice(const char *device, /*######################### Plugin Functions ##############################*/ 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 = { diff --git a/src/input/plugins/ArchiveInputPlugin.cxx b/src/input/plugins/ArchiveInputPlugin.cxx index 590155d0e..3e307bfcc 100644 --- a/src/input/plugins/ArchiveInputPlugin.cxx +++ b/src/input/plugins/ArchiveInputPlugin.cxx @@ -25,14 +25,18 @@ #include "archive/ArchivePlugin.hxx" #include "archive/ArchiveFile.hxx" #include "../InputPlugin.hxx" +#include "../InputStream.hxx" #include "fs/Path.hxx" #include "Log.hxx" #include "util/ScopeExit.hxx" +#include "util/Error.hxx" + +#include <stdexcept> #include <stdlib.h> -InputStream * -OpenArchiveInputStream(Path path, Mutex &mutex, Cond &cond, Error &error) +InputStreamPtr +OpenArchiveInputStream(Path path, Mutex &mutex, Cond &cond) { const ArchivePlugin *arplug; @@ -57,22 +61,21 @@ OpenArchiveInputStream(Path path, Mutex &mutex, Cond &cond, Error &error) return nullptr; } + Error error; auto file = archive_file_open(arplug, Path::FromFS(archive), error); - if (file == nullptr) { - return nullptr; - } + if (file == nullptr) + throw std::runtime_error(error.GetMessage()); AtScopeExit(file) { file->Close(); }; - return file->OpenStream(filename, mutex, cond, error); + return InputStreamPtr(file->OpenStream(filename, mutex, cond)); } static InputStream * input_archive_open(gcc_unused const char *filename, - gcc_unused Mutex &mutex, gcc_unused Cond &cond, - gcc_unused Error &error) + gcc_unused Mutex &mutex, gcc_unused Cond &cond) { /* dummy method; use OpenArchiveInputStream() instead */ diff --git a/src/input/plugins/ArchiveInputPlugin.hxx b/src/input/plugins/ArchiveInputPlugin.hxx index 68d369206..b248dd277 100644 --- a/src/input/plugins/ArchiveInputPlugin.hxx +++ b/src/input/plugins/ArchiveInputPlugin.hxx @@ -20,15 +20,15 @@ #ifndef MPD_INPUT_ARCHIVE_HXX #define MPD_INPUT_ARCHIVE_HXX -class InputStream; +#include "input/Ptr.hxx" + class Path; class Mutex; class Cond; -class Error; extern const struct InputPlugin input_plugin_archive; -InputStream * -OpenArchiveInputStream(Path path, Mutex &mutex, Cond &cond, Error &error); +InputStreamPtr +OpenArchiveInputStream(Path path, Mutex &mutex, Cond &cond); #endif diff --git a/src/input/plugins/CdioParanoiaInputPlugin.cxx b/src/input/plugins/CdioParanoiaInputPlugin.cxx index c9a3067f0..f06d01a10 100644 --- a/src/input/plugins/CdioParanoiaInputPlugin.cxx +++ b/src/input/plugins/CdioParanoiaInputPlugin.cxx @@ -127,7 +127,7 @@ struct cdio_uri { }; 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://")) return false; @@ -160,10 +160,8 @@ parse_cdio_uri(struct cdio_uri *dest, const char *src, Error &error) char *endptr; dest->track = strtoul(track, &endptr, 10); - if (*endptr != 0) { - error.Set(cdio_domain, "Malformed track number"); - return false; - } + if (*endptr != 0) + throw std::runtime_error("Malformed track number"); if (endptr == track) /* play the whole CD */ @@ -187,35 +185,28 @@ cdio_detect_device(void) static InputStream * input_cdio_open(const char *uri, - Mutex &mutex, Cond &cond, - Error &error) + Mutex &mutex, Cond &cond) { struct cdio_uri parsed_uri; - if (!parse_cdio_uri(&parsed_uri, uri, error)) + if (!parse_cdio_uri(&parsed_uri, uri)) return nullptr; /* get list of CD's supporting CD-DA */ const AllocatedPath device = parsed_uri.device[0] != 0 ? AllocatedPath::FromFS(parsed_uri.device) : cdio_detect_device(); - if (device.IsNull()) { - error.Set(cdio_domain, - "Unable find or access a CD-ROM drive with an audio CD in it."); - return nullptr; - } + if (device.IsNull()) + throw std::runtime_error("Unable find or access a CD-ROM drive with an audio CD in it."); /* 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); - if (cdio == nullptr) { - error.Set(cdio_domain, "Failed to open CD drive"); - return nullptr; - } + if (cdio == nullptr) + throw std::runtime_error("Failed to open CD drive"); const auto drv = cdio_cddap_identify_cdio(cdio, 1, nullptr); if (drv == nullptr) { - error.Set(cdio_domain, "Unable to identify audio CD disc."); 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); @@ -223,12 +214,12 @@ input_cdio_open(const char *uri, if (0 != cdio_cddap_open(drv)) { cdio_cddap_close_no_free_cdio(drv); cdio_destroy(cdio); - error.Set(cdio_domain, "Unable to open disc."); - return nullptr; + throw std::runtime_error("Unable to open disc."); } bool reverse_endian; - switch (data_bigendianp(drv)) { + const int be = data_bigendianp(drv); + switch (be) { case -1: LogDebug(cdio_domain, "drive returns unknown audio data"); reverse_endian = default_reverse_endian; @@ -245,11 +236,10 @@ input_cdio_open(const char *uri, break; default: - error.Format(cdio_domain, "Drive returns unknown data type %d", - data_bigendianp(drv)); cdio_cddap_close_no_free_cdio(drv); cdio_destroy(cdio); - return nullptr; + throw FormatRuntimeError("Drive returns unknown data type %d", + be); } lsn_t lsn_from, lsn_to; diff --git a/src/input/plugins/CurlInputPlugin.cxx b/src/input/plugins/CurlInputPlugin.cxx index 38375d2f6..2d1df3a26 100644 --- a/src/input/plugins/CurlInputPlugin.cxx +++ b/src/input/plugins/CurlInputPlugin.cxx @@ -32,6 +32,7 @@ #include "util/ASCII.hxx" #include "util/StringUtil.hxx" #include "util/NumberParser.hxx" +#include "util/RuntimeError.hxx" #include "util/Error.hxx" #include "util/Domain.hxx" #include "Log.hxx" @@ -78,17 +79,18 @@ struct CurlInputStream final : public AsyncInputStream { CURL_MAX_BUFFERED, CURL_RESUME_AT), request_headers(nullptr), - icy(new IcyInputStream(this)) {} + icy(new IcyInputStream(this)) { + InitEasy(); + } ~CurlInputStream(); CurlInputStream(const CurlInputStream &) = delete; CurlInputStream &operator=(const CurlInputStream &) = delete; - static InputStream *Open(const char *url, Mutex &mutex, Cond &cond, - Error &error); + static InputStream *Open(const char *url, Mutex &mutex, Cond &cond); - bool InitEasy(Error &error); + void InitEasy(); /** * Frees the current "libcurl easy" handle, and everything @@ -201,7 +203,7 @@ public: curl_multi_cleanup(multi); } - bool Add(CurlInputStream *c, Error &error); + void Add(CurlInputStream *c); void Remove(CurlInputStream *c); /** @@ -355,41 +357,39 @@ CurlSocket::OnSocketReady(unsigned flags) /** * Runs in the I/O thread. No lock needed. + * + * Throws std::runtime_error on error. */ -inline bool -CurlMulti::Add(CurlInputStream *c, Error &error) +inline void +CurlMulti::Add(CurlInputStream *c) { assert(io_thread_inside()); assert(c != nullptr); assert(c->easy != nullptr); CURLMcode mcode = curl_multi_add_handle(multi, c->easy); - if (mcode != CURLM_OK) { - error.Format(curlm_domain, mcode, - "curl_multi_add_handle() failed: %s", - curl_multi_strerror(mcode)); - return false; - } + if (mcode != CURLM_OK) + throw FormatRuntimeError("curl_multi_add_handle() failed: %s", + curl_multi_strerror(mcode)); InvalidateSockets(); - return true; } /** * Call input_curl_easy_add() in the I/O thread. May be called from * any thread. Caller must not hold a mutex. + * + * Throws std::runtime_error on error. */ -static bool -input_curl_easy_add_indirect(CurlInputStream *c, Error &error) +static void +input_curl_easy_add_indirect(CurlInputStream *c) { assert(c != nullptr); assert(c->easy != nullptr); - bool result; - BlockingCall(io_thread_get(), [c, &error, &result](){ - result = curl_multi->Add(c, error); + BlockingCall(io_thread_get(), [c](){ + curl_multi->Add(c); }); - return result; } inline void @@ -727,14 +727,12 @@ input_curl_writefunction(void *ptr, size_t size, size_t nmemb, void *stream) return c.DataReceived(ptr, size); } -bool -CurlInputStream::InitEasy(Error &error) +void +CurlInputStream::InitEasy() { easy = curl_easy_init(); - if (easy == nullptr) { - error.Set(curl_domain, "curl_easy_init() failed"); - return false; - } + if (easy == nullptr) + throw std::runtime_error("curl_easy_init() failed"); curl_easy_setopt(easy, CURLOPT_PRIVATE, (void *)this); 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); CURLcode code = curl_easy_setopt(easy, CURLOPT_URL, GetURI()); - if (code != CURLE_OK) { - error.Format(curl_domain, code, - "curl_easy_setopt() failed: %s", - curl_easy_strerror(code)); - return false; - } + if (code != CURLE_OK) + throw FormatRuntimeError("curl_easy_setopt() failed: %s", + curl_easy_strerror(code)); request_headers = nullptr; request_headers = curl_slist_append(request_headers, "Icy-Metadata: 1"); curl_easy_setopt(easy, CURLOPT_HTTPHEADER, request_headers); - - return true; } void @@ -809,11 +802,11 @@ CurlInputStream::DoSeek(offset_type new_offset) return; } - Error error; - if (!InitEasy(postponed_error)) { + try { + InitEasy(); + } catch (...) { mutex.lock(); - PostponeError(std::move(error)); - return; + throw; } /* send the "Range" header */ @@ -823,10 +816,11 @@ CurlInputStream::DoSeek(offset_type new_offset) 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(); - PostponeError(std::move(error)); - return; + throw; } mutex.lock(); @@ -834,27 +828,29 @@ CurlInputStream::DoSeek(offset_type new_offset) } inline InputStream * -CurlInputStream::Open(const char *url, Mutex &mutex, Cond &cond, - Error &error) +CurlInputStream::Open(const char *url, Mutex &mutex, Cond &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; - return nullptr; + throw; } return c->icy; } static InputStream * -input_curl_open(const char *url, Mutex &mutex, Cond &cond, - Error &error) +input_curl_open(const char *url, Mutex &mutex, Cond &cond) { if (memcmp(url, "http://", 7) != 0 && memcmp(url, "https://", 8) != 0) return nullptr; - return CurlInputStream::Open(url, mutex, cond, error); + return CurlInputStream::Open(url, mutex, cond); } const struct InputPlugin input_plugin_curl = { diff --git a/src/input/plugins/FfmpegInputPlugin.cxx b/src/input/plugins/FfmpegInputPlugin.cxx index 1eb91f421..ab189c490 100644 --- a/src/input/plugins/FfmpegInputPlugin.cxx +++ b/src/input/plugins/FfmpegInputPlugin.cxx @@ -84,8 +84,7 @@ input_ffmpeg_init(gcc_unused const ConfigBlock &block) static InputStream * input_ffmpeg_open(const char *uri, - Mutex &mutex, Cond &cond, - Error &error) + Mutex &mutex, Cond &cond) { if (!StringStartsWith(uri, "gopher://") && !StringStartsWith(uri, "rtp://") && @@ -97,10 +96,8 @@ input_ffmpeg_open(const char *uri, AVIOContext *h; auto result = avio_open(&h, uri, AVIO_FLAG_READ); - if (result != 0) { - SetFfmpegError(error, result); - return nullptr; - } + if (result != 0) + throw MakeFfmpegError(result); return new FfmpegInputStream(uri, mutex, cond, h); } diff --git a/src/input/plugins/FileInputPlugin.cxx b/src/input/plugins/FileInputPlugin.cxx index 1d5eaf90e..6fb816423 100644 --- a/src/input/plugins/FileInputPlugin.cxx +++ b/src/input/plugins/FileInputPlugin.cxx @@ -21,18 +21,15 @@ #include "FileInputPlugin.hxx" #include "../InputStream.hxx" #include "../InputPlugin.hxx" -#include "util/Error.hxx" -#include "util/Domain.hxx" #include "fs/Path.hxx" #include "fs/FileInfo.hxx" #include "fs/io/FileReader.hxx" #include "system/FileDescriptor.hxx" +#include "util/RuntimeError.hxx" #include <sys/stat.h> #include <fcntl.h> -static constexpr Domain file_domain("file"); - class FileInputStream final : public InputStream { FileReader reader; @@ -56,38 +53,31 @@ public: bool Seek(offset_type offset, Error &error) override; }; -InputStream * +InputStreamPtr OpenFileInputStream(Path path, - Mutex &mutex, Cond &cond, - Error &error) -try { + Mutex &mutex, Cond &cond) +{ FileReader reader(path); const FileInfo info = reader.GetFileInfo(); - if (!info.IsRegular()) { - error.Format(file_domain, "Not a regular file: %s", - path.c_str()); - return nullptr; - } + if (!info.IsRegular()) + throw FormatRuntimeError("Not a regular file: %s", + path.c_str()); #ifdef POSIX_FADV_SEQUENTIAL posix_fadvise(reader.GetFD().Get(), (off_t)0, info.GetSize(), POSIX_FADV_SEQUENTIAL); #endif - return new FileInputStream(path.ToUTF8().c_str(), - std::move(reader), info.GetSize(), - mutex, cond); -} catch (const std::exception &e) { - error.Set(std::current_exception()); - return nullptr; + return InputStreamPtr(new FileInputStream(path.ToUTF8().c_str(), + std::move(reader), info.GetSize(), + mutex, cond)); } static InputStream * input_file_open(gcc_unused const char *filename, - gcc_unused Mutex &mutex, gcc_unused Cond &cond, - gcc_unused Error &error) + gcc_unused Mutex &mutex, gcc_unused Cond &cond) { /* dummy method; use OpenFileInputStream() instead */ diff --git a/src/input/plugins/FileInputPlugin.hxx b/src/input/plugins/FileInputPlugin.hxx index b508c9900..c967d84d6 100644 --- a/src/input/plugins/FileInputPlugin.hxx +++ b/src/input/plugins/FileInputPlugin.hxx @@ -20,17 +20,16 @@ #ifndef MPD_INPUT_FILE_HXX #define MPD_INPUT_FILE_HXX -class InputStream; +#include "input/Ptr.hxx" + class Path; class Mutex; class Cond; -class Error; extern const struct InputPlugin input_plugin_file; -InputStream * +InputStreamPtr OpenFileInputStream(Path path, - Mutex &mutex, Cond &cond, - Error &error); + Mutex &mutex, Cond &cond); #endif diff --git a/src/input/plugins/MmsInputPlugin.cxx b/src/input/plugins/MmsInputPlugin.cxx index 25af267e1..9649cc85f 100644 --- a/src/input/plugins/MmsInputPlugin.cxx +++ b/src/input/plugins/MmsInputPlugin.cxx @@ -72,8 +72,7 @@ MmsInputStream::Open(Error &error) static InputStream * input_mms_open(const char *url, - Mutex &mutex, Cond &cond, - gcc_unused Error &error) + Mutex &mutex, Cond &cond) { if (!StringStartsWith(url, "mms://") && !StringStartsWith(url, "mmsh://") && diff --git a/src/input/plugins/NfsInputPlugin.cxx b/src/input/plugins/NfsInputPlugin.cxx index b2a9c8c30..ddacf317f 100644 --- a/src/input/plugins/NfsInputPlugin.cxx +++ b/src/input/plugins/NfsInputPlugin.cxx @@ -57,10 +57,10 @@ public: DeferClose(); } - bool Open(Error &error) { + void Open() { assert(!IsReady()); - return NfsFileReader::Open(GetURI(), error); + NfsFileReader::Open(GetURI()); } private: @@ -119,17 +119,10 @@ NfsInputStream::DoResume() reconnect_on_resume = false; reconnecting = true; - mutex.unlock(); - NfsFileReader::Close(); - - Error error; - bool success = NfsFileReader::Open(GetURI(), error); - mutex.lock(); + ScopeUnlock unlock(mutex); - if (!success) { - postponed_error = std::move(error); - cond.broadcast(); - } + NfsFileReader::Close(); + NfsFileReader::Open(GetURI()); return; } @@ -229,16 +222,17 @@ input_nfs_finish() static InputStream * input_nfs_open(const char *uri, - Mutex &mutex, Cond &cond, - Error &error) + Mutex &mutex, Cond &cond) { if (!StringStartsWith(uri, "nfs://")) return nullptr; NfsInputStream *is = new NfsInputStream(uri, mutex, cond); - if (!is->Open(error)) { + try { + is->Open(); + } catch (...) { delete is; - return nullptr; + throw; } return is; diff --git a/src/input/plugins/SmbclientInputPlugin.cxx b/src/input/plugins/SmbclientInputPlugin.cxx index d74afa828..7eea671f0 100644 --- a/src/input/plugins/SmbclientInputPlugin.cxx +++ b/src/input/plugins/SmbclientInputPlugin.cxx @@ -24,6 +24,7 @@ #include "../InputStream.hxx" #include "../InputPlugin.hxx" #include "PluginUnavailable.hxx" +#include "system/Error.hxx" #include "util/StringCompare.hxx" #include "util/Error.hxx" @@ -85,8 +86,7 @@ input_smbclient_init(gcc_unused const ConfigBlock &block) static InputStream * input_smbclient_open(const char *uri, - Mutex &mutex, Cond &cond, - Error &error) + Mutex &mutex, Cond &cond) { if (!StringStartsWith(uri, "smb://")) return nullptr; @@ -94,33 +94,30 @@ input_smbclient_open(const char *uri, const ScopeLock protect(smbclient_mutex); SMBCCTX *ctx = smbc_new_context(); - if (ctx == nullptr) { - error.SetErrno("smbc_new_context() failed"); - return nullptr; - } + if (ctx == nullptr) + throw MakeErrno("smbc_new_context() failed"); SMBCCTX *ctx2 = smbc_init_context(ctx); if (ctx2 == nullptr) { - error.SetErrno("smbc_init_context() failed"); + int e = errno; smbc_free_context(ctx, 1); - return nullptr; + throw MakeErrno(e, "smbc_init_context() failed"); } ctx = ctx2; int fd = smbc_open(uri, O_RDONLY, 0); if (fd < 0) { - error.SetErrno("smbc_open() failed"); + int e = errno; smbc_free_context(ctx, 1); - return nullptr; + throw MakeErrno(e, "smbc_open() failed"); } struct stat st; if (smbc_fstat(fd, &st) < 0) { - error.SetErrno("smbc_fstat() failed"); - smbc_close(fd); + int e = errno; smbc_free_context(ctx, 1); - return nullptr; + throw MakeErrno(e, "smbc_fstat() failed"); } return new SmbclientInputStream(uri, mutex, cond, ctx, fd, st); diff --git a/src/lib/ffmpeg/Error.cxx b/src/lib/ffmpeg/Error.cxx index 9dc193bfa..92608300f 100644 --- a/src/lib/ffmpeg/Error.cxx +++ b/src/lib/ffmpeg/Error.cxx @@ -26,6 +26,14 @@ extern "C" { #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 SetFfmpegError(Error &error, int errnum) { diff --git a/src/lib/ffmpeg/Error.hxx b/src/lib/ffmpeg/Error.hxx index 7dc7fc550..3a6eb876d 100644 --- a/src/lib/ffmpeg/Error.hxx +++ b/src/lib/ffmpeg/Error.hxx @@ -20,8 +20,13 @@ #ifndef MPD_FFMPEG_ERROR_HXX #define MPD_FFMPEG_ERROR_HXX +#include <stdexcept> + class Error; +std::runtime_error +MakeFfmpegError(int errnum); + void SetFfmpegError(Error &error, int errnum); diff --git a/src/lib/nfs/FileReader.cxx b/src/lib/nfs/FileReader.cxx index 523690de7..54b59e09a 100644 --- a/src/lib/nfs/FileReader.cxx +++ b/src/lib/nfs/FileReader.cxx @@ -91,23 +91,19 @@ NfsFileReader::DeferClose() BlockingCall(io_thread_get(), [this](){ Close(); }); } -bool -NfsFileReader::Open(const char *uri, Error &error) +void +NfsFileReader::Open(const char *uri) { assert(state == State::INITIAL); - if (!StringStartsWith(uri, "nfs://")) { - error.Set(nfs_domain, "Malformed nfs:// URI"); - return false; - } + if (!StringStartsWith(uri, "nfs://")) + throw std::runtime_error("Malformed nfs:// URI"); uri += 6; const char *slash = strchr(uri, '/'); - if (slash == nullptr) { - error.Set(nfs_domain, "Malformed nfs:// URI"); - return false; - } + if (slash == nullptr) + throw std::runtime_error("Malformed nfs:// URI"); server = std::string(uri, slash); @@ -121,10 +117,8 @@ NfsFileReader::Open(const char *uri, Error &error) path = new_path; } else { slash = strrchr(uri + 1, '/'); - if (slash == nullptr || slash[1] == 0) { - error.Set(nfs_domain, "Malformed nfs:// URI"); - return false; - } + if (slash == nullptr || slash[1] == 0) + throw std::runtime_error("Malformed nfs:// URI"); export_name = std::string(uri, slash); path = slash; @@ -132,7 +126,6 @@ NfsFileReader::Open(const char *uri, Error &error) state = State::DEFER; DeferredMonitor::Schedule(); - return true; } bool diff --git a/src/lib/nfs/FileReader.hxx b/src/lib/nfs/FileReader.hxx index ab88299cc..177fb66f2 100644 --- a/src/lib/nfs/FileReader.hxx +++ b/src/lib/nfs/FileReader.hxx @@ -61,7 +61,11 @@ public: void Close(); 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); void CancelRead(); diff --git a/src/playlist/PlaylistStream.cxx b/src/playlist/PlaylistStream.cxx index 37d7663de..fc3a5586b 100644 --- a/src/playlist/PlaylistStream.cxx +++ b/src/playlist/PlaylistStream.cxx @@ -44,13 +44,7 @@ try { if (!playlist_suffix_supported(suffix_utf8.c_str())) return nullptr; - Error error; - auto is = OpenLocalInputStream(path, mutex, cond, error); - if (is == nullptr) { - LogError(error); - return nullptr; - } - + auto is = OpenLocalInputStream(path, mutex, cond); return playlist_list_open_stream_suffix(std::move(is), suffix_utf8.c_str()); } catch (const std::runtime_error &e) { @@ -85,15 +79,7 @@ try { if (playlist != nullptr) return playlist; - Error error; - auto is = InputStream::OpenReady(uri, mutex, cond, error); - if (is == nullptr) { - if (error.IsDefined()) - FormatError(error, "Failed to open %s", uri); - - return nullptr; - } - + auto is = InputStream::OpenReady(uri, mutex, cond); return playlist_list_open_stream(std::move(is), uri); } catch (const std::runtime_error &e) { LogError(e); diff --git a/src/playlist/plugins/SoundCloudPlaylistPlugin.cxx b/src/playlist/plugins/SoundCloudPlaylistPlugin.cxx index e18d1abab..67a64ce2e 100644 --- a/src/playlist/plugins/SoundCloudPlaylistPlugin.cxx +++ b/src/playlist/plugins/SoundCloudPlaylistPlugin.cxx @@ -230,15 +230,9 @@ static constexpr yajl_callbacks parse_callbacks = { static int soundcloud_parse_json(const char *url, yajl_handle hand, Mutex &mutex, Cond &cond) -{ +try { Error error; - auto input_stream = InputStream::OpenReady(url, mutex, cond, - error); - if (input_stream == nullptr) { - if (error.IsDefined()) - LogError(error); - return -1; - } + auto input_stream = InputStream::OpenReady(url, mutex, cond); const ScopeLock protect(mutex); @@ -275,6 +269,9 @@ soundcloud_parse_json(const char *url, yajl_handle hand, } return 0; +} catch (const std::exception &e) { + LogError(e); + return -1; } /** diff --git a/src/system/Error.hxx b/src/system/Error.hxx index 4c9ad8613..7adf7921e 100644 --- a/src/system/Error.hxx +++ b/src/system/Error.hxx @@ -142,6 +142,19 @@ IsFileNotFound(const std::system_error &e) 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 +static inline bool IsAccessDenied(const std::system_error &e) { #ifdef WIN32 diff --git a/src/tag/Generic.cxx b/src/tag/Generic.cxx index 4c2eee63c..ad2f1e6e1 100644 --- a/src/tag/Generic.cxx +++ b/src/tag/Generic.cxx @@ -53,13 +53,7 @@ try { Mutex mutex; Cond cond; - Error error; - auto is = OpenLocalInputStream(path, mutex, cond, error); - if (!is) { - LogError(error); - return false; - } - + auto is = OpenLocalInputStream(path, mutex, cond); return ScanGenericTags(*is, handler, ctx); } catch (const std::runtime_error &e) { LogError(e); |