diff options
Diffstat (limited to 'src/input')
-rw-r--r-- | src/input/Init.cxx | 102 | ||||
-rw-r--r-- | src/input/Init.hxx | 36 | ||||
-rw-r--r-- | src/input/InputPlugin.hxx | 91 | ||||
-rw-r--r-- | src/input/InputStream.cxx | 214 | ||||
-rw-r--r-- | src/input/InputStream.hxx | 301 | ||||
-rw-r--r-- | src/input/Registry.cxx | 86 | ||||
-rw-r--r-- | src/input/Registry.hxx | 43 | ||||
-rw-r--r-- | src/input/TextInputStream.cxx | 78 | ||||
-rw-r--r-- | src/input/TextInputStream.hxx | 56 | ||||
-rw-r--r-- | src/input/plugins/AlsaInputPlugin.cxx (renamed from src/input/AlsaInputPlugin.cxx) | 4 | ||||
-rw-r--r-- | src/input/plugins/AlsaInputPlugin.hxx (renamed from src/input/AlsaInputPlugin.hxx) | 2 | ||||
-rw-r--r-- | src/input/plugins/ArchiveInputPlugin.cxx (renamed from src/input/ArchiveInputPlugin.cxx) | 2 | ||||
-rw-r--r-- | src/input/plugins/ArchiveInputPlugin.hxx (renamed from src/input/ArchiveInputPlugin.hxx) | 0 | ||||
-rw-r--r-- | src/input/plugins/CdioParanoiaInputPlugin.cxx (renamed from src/input/CdioParanoiaInputPlugin.cxx) | 4 | ||||
-rw-r--r-- | src/input/plugins/CdioParanoiaInputPlugin.hxx (renamed from src/input/CdioParanoiaInputPlugin.hxx) | 0 | ||||
-rw-r--r-- | src/input/plugins/CurlInputPlugin.cxx (renamed from src/input/CurlInputPlugin.cxx) | 4 | ||||
-rw-r--r-- | src/input/plugins/CurlInputPlugin.hxx (renamed from src/input/CurlInputPlugin.hxx) | 0 | ||||
-rw-r--r-- | src/input/plugins/DespotifyInputPlugin.cxx (renamed from src/input/DespotifyInputPlugin.cxx) | 4 | ||||
-rw-r--r-- | src/input/plugins/DespotifyInputPlugin.hxx (renamed from src/input/DespotifyInputPlugin.hxx) | 0 | ||||
-rw-r--r-- | src/input/plugins/FfmpegInputPlugin.cxx (renamed from src/input/FfmpegInputPlugin.cxx) | 4 | ||||
-rw-r--r-- | src/input/plugins/FfmpegInputPlugin.hxx (renamed from src/input/FfmpegInputPlugin.hxx) | 0 | ||||
-rw-r--r-- | src/input/plugins/FileInputPlugin.cxx (renamed from src/input/FileInputPlugin.cxx) | 4 | ||||
-rw-r--r-- | src/input/plugins/FileInputPlugin.hxx (renamed from src/input/FileInputPlugin.hxx) | 0 | ||||
-rw-r--r-- | src/input/plugins/MmsInputPlugin.cxx (renamed from src/input/MmsInputPlugin.cxx) | 4 | ||||
-rw-r--r-- | src/input/plugins/MmsInputPlugin.hxx (renamed from src/input/MmsInputPlugin.hxx) | 0 | ||||
-rw-r--r-- | src/input/plugins/RewindInputPlugin.cxx (renamed from src/input/RewindInputPlugin.cxx) | 4 | ||||
-rw-r--r-- | src/input/plugins/RewindInputPlugin.hxx (renamed from src/input/RewindInputPlugin.hxx) | 0 | ||||
-rw-r--r-- | src/input/plugins/SmbclientInputPlugin.cxx (renamed from src/input/SmbclientInputPlugin.cxx) | 4 | ||||
-rw-r--r-- | src/input/plugins/SmbclientInputPlugin.hxx (renamed from src/input/SmbclientInputPlugin.hxx) | 0 |
29 files changed, 1027 insertions, 20 deletions
diff --git a/src/input/Init.cxx b/src/input/Init.cxx new file mode 100644 index 000000000..14a7feef3 --- /dev/null +++ b/src/input/Init.cxx @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2003-2014 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "Init.hxx" +#include "Registry.hxx" +#include "InputPlugin.hxx" +#include "util/Error.hxx" +#include "util/Domain.hxx" +#include "config/ConfigGlobal.hxx" +#include "config/ConfigOption.hxx" +#include "config/ConfigData.hxx" + +#include <assert.h> +#include <string.h> + +extern constexpr Domain input_domain("input"); + +/** + * Find the "input" configuration block for the specified plugin. + * + * @param plugin_name the name of the input plugin + * @return the configuration block, or nullptr if none was configured + */ +static const struct config_param * +input_plugin_config(const char *plugin_name, Error &error) +{ + const struct config_param *param = nullptr; + + while ((param = config_get_next_param(CONF_INPUT, param)) != nullptr) { + const char *name = param->GetBlockValue("plugin"); + if (name == nullptr) { + error.Format(input_domain, + "input configuration without 'plugin' name in line %d", + param->line); + return nullptr; + } + + if (strcmp(name, plugin_name) == 0) + return param; + } + + return nullptr; +} + +bool +input_stream_global_init(Error &error) +{ + const config_param empty; + + for (unsigned i = 0; input_plugins[i] != nullptr; ++i) { + const InputPlugin *plugin = input_plugins[i]; + + assert(plugin->name != nullptr); + assert(*plugin->name != 0); + assert(plugin->open != nullptr); + + const struct config_param *param = + input_plugin_config(plugin->name, error); + if (param == nullptr) { + if (error.IsDefined()) + return false; + + param = ∅ + } else if (!param->GetBlockValue("enabled", true)) + /* the plugin is disabled in mpd.conf */ + continue; + + if (plugin->init == nullptr || plugin->init(*param, error)) + input_plugins_enabled[i] = true; + else { + error.FormatPrefix("Failed to initialize input plugin '%s': ", + plugin->name); + return false; + } + } + + return true; +} + +void input_stream_global_finish(void) +{ + input_plugins_for_each_enabled(plugin) + if (plugin->finish != nullptr) + plugin->finish(); +} diff --git a/src/input/Init.hxx b/src/input/Init.hxx new file mode 100644 index 000000000..875fdce7c --- /dev/null +++ b/src/input/Init.hxx @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2003-2014 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_INPUT_INIT_HXX +#define MPD_INPUT_INIT_HXX + +class Error; + +/** + * Initializes this library and all input_stream implementations. + */ +bool +input_stream_global_init(Error &error); + +/** + * Deinitializes this library and all input_stream implementations. + */ +void input_stream_global_finish(void); + +#endif diff --git a/src/input/InputPlugin.hxx b/src/input/InputPlugin.hxx new file mode 100644 index 000000000..83e0ab26e --- /dev/null +++ b/src/input/InputPlugin.hxx @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2003-2014 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_INPUT_PLUGIN_HXX +#define MPD_INPUT_PLUGIN_HXX + +#include "thread/Mutex.hxx" +#include "thread/Cond.hxx" + +#include <stddef.h> +#include <stdint.h> + +struct config_param; +struct InputStream; +class Error; +struct Tag; + +struct InputPlugin { + typedef int64_t offset_type; + + const char *name; + + /** + * Global initialization. This method is called when MPD starts. + * + * @return true on success, false if the plugin should be + * disabled + */ + bool (*init)(const config_param ¶m, Error &error); + + /** + * Global deinitialization. Called once before MPD shuts + * down (only if init() has returned true). + */ + void (*finish)(void); + + InputStream *(*open)(const char *uri, + Mutex &mutex, Cond &cond, + Error &error); + void (*close)(InputStream *is); + + /** + * Check for errors that may have occurred in the I/O thread. + * May be unimplemented for synchronous plugins. + * + * @return false on error + */ + bool (*check)(InputStream *is, Error &error); + + /** + * Update the public attributes. Call before access. Can be + * nullptr if the plugin always keeps its attributes up to date. + */ + void (*update)(InputStream *is); + + Tag *(*tag)(InputStream *is); + + /** + * Returns true if the next read operation will not block: + * either data is available, or end-of-stream has been + * reached, or an error has occurred. + * + * If this method is unimplemented, then it is assumed that + * reading will never block. + */ + bool (*available)(InputStream *is); + + size_t (*read)(InputStream *is, void *ptr, size_t size, + Error &error); + bool (*eof)(InputStream *is); + bool (*seek)(InputStream *is, offset_type offset, int whence, + Error &error); +}; + +#endif diff --git a/src/input/InputStream.cxx b/src/input/InputStream.cxx new file mode 100644 index 000000000..0621437c4 --- /dev/null +++ b/src/input/InputStream.cxx @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2003-2014 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "InputStream.hxx" +#include "Registry.hxx" +#include "InputPlugin.hxx" +#include "plugins/RewindInputPlugin.hxx" +#include "util/UriUtil.hxx" +#include "util/Error.hxx" +#include "util/Domain.hxx" + +#include <assert.h> +#include <stdio.h> /* for SEEK_SET */ + +static constexpr Domain input_domain("input"); + +InputStream * +InputStream::Open(const char *url, + Mutex &mutex, Cond &cond, + Error &error) +{ + input_plugins_for_each_enabled(plugin) { + InputStream *is; + + is = plugin->open(url, mutex, cond, error); + if (is != nullptr) { + assert(is->plugin.close != nullptr); + assert(is->plugin.read != nullptr); + assert(is->plugin.eof != nullptr); + assert(!is->seekable || is->plugin.seek != nullptr); + + is = input_rewind_open(is); + + return is; + } else if (error.IsDefined()) + return nullptr; + } + + error.Set(input_domain, "Unrecognized URI"); + return nullptr; +} + +InputStream * +InputStream::OpenReady(const char *uri, + Mutex &mutex, Cond &cond, + Error &error) +{ + InputStream *is = Open(uri, mutex, cond, error); + if (is == nullptr) + return nullptr; + + mutex.lock(); + is->WaitReady(); + bool success = is->Check(error); + mutex.unlock(); + + if (!success) { + is->Close(); + is = nullptr; + } + + return is; +} + +bool +InputStream::Check(Error &error) +{ + return plugin.check == nullptr || plugin.check(this, error); +} + +void +InputStream::Update() +{ + if (plugin.update != nullptr) + plugin.update(this); +} + +void +InputStream::WaitReady() +{ + while (true) { + Update(); + if (ready) + break; + + cond.wait(mutex); + } +} + +void +InputStream::LockWaitReady() +{ + const ScopeLock protect(mutex); + WaitReady(); +} + +bool +InputStream::CheapSeeking() const +{ + return IsSeekable() && !uri_has_scheme(uri.c_str()); +} + +bool +InputStream::Seek(offset_type _offset, int whence, Error &error) +{ + if (plugin.seek == nullptr) + return false; + + return plugin.seek(this, _offset, whence, error); +} + +bool +InputStream::LockSeek(offset_type _offset, int whence, Error &error) +{ + if (plugin.seek == nullptr) + return false; + + const ScopeLock protect(mutex); + return Seek(_offset, whence, error); +} + +bool +InputStream::Rewind(Error &error) +{ + return Seek(0, SEEK_SET, error); +} + +bool +InputStream::LockRewind(Error &error) +{ + return LockSeek(0, SEEK_SET, error); +} + +Tag * +InputStream::ReadTag() +{ + return plugin.tag != nullptr + ? plugin.tag(this) + : nullptr; +} + +Tag * +InputStream::LockReadTag() +{ + if (plugin.tag == nullptr) + return nullptr; + + const ScopeLock protect(mutex); + return ReadTag(); +} + +bool +InputStream::IsAvailable() +{ + return plugin.available != nullptr + ? plugin.available(this) + : true; +} + +size_t +InputStream::Read(void *ptr, size_t _size, Error &error) +{ + assert(ptr != nullptr); + assert(_size > 0); + + return plugin.read(this, ptr, _size, error); +} + +size_t +InputStream::LockRead(void *ptr, size_t _size, Error &error) +{ + assert(ptr != nullptr); + assert(_size > 0); + + const ScopeLock protect(mutex); + return Read(ptr, _size, error); +} + +void +InputStream::Close() +{ + plugin.close(this); +} + +bool +InputStream::IsEOF() +{ + return plugin.eof(this); +} + +bool +InputStream::LockIsEOF() +{ + const ScopeLock protect(mutex); + return IsEOF(); +} + diff --git a/src/input/InputStream.hxx b/src/input/InputStream.hxx new file mode 100644 index 000000000..c66091687 --- /dev/null +++ b/src/input/InputStream.hxx @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2003-2014 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_INPUT_STREAM_HXX +#define MPD_INPUT_STREAM_HXX + +#include "check.h" +#include "thread/Mutex.hxx" +#include "Compiler.h" + +#include <string> + +#include <assert.h> +#include <stdint.h> + +class Cond; +class Error; +struct Tag; +struct InputPlugin; + +struct InputStream { + typedef int64_t offset_type; + + /** + * the plugin which implements this input stream + */ + const InputPlugin &plugin; + + /** + * The absolute URI which was used to open this stream. + */ + std::string uri; + + /** + * A mutex that protects the mutable attributes of this object + * and its implementation. It must be locked before calling + * any of the public methods. + * + * This object is allocated by the client, and the client is + * responsible for freeing it. + */ + Mutex &mutex; + + /** + * A cond that gets signalled when the state of this object + * changes from the I/O thread. The client of this object may + * wait on it. Optional, may be nullptr. + * + * This object is allocated by the client, and the client is + * responsible for freeing it. + */ + Cond &cond; + + /** + * indicates whether the stream is ready for reading and + * whether the other attributes in this struct are valid + */ + bool ready; + + /** + * if true, then the stream is fully seekable + */ + bool seekable; + + /** + * the size of the resource, or -1 if unknown + */ + offset_type size; + + /** + * the current offset within the stream + */ + offset_type offset; + + /** + * the MIME content type of the resource, or empty if unknown. + */ + std::string mime; + + InputStream(const InputPlugin &_plugin, + const char *_uri, Mutex &_mutex, Cond &_cond) + :plugin(_plugin), uri(_uri), + mutex(_mutex), cond(_cond), + ready(false), seekable(false), + size(-1), offset(0) { + assert(_uri != nullptr); + } + + /** + * Opens a new input stream. You may not access it until the "ready" + * flag is set. + * + * @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 + */ + gcc_nonnull_all + gcc_malloc + static InputStream *Open(const char *uri, Mutex &mutex, Cond &cond, + Error &error); + + /** + * Just like Open(), but waits for the stream to become ready. + * It is a wrapper for Open(), WaitReady() and Check(). + */ + gcc_malloc gcc_nonnull_all + static InputStream *OpenReady(const char *uri, + Mutex &mutex, Cond &cond, + Error &error); + + /** + * Close the input stream and free resources. + * + * The caller must not lock the mutex. + */ + void Close(); + + void Lock() { + mutex.lock(); + } + + void Unlock() { + mutex.unlock(); + } + + /** + * Check for errors that may have occurred in the I/O thread. + * + * @return false on error + */ + bool Check(Error &error); + + /** + * Update the public attributes. Call before accessing attributes + * such as "ready" or "offset". + */ + void Update(); + + /** + * Wait until the stream becomes ready. + * + * The caller must lock the mutex. + */ + void WaitReady(); + + /** + * Wrapper for WaitReady() which locks and unlocks the mutex; + * the caller must not be holding it already. + */ + void LockWaitReady(); + + gcc_pure + const char *GetMimeType() const { + assert(ready); + + return mime.empty() ? nullptr : mime.c_str(); + } + + gcc_nonnull_all + void OverrideMimeType(const char *_mime) { + assert(ready); + + mime = _mime; + } + + gcc_pure + offset_type GetSize() const { + assert(ready); + + return size; + } + + gcc_pure + offset_type GetOffset() const { + assert(ready); + + return offset; + } + + gcc_pure + bool IsSeekable() const { + assert(ready); + + return seekable; + } + + /** + * Determines whether seeking is cheap. This is true for local files. + */ + gcc_pure + bool CheapSeeking() const; + + /** + * Seeks to the specified position in the stream. This will most + * likely fail if the "seekable" flag is false. + * + * The caller must lock the mutex. + * + * @param offset the relative offset + * @param whence the base of the seek, one of SEEK_SET, SEEK_CUR, SEEK_END + */ + bool Seek(offset_type offset, int whence, Error &error); + + /** + * Wrapper for Seek() which locks and unlocks the mutex; the + * caller must not be holding it already. + */ + bool LockSeek(offset_type offset, int whence, Error &error); + + /** + * Rewind to the beginning of the stream. This is a wrapper + * for Seek(0, SEEK_SET, error). + */ + bool Rewind(Error &error); + bool LockRewind(Error &error); + + /** + * Returns true if the stream has reached end-of-file. + * + * The caller must lock the mutex. + */ + gcc_pure + bool IsEOF(); + + /** + * Wrapper for IsEOF() which locks and unlocks the mutex; the + * caller must not be holding it already. + */ + gcc_pure + bool LockIsEOF(); + + /** + * Reads the tag from the stream. + * + * The caller must lock the mutex. + * + * @return a tag object which must be freed by the caller, or + * nullptr if the tag has not changed since the last call + */ + gcc_malloc + Tag *ReadTag(); + + /** + * Wrapper for ReadTag() which locks and unlocks the mutex; + * the caller must not be holding it already. + */ + gcc_malloc + Tag *LockReadTag(); + + /** + * Returns true if the next read operation will not block: either data + * is available, or end-of-stream has been reached, or an error has + * occurred. + * + * The caller must lock the mutex. + */ + gcc_pure + bool IsAvailable(); + + /** + * Reads data from the stream into the caller-supplied buffer. + * Returns 0 on error or eof (check with IsEOF()). + * + * The caller must lock the mutex. + * + * @param is the InputStream object + * @param ptr the buffer to read into + * @param size the maximum number of bytes to read + * @return the number of bytes read + */ + gcc_nonnull_all + size_t Read(void *ptr, size_t size, Error &error); + + /** + * Wrapper for Read() which locks and unlocks the mutex; + * the caller must not be holding it already. + */ + gcc_nonnull_all + size_t LockRead(void *ptr, size_t size, Error &error); +}; + +#endif diff --git a/src/input/Registry.cxx b/src/input/Registry.cxx new file mode 100644 index 000000000..30c6a67e0 --- /dev/null +++ b/src/input/Registry.cxx @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2003-2014 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "Registry.hxx" +#include "util/Macros.hxx" +#include "plugins/FileInputPlugin.hxx" + +#ifdef HAVE_ALSA +#include "plugins/AlsaInputPlugin.hxx" +#endif + +#ifdef ENABLE_ARCHIVE +#include "plugins/ArchiveInputPlugin.hxx" +#endif + +#ifdef ENABLE_CURL +#include "plugins/CurlInputPlugin.hxx" +#endif + +#ifdef HAVE_FFMPEG +#include "plugins/FfmpegInputPlugin.hxx" +#endif + +#ifdef ENABLE_SMBCLIENT +#include "plugins/SmbclientInputPlugin.hxx" +#endif + +#ifdef ENABLE_MMS +#include "plugins/MmsInputPlugin.hxx" +#endif + +#ifdef ENABLE_CDIO_PARANOIA +#include "plugins/CdioParanoiaInputPlugin.hxx" +#endif + +#ifdef ENABLE_DESPOTIFY +#include "plugins/DespotifyInputPlugin.hxx" +#endif + +const InputPlugin *const input_plugins[] = { + &input_plugin_file, +#ifdef HAVE_ALSA + &input_plugin_alsa, +#endif +#ifdef ENABLE_ARCHIVE + &input_plugin_archive, +#endif +#ifdef ENABLE_CURL + &input_plugin_curl, +#endif +#ifdef HAVE_FFMPEG + &input_plugin_ffmpeg, +#endif +#ifdef ENABLE_SMBCLIENT + &input_plugin_smbclient, +#endif +#ifdef ENABLE_MMS + &input_plugin_mms, +#endif +#ifdef ENABLE_CDIO_PARANOIA + &input_plugin_cdio_paranoia, +#endif +#ifdef ENABLE_DESPOTIFY + &input_plugin_despotify, +#endif + nullptr +}; + +bool input_plugins_enabled[ARRAY_SIZE(input_plugins) - 1]; diff --git a/src/input/Registry.hxx b/src/input/Registry.hxx new file mode 100644 index 000000000..1b81f8f06 --- /dev/null +++ b/src/input/Registry.hxx @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2003-2014 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_INPUT_REGISTRY_HXX +#define MPD_INPUT_REGISTRY_HXX + +#include "check.h" + +/** + * NULL terminated list of all input plugins which were enabled at + * compile time. + */ +extern const struct InputPlugin *const input_plugins[]; + +extern bool input_plugins_enabled[]; + +#define input_plugins_for_each(plugin) \ + for (const InputPlugin *plugin, \ + *const*input_plugin_iterator = &input_plugins[0]; \ + (plugin = *input_plugin_iterator) != NULL; \ + ++input_plugin_iterator) + +#define input_plugins_for_each_enabled(plugin) \ + input_plugins_for_each(plugin) \ + if (input_plugins_enabled[input_plugin_iterator - input_plugins]) + +#endif diff --git a/src/input/TextInputStream.cxx b/src/input/TextInputStream.cxx new file mode 100644 index 000000000..25b9b42fe --- /dev/null +++ b/src/input/TextInputStream.cxx @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2003-2014 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "TextInputStream.hxx" +#include "InputStream.hxx" +#include "util/CharUtil.hxx" +#include "util/Error.hxx" +#include "Log.hxx" + +#include <assert.h> +#include <string.h> + +bool TextInputStream::ReadLine(std::string &line) +{ + const char *src, *p; + + do { + size_t nbytes; + auto dest = buffer.Write(); + if (dest.size >= 2) { + /* reserve one byte for the null terminator if + the last line is not terminated by a + newline character */ + --dest.size; + + Error error; + nbytes = is.LockRead(dest.data, dest.size, error); + if (nbytes > 0) + buffer.Append(nbytes); + else if (error.IsDefined()) { + LogError(error); + return false; + } + } else + nbytes = 0; + + auto src_p = buffer.Read(); + if (src_p.IsEmpty()) + return false; + + src = src_p.data; + + p = reinterpret_cast<const char*>(memchr(src, '\n', src_p.size)); + if (p == nullptr && nbytes == 0) { + /* end of file (or line too long): terminate + the current line */ + dest = buffer.Write(); + assert(!dest.IsEmpty()); + dest.data[0] = '\n'; + buffer.Append(1); + } + } while (p == nullptr); + + size_t length = p - src + 1; + while (p > src && IsWhitespaceOrNull(p[-1])) + --p; + + line = std::string(src, p - src); + buffer.Consume(length); + return true; +} diff --git a/src/input/TextInputStream.hxx b/src/input/TextInputStream.hxx new file mode 100644 index 000000000..86ae16e41 --- /dev/null +++ b/src/input/TextInputStream.hxx @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2003-2014 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_TEXT_INPUT_STREAM_HXX +#define MPD_TEXT_INPUT_STREAM_HXX + +#include "util/FifoBuffer.hxx" + +#include <string> + +struct InputStream; + +class TextInputStream { + InputStream &is; + FifoBuffer<char, 4096> buffer; + +public: + /** + * Wraps an existing #input_stream object into a #TextInputStream, + * to read its contents as text lines. + * + * @param _is an open #input_stream object + */ + explicit TextInputStream(InputStream &_is) + :is(_is) {} + + TextInputStream(const TextInputStream &) = delete; + TextInputStream& operator=(const TextInputStream &) = delete; + + /** + * Reads the next line from the stream with newline character stripped. + * + * @param line a string to put result to + * @return true if line is read successfully, false on end of file + * or error + */ + bool ReadLine(std::string &line); +}; + +#endif diff --git a/src/input/AlsaInputPlugin.cxx b/src/input/plugins/AlsaInputPlugin.cxx index 29c6b2504..da2d9a926 100644 --- a/src/input/AlsaInputPlugin.cxx +++ b/src/input/plugins/AlsaInputPlugin.cxx @@ -26,8 +26,8 @@ #include "config.h" #include "AlsaInputPlugin.hxx" -#include "InputPlugin.hxx" -#include "InputStream.hxx" +#include "../InputPlugin.hxx" +#include "../InputStream.hxx" #include "util/Domain.hxx" #include "util/Error.hxx" #include "util/StringUtil.hxx" diff --git a/src/input/AlsaInputPlugin.hxx b/src/input/plugins/AlsaInputPlugin.hxx index dda1e5176..dddf7dfd7 100644 --- a/src/input/AlsaInputPlugin.hxx +++ b/src/input/plugins/AlsaInputPlugin.hxx @@ -20,7 +20,7 @@ #ifndef MPD_ALSA_INPUT_PLUGIN_HXX #define MPD_ALSA_INPUT_PLUGIN_HXX -#include "InputPlugin.hxx" +#include "../InputPlugin.hxx" extern const struct InputPlugin input_plugin_alsa; diff --git a/src/input/ArchiveInputPlugin.cxx b/src/input/plugins/ArchiveInputPlugin.cxx index e5591a95e..df1a72585 100644 --- a/src/input/ArchiveInputPlugin.cxx +++ b/src/input/plugins/ArchiveInputPlugin.cxx @@ -24,7 +24,7 @@ #include "archive/ArchiveList.hxx" #include "archive/ArchivePlugin.hxx" #include "archive/ArchiveFile.hxx" -#include "InputPlugin.hxx" +#include "../InputPlugin.hxx" #include "fs/Traits.hxx" #include "util/Alloc.hxx" #include "Log.hxx" diff --git a/src/input/ArchiveInputPlugin.hxx b/src/input/plugins/ArchiveInputPlugin.hxx index 024723726..024723726 100644 --- a/src/input/ArchiveInputPlugin.hxx +++ b/src/input/plugins/ArchiveInputPlugin.hxx diff --git a/src/input/CdioParanoiaInputPlugin.cxx b/src/input/plugins/CdioParanoiaInputPlugin.cxx index 297ee84dc..9267b50e1 100644 --- a/src/input/CdioParanoiaInputPlugin.cxx +++ b/src/input/plugins/CdioParanoiaInputPlugin.cxx @@ -23,8 +23,8 @@ #include "config.h" #include "CdioParanoiaInputPlugin.hxx" -#include "InputStream.hxx" -#include "InputPlugin.hxx" +#include "../InputStream.hxx" +#include "../InputPlugin.hxx" #include "util/StringUtil.hxx" #include "util/Error.hxx" #include "util/Domain.hxx" diff --git a/src/input/CdioParanoiaInputPlugin.hxx b/src/input/plugins/CdioParanoiaInputPlugin.hxx index e2804e8c7..e2804e8c7 100644 --- a/src/input/CdioParanoiaInputPlugin.hxx +++ b/src/input/plugins/CdioParanoiaInputPlugin.hxx diff --git a/src/input/CurlInputPlugin.cxx b/src/input/plugins/CurlInputPlugin.cxx index 64321b38d..a3c6c1d1a 100644 --- a/src/input/CurlInputPlugin.cxx +++ b/src/input/plugins/CurlInputPlugin.cxx @@ -19,8 +19,8 @@ #include "config.h" #include "CurlInputPlugin.hxx" -#include "InputStream.hxx" -#include "InputPlugin.hxx" +#include "../InputStream.hxx" +#include "../InputPlugin.hxx" #include "config/ConfigGlobal.hxx" #include "config/ConfigData.hxx" #include "tag/Tag.hxx" diff --git a/src/input/CurlInputPlugin.hxx b/src/input/plugins/CurlInputPlugin.hxx index 4acb18bfc..4acb18bfc 100644 --- a/src/input/CurlInputPlugin.hxx +++ b/src/input/plugins/CurlInputPlugin.hxx diff --git a/src/input/DespotifyInputPlugin.cxx b/src/input/plugins/DespotifyInputPlugin.cxx index 29a80e585..a01ba3759 100644 --- a/src/input/DespotifyInputPlugin.cxx +++ b/src/input/plugins/DespotifyInputPlugin.cxx @@ -20,8 +20,8 @@ #include "config.h" #include "DespotifyInputPlugin.hxx" #include "DespotifyUtils.hxx" -#include "InputStream.hxx" -#include "InputPlugin.hxx" +#include "../InputStream.hxx" +#include "../InputPlugin.hxx" #include "tag/Tag.hxx" #include "util/StringUtil.hxx" #include "Log.hxx" diff --git a/src/input/DespotifyInputPlugin.hxx b/src/input/plugins/DespotifyInputPlugin.hxx index 83f963520..83f963520 100644 --- a/src/input/DespotifyInputPlugin.hxx +++ b/src/input/plugins/DespotifyInputPlugin.hxx diff --git a/src/input/FfmpegInputPlugin.cxx b/src/input/plugins/FfmpegInputPlugin.cxx index 50fec8aec..0d0a4375e 100644 --- a/src/input/FfmpegInputPlugin.cxx +++ b/src/input/plugins/FfmpegInputPlugin.cxx @@ -22,8 +22,8 @@ #include "config.h" #include "FfmpegInputPlugin.hxx" -#include "InputStream.hxx" -#include "InputPlugin.hxx" +#include "../InputStream.hxx" +#include "../InputPlugin.hxx" #include "util/StringUtil.hxx" #include "util/Error.hxx" #include "util/Domain.hxx" diff --git a/src/input/FfmpegInputPlugin.hxx b/src/input/plugins/FfmpegInputPlugin.hxx index 43f829e89..43f829e89 100644 --- a/src/input/FfmpegInputPlugin.hxx +++ b/src/input/plugins/FfmpegInputPlugin.hxx diff --git a/src/input/FileInputPlugin.cxx b/src/input/plugins/FileInputPlugin.cxx index d9f5a217f..780e93263 100644 --- a/src/input/FileInputPlugin.cxx +++ b/src/input/plugins/FileInputPlugin.cxx @@ -19,8 +19,8 @@ #include "config.h" /* must be first for large file support */ #include "FileInputPlugin.hxx" -#include "InputStream.hxx" -#include "InputPlugin.hxx" +#include "../InputStream.hxx" +#include "../InputPlugin.hxx" #include "util/Error.hxx" #include "util/Domain.hxx" #include "fs/Traits.hxx" diff --git a/src/input/FileInputPlugin.hxx b/src/input/plugins/FileInputPlugin.hxx index 4aef94637..4aef94637 100644 --- a/src/input/FileInputPlugin.hxx +++ b/src/input/plugins/FileInputPlugin.hxx diff --git a/src/input/MmsInputPlugin.cxx b/src/input/plugins/MmsInputPlugin.cxx index 8f946ae5e..a7068cb2b 100644 --- a/src/input/MmsInputPlugin.cxx +++ b/src/input/plugins/MmsInputPlugin.cxx @@ -19,8 +19,8 @@ #include "config.h" #include "MmsInputPlugin.hxx" -#include "InputStream.hxx" -#include "InputPlugin.hxx" +#include "../InputStream.hxx" +#include "../InputPlugin.hxx" #include "util/StringUtil.hxx" #include "util/Error.hxx" #include "util/Domain.hxx" diff --git a/src/input/MmsInputPlugin.hxx b/src/input/plugins/MmsInputPlugin.hxx index b4017ffd6..b4017ffd6 100644 --- a/src/input/MmsInputPlugin.hxx +++ b/src/input/plugins/MmsInputPlugin.hxx diff --git a/src/input/RewindInputPlugin.cxx b/src/input/plugins/RewindInputPlugin.cxx index 685ca1e6e..1a930ac53 100644 --- a/src/input/RewindInputPlugin.cxx +++ b/src/input/plugins/RewindInputPlugin.cxx @@ -19,8 +19,8 @@ #include "config.h" #include "RewindInputPlugin.hxx" -#include "InputStream.hxx" -#include "InputPlugin.hxx" +#include "../InputStream.hxx" +#include "../InputPlugin.hxx" #include <assert.h> #include <string.h> diff --git a/src/input/RewindInputPlugin.hxx b/src/input/plugins/RewindInputPlugin.hxx index f19705154..f19705154 100644 --- a/src/input/RewindInputPlugin.hxx +++ b/src/input/plugins/RewindInputPlugin.hxx diff --git a/src/input/SmbclientInputPlugin.cxx b/src/input/plugins/SmbclientInputPlugin.cxx index ed94d581a..9fbe72b59 100644 --- a/src/input/SmbclientInputPlugin.cxx +++ b/src/input/plugins/SmbclientInputPlugin.cxx @@ -19,8 +19,8 @@ #include "config.h" #include "SmbclientInputPlugin.hxx" -#include "InputStream.hxx" -#include "InputPlugin.hxx" +#include "../InputStream.hxx" +#include "../InputPlugin.hxx" #include "util/StringUtil.hxx" #include "util/Error.hxx" diff --git a/src/input/SmbclientInputPlugin.hxx b/src/input/plugins/SmbclientInputPlugin.hxx index a0539d020..a0539d020 100644 --- a/src/input/SmbclientInputPlugin.hxx +++ b/src/input/plugins/SmbclientInputPlugin.hxx |