playlist/Plugin: pass InputStreamPtr&& to open_stream()

Obsolete class CloseSongEnumerator, which was a kludge.
This commit is contained in:
Max Kellermann 2016-02-21 12:53:47 +01:00
parent cadc67ea40
commit 0705f42cf8
18 changed files with 97 additions and 157 deletions

View File

@ -1468,8 +1468,6 @@ endif
libplaylist_plugins_a_SOURCES = \ libplaylist_plugins_a_SOURCES = \
src/playlist/PlaylistPlugin.hxx \ src/playlist/PlaylistPlugin.hxx \
src/playlist/SongEnumerator.hxx \ src/playlist/SongEnumerator.hxx \
src/playlist/CloseSongEnumerator.cxx \
src/playlist/CloseSongEnumerator.hxx \
src/playlist/MemorySongEnumerator.cxx \ src/playlist/MemorySongEnumerator.cxx \
src/playlist/MemorySongEnumerator.hxx \ src/playlist/MemorySongEnumerator.hxx \
src/playlist/plugins/ExtM3uPlaylistPlugin.cxx \ src/playlist/plugins/ExtM3uPlaylistPlugin.cxx \

View File

@ -26,6 +26,11 @@
#include <assert.h> #include <assert.h>
TextInputStream::TextInputStream(InputStreamPtr &&_is)
:is(std::move(_is)) {}
TextInputStream::~TextInputStream() {}
char * char *
TextInputStream::ReadLine() TextInputStream::ReadLine()
{ {
@ -54,7 +59,7 @@ TextInputStream::ReadLine()
--dest.size; --dest.size;
Error error; Error error;
size_t nbytes = is.LockRead(dest.data, dest.size, error); size_t nbytes = is->LockRead(dest.data, dest.size, error);
if (nbytes > 0) if (nbytes > 0)
buffer.Append(nbytes); buffer.Append(nbytes);
else if (error.IsDefined()) { else if (error.IsDefined()) {

View File

@ -20,12 +20,13 @@
#ifndef MPD_TEXT_INPUT_STREAM_HXX #ifndef MPD_TEXT_INPUT_STREAM_HXX
#define MPD_TEXT_INPUT_STREAM_HXX #define MPD_TEXT_INPUT_STREAM_HXX
#include "input/Ptr.hxx"
#include "util/StaticFifoBuffer.hxx" #include "util/StaticFifoBuffer.hxx"
class InputStream; class InputStream;
class TextInputStream { class TextInputStream {
InputStream &is; InputStreamPtr is;
StaticFifoBuffer<char, 4096> buffer; StaticFifoBuffer<char, 4096> buffer;
public: public:
@ -35,12 +36,16 @@ public:
* *
* @param _is an open #InputStream object * @param _is an open #InputStream object
*/ */
explicit TextInputStream(InputStream &_is) explicit TextInputStream(InputStreamPtr &&_is);
:is(_is) {} ~TextInputStream();
TextInputStream(const TextInputStream &) = delete; TextInputStream(const TextInputStream &) = delete;
TextInputStream& operator=(const TextInputStream &) = delete; TextInputStream& operator=(const TextInputStream &) = delete;
InputStreamPtr &&StealInputStream() {
return std::move(is);
}
/** /**
* Reads the next line from the stream with newline character stripped. * Reads the next line from the stream with newline character stripped.
* *

View File

@ -1,35 +0,0 @@
/*
* Copyright (C) 2003-2015 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 "CloseSongEnumerator.hxx"
#include "input/InputStream.hxx"
#include "DetachedSong.hxx"
CloseSongEnumerator::~CloseSongEnumerator()
{
delete other;
delete is;
}
std::unique_ptr<DetachedSong>
CloseSongEnumerator::NextSong()
{
return other->NextSong();
}

View File

@ -1,47 +0,0 @@
/*
* Copyright (C) 2003-2015 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_CLOSE_SONG_ENUMERATOR_HXX
#define MPD_CLOSE_SONG_ENUMERATOR_HXX
#include "SongEnumerator.hxx"
#include "Compiler.h"
class InputStream;
/**
* A #SongEnumerator wrapper that closes an #InputStream automatically
* after deleting the #SongEnumerator
*/
class CloseSongEnumerator final : public SongEnumerator {
SongEnumerator *const other;
InputStream *const is;
public:
gcc_nonnull_all
CloseSongEnumerator(SongEnumerator *_other, InputStream *const _is)
:other(_other), is(_is) {}
virtual ~CloseSongEnumerator();
virtual std::unique_ptr<DetachedSong> NextSong() override;
};
#endif

View File

@ -20,8 +20,9 @@
#ifndef MPD_PLAYLIST_PLUGIN_HXX #ifndef MPD_PLAYLIST_PLUGIN_HXX
#define MPD_PLAYLIST_PLUGIN_HXX #define MPD_PLAYLIST_PLUGIN_HXX
#include "input/Ptr.hxx"
struct ConfigBlock; struct ConfigBlock;
class InputStream;
struct Tag; struct Tag;
class Mutex; class Mutex;
class Cond; class Cond;
@ -57,8 +58,11 @@ struct playlist_plugin {
* Opens the playlist in the specified input stream. It has * Opens the playlist in the specified input stream. It has
* either matched one of the suffixes or one of the MIME * either matched one of the suffixes or one of the MIME
* types. * types.
*
* @parm is the input stream; the pointer will not be
* invalidated when the function returns nullptr
*/ */
SongEnumerator *(*open_stream)(InputStream &is); SongEnumerator *(*open_stream)(InputStreamPtr &&is);
const char *const*schemes; const char *const*schemes;
const char *const*suffixes; const char *const*suffixes;
@ -101,9 +105,9 @@ playlist_plugin_open_uri(const struct playlist_plugin *plugin, const char *uri,
static inline SongEnumerator * static inline SongEnumerator *
playlist_plugin_open_stream(const struct playlist_plugin *plugin, playlist_plugin_open_stream(const struct playlist_plugin *plugin,
InputStream &is) InputStreamPtr &&is)
{ {
return plugin->open_stream(is); return plugin->open_stream(std::move(is));
} }
#endif #endif

View File

@ -183,7 +183,7 @@ playlist_list_open_uri(const char *uri, Mutex &mutex, Cond &cond)
} }
static SongEnumerator * static SongEnumerator *
playlist_list_open_stream_mime2(InputStream &is, const char *mime) playlist_list_open_stream_mime2(InputStreamPtr &&is, const char *mime)
{ {
assert(mime != nullptr); assert(mime != nullptr);
@ -193,10 +193,10 @@ playlist_list_open_stream_mime2(InputStream &is, const char *mime)
string_array_contains(plugin->mime_types, mime)) { string_array_contains(plugin->mime_types, mime)) {
/* rewind the stream, so each plugin gets a /* rewind the stream, so each plugin gets a
fresh start */ fresh start */
is.Rewind(IgnoreError()); is->Rewind(IgnoreError());
auto playlist = playlist_plugin_open_stream(plugin, auto playlist = playlist_plugin_open_stream(plugin,
is); std::move(is));
if (playlist != nullptr) if (playlist != nullptr)
return playlist; return playlist;
} }
@ -206,24 +206,25 @@ playlist_list_open_stream_mime2(InputStream &is, const char *mime)
} }
static SongEnumerator * static SongEnumerator *
playlist_list_open_stream_mime(InputStream &is, const char *full_mime) playlist_list_open_stream_mime(InputStreamPtr &&is, const char *full_mime)
{ {
assert(full_mime != nullptr); assert(full_mime != nullptr);
const char *semicolon = strchr(full_mime, ';'); const char *semicolon = strchr(full_mime, ';');
if (semicolon == nullptr) if (semicolon == nullptr)
return playlist_list_open_stream_mime2(is, full_mime); return playlist_list_open_stream_mime2(std::move(is),
full_mime);
if (semicolon == full_mime) if (semicolon == full_mime)
return nullptr; return nullptr;
/* probe only the portion before the semicolon*/ /* probe only the portion before the semicolon*/
const std::string mime(full_mime, semicolon); const std::string mime(full_mime, semicolon);
return playlist_list_open_stream_mime2(is, mime.c_str()); return playlist_list_open_stream_mime2(std::move(is), mime.c_str());
} }
SongEnumerator * SongEnumerator *
playlist_list_open_stream_suffix(InputStream &is, const char *suffix) playlist_list_open_stream_suffix(InputStreamPtr &&is, const char *suffix)
{ {
assert(suffix != nullptr); assert(suffix != nullptr);
@ -233,9 +234,10 @@ playlist_list_open_stream_suffix(InputStream &is, const char *suffix)
string_array_contains(plugin->suffixes, suffix)) { string_array_contains(plugin->suffixes, suffix)) {
/* rewind the stream, so each plugin gets a /* rewind the stream, so each plugin gets a
fresh start */ fresh start */
is.Rewind(IgnoreError()); is->Rewind(IgnoreError());
auto playlist = playlist_plugin_open_stream(plugin, is); auto playlist = playlist_plugin_open_stream(plugin,
std::move(is));
if (playlist != nullptr) if (playlist != nullptr)
return playlist; return playlist;
} }
@ -245,13 +247,14 @@ playlist_list_open_stream_suffix(InputStream &is, const char *suffix)
} }
SongEnumerator * SongEnumerator *
playlist_list_open_stream(InputStream &is, const char *uri) playlist_list_open_stream(InputStreamPtr &&is, const char *uri)
{ {
assert(is.IsReady()); assert(is->IsReady());
const char *const mime = is.GetMimeType(); const char *const mime = is->GetMimeType();
if (mime != nullptr) { if (mime != nullptr) {
auto playlist = playlist_list_open_stream_mime(is, mime); auto playlist = playlist_list_open_stream_mime(std::move(is),
mime);
if (playlist != nullptr) if (playlist != nullptr)
return playlist; return playlist;
} }
@ -261,7 +264,8 @@ playlist_list_open_stream(InputStream &is, const char *uri)
? uri_get_suffix(uri, suffix_buffer) ? uri_get_suffix(uri, suffix_buffer)
: nullptr; : nullptr;
if (suffix != nullptr) { if (suffix != nullptr) {
auto playlist = playlist_list_open_stream_suffix(is, suffix); auto playlist = playlist_list_open_stream_suffix(std::move(is),
suffix);
if (playlist != nullptr) if (playlist != nullptr)
return playlist; return playlist;
} }

View File

@ -20,10 +20,11 @@
#ifndef MPD_PLAYLIST_REGISTRY_HXX #ifndef MPD_PLAYLIST_REGISTRY_HXX
#define MPD_PLAYLIST_REGISTRY_HXX #define MPD_PLAYLIST_REGISTRY_HXX
#include "input/Ptr.hxx"
class Mutex; class Mutex;
class Cond; class Cond;
class SongEnumerator; class SongEnumerator;
class InputStream;
extern const struct playlist_plugin *const playlist_plugins[]; extern const struct playlist_plugin *const playlist_plugins[];
@ -52,7 +53,7 @@ SongEnumerator *
playlist_list_open_uri(const char *uri, Mutex &mutex, Cond &cond); playlist_list_open_uri(const char *uri, Mutex &mutex, Cond &cond);
SongEnumerator * SongEnumerator *
playlist_list_open_stream_suffix(InputStream &is, const char *suffix); playlist_list_open_stream_suffix(InputStreamPtr &&is, const char *suffix);
/** /**
* Opens a playlist from an input stream. * Opens a playlist from an input stream.
@ -62,7 +63,7 @@ playlist_list_open_stream_suffix(InputStream &is, const char *suffix);
* used to select the appropriate playlist plugin * used to select the appropriate playlist plugin
*/ */
SongEnumerator * SongEnumerator *
playlist_list_open_stream(InputStream &is, const char *uri); playlist_list_open_stream(InputStreamPtr &&is, const char *uri);
/** /**
* Determines if there is a playlist plugin which can handle the * Determines if there is a playlist plugin which can handle the

View File

@ -20,7 +20,6 @@
#include "config.h" #include "config.h"
#include "PlaylistStream.hxx" #include "PlaylistStream.hxx"
#include "PlaylistRegistry.hxx" #include "PlaylistRegistry.hxx"
#include "CloseSongEnumerator.hxx"
#include "util/UriUtil.hxx" #include "util/UriUtil.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include "input/InputStream.hxx" #include "input/InputStream.hxx"
@ -50,12 +49,8 @@ try {
return nullptr; return nullptr;
} }
auto playlist = playlist_list_open_stream_suffix(*is, return playlist_list_open_stream_suffix(std::move(is),
suffix_utf8.c_str()); suffix_utf8.c_str());
if (playlist != nullptr)
playlist = new CloseSongEnumerator(playlist, is.release());
return playlist;
} catch (const std::runtime_error &e) { } catch (const std::runtime_error &e) {
LogError(e); LogError(e);
return nullptr; return nullptr;
@ -97,11 +92,7 @@ try {
return nullptr; return nullptr;
} }
playlist = playlist_list_open_stream(*is, uri); return playlist_list_open_stream(std::move(is), uri);
if (playlist == nullptr)
return nullptr;
return new CloseSongEnumerator(playlist, is.release());
} catch (const std::runtime_error &e) { } catch (const std::runtime_error &e) {
LogError(e); LogError(e);
return nullptr; return nullptr;

View File

@ -144,7 +144,7 @@ asx_char_data(void *user_data, const XML_Char *s, int len)
*/ */
static SongEnumerator * static SongEnumerator *
asx_open_stream(InputStream &is) asx_open_stream(InputStreamPtr &&is)
{ {
AsxParser parser; AsxParser parser;
@ -154,7 +154,7 @@ asx_open_stream(InputStream &is)
expat.SetCharacterDataHandler(asx_char_data); expat.SetCharacterDataHandler(asx_char_data);
Error error; Error error;
if (!expat.Parse(is, error)) { if (!expat.Parse(*is, error)) {
LogError(error); LogError(error);
return nullptr; return nullptr;
} }

View File

@ -27,22 +27,21 @@
#include <string> #include <string>
class CuePlaylist final : public SongEnumerator { class CuePlaylist final : public SongEnumerator {
InputStream &is;
TextInputStream tis; TextInputStream tis;
CueParser parser; CueParser parser;
public: public:
CuePlaylist(InputStream &_is) CuePlaylist(InputStreamPtr &&is)
:is(_is), tis(is) { :tis(std::move(is)) {
} }
virtual std::unique_ptr<DetachedSong> NextSong() override; virtual std::unique_ptr<DetachedSong> NextSong() override;
}; };
static SongEnumerator * static SongEnumerator *
cue_playlist_open_stream(InputStream &is) cue_playlist_open_stream(InputStreamPtr &&is)
{ {
return new CuePlaylist(is); return new CuePlaylist(std::move(is));
} }
std::unique_ptr<DetachedSong> std::unique_ptr<DetachedSong>

View File

@ -27,6 +27,7 @@
#include "util/StringUtil.hxx" #include "util/StringUtil.hxx"
#include "util/StringCompare.hxx" #include "util/StringCompare.hxx"
#include "input/TextInputStream.hxx" #include "input/TextInputStream.hxx"
#include "input/InputStream.hxx"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@ -35,28 +36,36 @@ class ExtM3uPlaylist final : public SongEnumerator {
TextInputStream tis; TextInputStream tis;
public: public:
ExtM3uPlaylist(InputStream &is) ExtM3uPlaylist(InputStreamPtr &&is)
:tis(is) { :tis(std::move(is)) {
} }
bool CheckFirstLine() { /**
* @return nullptr if ExtM3U was recognized, or the original
* InputStream on error
*/
InputStreamPtr CheckFirstLine() {
char *line = tis.ReadLine(); char *line = tis.ReadLine();
if (line == nullptr) if (line == nullptr)
return false; return tis.StealInputStream();
StripRight(line); StripRight(line);
return strcmp(line, "#EXTM3U") == 0; if (strcmp(line, "#EXTM3U") != 0)
return tis.StealInputStream();
return nullptr;
} }
virtual std::unique_ptr<DetachedSong> NextSong() override; virtual std::unique_ptr<DetachedSong> NextSong() override;
}; };
static SongEnumerator * static SongEnumerator *
extm3u_open_stream(InputStream &is) extm3u_open_stream(InputStreamPtr &&is)
{ {
ExtM3uPlaylist *playlist = new ExtM3uPlaylist(is); ExtM3uPlaylist *playlist = new ExtM3uPlaylist(std::move(is));
if (!playlist->CheckFirstLine()) { is = playlist->CheckFirstLine();
if (is) {
/* no EXTM3U header: fall back to the plain m3u /* no EXTM3U header: fall back to the plain m3u
plugin */ plugin */
delete playlist; delete playlist;

View File

@ -29,17 +29,17 @@ class M3uPlaylist final : public SongEnumerator {
TextInputStream tis; TextInputStream tis;
public: public:
M3uPlaylist(InputStream &is) M3uPlaylist(InputStreamPtr &&is)
:tis(is) { :tis(std::move(is)) {
} }
virtual std::unique_ptr<DetachedSong> NextSong() override; virtual std::unique_ptr<DetachedSong> NextSong() override;
}; };
static SongEnumerator * static SongEnumerator *
m3u_open_stream(InputStream &is) m3u_open_stream(InputStreamPtr &&is)
{ {
return new M3uPlaylist(is); return new M3uPlaylist(std::move(is));
} }
std::unique_ptr<DetachedSong> std::unique_ptr<DetachedSong>

View File

@ -22,6 +22,7 @@
#include "../PlaylistPlugin.hxx" #include "../PlaylistPlugin.hxx"
#include "../MemorySongEnumerator.hxx" #include "../MemorySongEnumerator.hxx"
#include "input/TextInputStream.hxx" #include "input/TextInputStream.hxx"
#include "input/InputStream.hxx"
#include "DetachedSong.hxx" #include "DetachedSong.hxx"
#include "tag/TagBuilder.hxx" #include "tag/TagBuilder.hxx"
#include "util/ASCII.hxx" #include "util/ASCII.hxx"
@ -142,17 +143,22 @@ ParsePls(TextInputStream &is, std::forward_list<DetachedSong> &songs)
} }
static bool static bool
ParsePls(InputStream &is, std::forward_list<DetachedSong> &songs) ParsePls(InputStreamPtr &&is, std::forward_list<DetachedSong> &songs)
{ {
TextInputStream tis(is); TextInputStream tis(std::move(is));
return ParsePls(tis, songs); if (!ParsePls(tis, songs)) {
is = tis.StealInputStream();
return false;
}
return true;
} }
static SongEnumerator * static SongEnumerator *
pls_open_stream(InputStream &is) pls_open_stream(InputStreamPtr &&is)
{ {
std::forward_list<DetachedSong> songs; std::forward_list<DetachedSong> songs;
if (!ParsePls(is, songs)) if (!ParsePls(std::move(is), songs))
return nullptr; return nullptr;
return new MemorySongEnumerator(std::move(songs)); return new MemorySongEnumerator(std::move(songs));

View File

@ -142,7 +142,7 @@ rss_char_data(void *user_data, const XML_Char *s, int len)
*/ */
static SongEnumerator * static SongEnumerator *
rss_open_stream(InputStream &is) rss_open_stream(InputStreamPtr &&is)
{ {
RssParser parser; RssParser parser;
@ -152,7 +152,7 @@ rss_open_stream(InputStream &is)
expat.SetCharacterDataHandler(rss_char_data); expat.SetCharacterDataHandler(rss_char_data);
Error error; Error error;
if (!expat.Parse(is, error)) { if (!expat.Parse(*is, error)) {
LogError(error); LogError(error);
return nullptr; return nullptr;
} }

View File

@ -189,7 +189,7 @@ xspf_char_data(void *user_data, const XML_Char *s, int len)
*/ */
static SongEnumerator * static SongEnumerator *
xspf_open_stream(InputStream &is) xspf_open_stream(InputStreamPtr &&is)
{ {
XspfParser parser; XspfParser parser;
@ -199,7 +199,7 @@ xspf_open_stream(InputStream &is)
expat.SetCharacterDataHandler(xspf_char_data); expat.SetCharacterDataHandler(xspf_char_data);
Error error; Error error;
if (!expat.Parse(is, error)) { if (!expat.Parse(*is, error)) {
LogError(error); LogError(error);
return nullptr; return nullptr;
} }

View File

@ -98,7 +98,7 @@ try {
/* open the playlist */ /* open the playlist */
playlist = playlist_list_open_stream(*is, uri); playlist = playlist_list_open_stream(std::move(is), uri);
if (playlist == NULL) { if (playlist == NULL) {
fprintf(stderr, "Failed to open playlist\n"); fprintf(stderr, "Failed to open playlist\n");
return 2; return 2;

View File

@ -44,23 +44,23 @@ dump_text_file(TextInputStream &is)
} }
static int static int
dump_input_stream(InputStream &is) dump_input_stream(InputStreamPtr &&is)
{ {
{ {
TextInputStream tis(is); TextInputStream tis(std::move(is));
dump_text_file(tis); dump_text_file(tis);
} }
is.Lock(); is->Lock();
Error error; Error error;
if (!is.Check(error)) { if (!is->Check(error)) {
LogError(error); LogError(error);
is.Unlock(); is->Unlock();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
is.Unlock(); is->Unlock();
return 0; return 0;
} }
@ -98,7 +98,7 @@ int main(int argc, char **argv)
auto is = InputStream::OpenReady(argv[1], mutex, cond, error); auto is = InputStream::OpenReady(argv[1], mutex, cond, error);
if (is) { if (is) {
ret = dump_input_stream(*is); ret = dump_input_stream(std::move(is));
} else { } else {
if (error.IsDefined()) if (error.IsDefined())
LogError(error); LogError(error);