summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2018-07-05 19:07:05 +0200
committerMax Kellermann <max@musicpd.org>2018-07-05 19:07:05 +0200
commit3d3a1232b1d2b58d2cc05b2dd5c37f2256832693 (patch)
tree250933da4d5dc29145ce18e5a05a7f8da30396fd
parent09d4176210d66cf9e2d258b563a7811892c560f4 (diff)
tag/Handler: convert to class with virtual methods
-rw-r--r--src/TagArchive.cxx4
-rw-r--r--src/TagArchive.hxx4
-rw-r--r--src/TagFile.cxx22
-rw-r--r--src/TagFile.hxx5
-rw-r--r--src/TagStream.cxx20
-rw-r--r--src/TagStream.hxx10
-rw-r--r--src/command/FileCommands.cxx28
-rw-r--r--src/command/OtherCommands.cxx27
-rw-r--r--src/decoder/DecoderPlugin.hxx20
-rw-r--r--src/decoder/plugins/AdPlugDecoderPlugin.cxx19
-rw-r--r--src/decoder/plugins/AudiofileDecoderPlugin.cxx5
-rw-r--r--src/decoder/plugins/DsdLib.cxx7
-rw-r--r--src/decoder/plugins/DsdLib.hxx7
-rw-r--r--src/decoder/plugins/DsdiffDecoderPlugin.cxx23
-rw-r--r--src/decoder/plugins/DsfDecoderPlugin.cxx8
-rw-r--r--src/decoder/plugins/FaadDecoderPlugin.cxx6
-rw-r--r--src/decoder/plugins/FfmpegDecoderPlugin.cxx34
-rw-r--r--src/decoder/plugins/FfmpegMetaData.cxx26
-rw-r--r--src/decoder/plugins/FfmpegMetaData.hxx5
-rw-r--r--src/decoder/plugins/FlacDecoderPlugin.cxx20
-rw-r--r--src/decoder/plugins/FlacMetadata.cxx35
-rw-r--r--src/decoder/plugins/FlacMetadata.hxx6
-rw-r--r--src/decoder/plugins/FluidsynthDecoderPlugin.cxx3
-rw-r--r--src/decoder/plugins/GmeDecoderPlugin.cxx41
-rw-r--r--src/decoder/plugins/MadDecoderPlugin.cxx6
-rw-r--r--src/decoder/plugins/MikmodDecoderPlugin.cxx6
-rw-r--r--src/decoder/plugins/ModplugDecoderPlugin.cxx9
-rw-r--r--src/decoder/plugins/MpcdecDecoderPlugin.cxx5
-rw-r--r--src/decoder/plugins/Mpg123DecoderPlugin.cxx5
-rw-r--r--src/decoder/plugins/OpusDecoderPlugin.cxx20
-rw-r--r--src/decoder/plugins/OpusTags.cxx14
-rw-r--r--src/decoder/plugins/OpusTags.hxx4
-rw-r--r--src/decoder/plugins/SidplayDecoderPlugin.cxx28
-rw-r--r--src/decoder/plugins/SndfileDecoderPlugin.cxx12
-rw-r--r--src/decoder/plugins/VorbisDecoderPlugin.cxx12
-rw-r--r--src/decoder/plugins/WavpackDecoderPlugin.cxx10
-rw-r--r--src/decoder/plugins/WildmidiDecoderPlugin.cxx5
-rw-r--r--src/lib/xiph/VorbisComments.cxx26
-rw-r--r--src/lib/xiph/VorbisComments.hxx5
-rw-r--r--src/playlist/plugins/EmbeddedCuePlaylistPlugin.cxx40
-rw-r--r--src/tag/ApeTag.cxx23
-rw-r--r--src/tag/ApeTag.hxx7
-rw-r--r--src/tag/Generic.cxx10
-rw-r--r--src/tag/Generic.hxx6
-rw-r--r--src/tag/Handler.cxx30
-rw-r--r--src/tag/Handler.hxx105
-rw-r--r--src/tag/Id3Scan.cxx80
-rw-r--r--src/tag/Id3Scan.hxx8
-rw-r--r--test/read_tags.cxx51
49 files changed, 415 insertions, 497 deletions
diff --git a/src/TagArchive.cxx b/src/TagArchive.cxx
index ce0f2ed39..a2d014d52 100644
--- a/src/TagArchive.cxx
+++ b/src/TagArchive.cxx
@@ -25,7 +25,7 @@
bool
tag_archive_scan(ArchiveFile &archive, const char *path_utf8,
- const TagHandler &handler, void *handler_ctx) noexcept
+ TagHandler &handler) noexcept
try {
Mutex mutex;
@@ -33,7 +33,7 @@ try {
if (!is)
return false;
- return tag_stream_scan(*is, handler, handler_ctx);
+ return tag_stream_scan(*is, handler);
} catch (const std::exception &e) {
return false;
}
diff --git a/src/TagArchive.hxx b/src/TagArchive.hxx
index 466ba8e78..f11b05fee 100644
--- a/src/TagArchive.hxx
+++ b/src/TagArchive.hxx
@@ -23,7 +23,7 @@
#include "check.h"
class ArchiveFile;
-struct TagHandler;
+class TagHandler;
class TagBuilder;
/**
@@ -36,7 +36,7 @@ class TagBuilder;
*/
bool
tag_archive_scan(ArchiveFile &archive, const char *path_utf8,
- const TagHandler &handler, void *handler_ctx) noexcept;
+ TagHandler &handler) noexcept;
/**
* Scan the tags of a song file inside an archive. Invokes matching
diff --git a/src/TagFile.cxx b/src/TagFile.cxx
index da25102bf..3ecef36b8 100644
--- a/src/TagFile.cxx
+++ b/src/TagFile.cxx
@@ -36,21 +36,20 @@ class TagFileScan {
const Path path_fs;
const char *const suffix;
- const TagHandler &handler;
- void *handler_ctx;
+ TagHandler &handler;
Mutex mutex;
InputStreamPtr is;
public:
TagFileScan(Path _path_fs, const char *_suffix,
- const TagHandler &_handler, void *_handler_ctx) noexcept
+ TagHandler &_handler) noexcept
:path_fs(_path_fs), suffix(_suffix),
- handler(_handler), handler_ctx(_handler_ctx) ,
+ handler(_handler),
is(nullptr) {}
bool ScanFile(const DecoderPlugin &plugin) noexcept {
- return plugin.ScanFile(path_fs, handler, handler_ctx);
+ return plugin.ScanFile(path_fs, handler);
}
bool ScanStream(const DecoderPlugin &plugin) noexcept {
@@ -72,7 +71,7 @@ public:
}
/* now try the stream_tag() method */
- return plugin.ScanStream(*is, handler, handler_ctx);
+ return plugin.ScanStream(*is, handler);
}
bool Scan(const DecoderPlugin &plugin) noexcept {
@@ -82,8 +81,7 @@ public:
};
bool
-tag_file_scan(Path path_fs,
- const TagHandler &handler, void *handler_ctx) noexcept
+tag_file_scan(Path path_fs, TagHandler &handler) noexcept
{
assert(!path_fs.IsNull());
@@ -95,7 +93,7 @@ tag_file_scan(Path path_fs,
const auto suffix_utf8 = Path::FromFS(suffix).ToUTF8();
- TagFileScan tfs(path_fs, suffix_utf8.c_str(), handler, handler_ctx);
+ TagFileScan tfs(path_fs, suffix_utf8.c_str(), handler);
return decoder_plugins_try([&](const DecoderPlugin &plugin){
return tfs.Scan(plugin);
});
@@ -104,11 +102,13 @@ tag_file_scan(Path path_fs,
bool
tag_file_scan(Path path, TagBuilder &builder) noexcept
{
- if (!tag_file_scan(path, full_tag_handler, &builder))
+ FullTagHandler h(builder);
+
+ if (!tag_file_scan(path, h))
return false;
if (builder.empty())
- ScanGenericTags(path, full_tag_handler, &builder);
+ ScanGenericTags(path, h);
return true;
}
diff --git a/src/TagFile.hxx b/src/TagFile.hxx
index 851cc9633..427c29c28 100644
--- a/src/TagFile.hxx
+++ b/src/TagFile.hxx
@@ -23,7 +23,7 @@
#include "check.h"
class Path;
-struct TagHandler;
+class TagHandler;
class TagBuilder;
/**
@@ -34,8 +34,7 @@ class TagBuilder;
* found)
*/
bool
-tag_file_scan(Path path,
- const TagHandler &handler, void *handler_ctx) noexcept;
+tag_file_scan(Path path, TagHandler &handler) noexcept;
/**
* Scan the tags of a song file. Invokes matching decoder plugins,
diff --git a/src/TagStream.cxx b/src/TagStream.cxx
index 0d57f050b..c4ceb736e 100644
--- a/src/TagStream.cxx
+++ b/src/TagStream.cxx
@@ -46,7 +46,7 @@ CheckDecoderPlugin(const DecoderPlugin &plugin,
}
bool
-tag_stream_scan(InputStream &is, const TagHandler &handler, void *ctx)
+tag_stream_scan(InputStream &is, TagHandler &handler) noexcept
{
assert(is.IsReady());
@@ -62,44 +62,46 @@ tag_stream_scan(InputStream &is, const TagHandler &handler, void *ctx)
mime = (mime_base = GetMimeTypeBase(mime)).c_str();
return decoder_plugins_try([suffix, mime, &is,
- &handler, ctx](const DecoderPlugin &plugin){
+ &handler](const DecoderPlugin &plugin){
try {
is.LockRewind();
} catch (...) {
}
return CheckDecoderPlugin(plugin, suffix, mime) &&
- plugin.ScanStream(is, handler, ctx);
+ plugin.ScanStream(is, handler);
});
}
bool
-tag_stream_scan(const char *uri, const TagHandler &handler, void *ctx)
+tag_stream_scan(const char *uri, TagHandler &handler) noexcept
try {
Mutex mutex;
auto is = InputStream::OpenReady(uri, mutex);
- return tag_stream_scan(*is, handler, ctx);
+ return tag_stream_scan(*is, handler);
} catch (const std::exception &e) {
return false;
}
bool
-tag_stream_scan(InputStream &is, TagBuilder &builder)
+tag_stream_scan(InputStream &is, TagBuilder &builder) noexcept
{
assert(is.IsReady());
- if (!tag_stream_scan(is, full_tag_handler, &builder))
+ FullTagHandler h(builder);
+
+ if (!tag_stream_scan(is, h))
return false;
if (builder.empty())
- ScanGenericTags(is, full_tag_handler, &builder);
+ ScanGenericTags(is, h);
return true;
}
bool
-tag_stream_scan(const char *uri, TagBuilder &builder)
+tag_stream_scan(const char *uri, TagBuilder &builder) noexcept
try {
Mutex mutex;
diff --git a/src/TagStream.hxx b/src/TagStream.hxx
index eb3037661..136b380a5 100644
--- a/src/TagStream.hxx
+++ b/src/TagStream.hxx
@@ -23,7 +23,7 @@
#include "check.h"
class InputStream;
-struct TagHandler;
+class TagHandler;
class TagBuilder;
/**
@@ -34,10 +34,10 @@ class TagBuilder;
* found)
*/
bool
-tag_stream_scan(InputStream &is, const TagHandler &handler, void *ctx);
+tag_stream_scan(InputStream &is, TagHandler &handler) noexcept;
bool
-tag_stream_scan(const char *uri, const TagHandler &handler, void *ctx);
+tag_stream_scan(const char *uri, TagHandler &handler) noexcept;
/**
* Scan the tags of an #InputStream. Invokes matching decoder
@@ -48,9 +48,9 @@ tag_stream_scan(const char *uri, const TagHandler &handler, void *ctx);
* found)
*/
bool
-tag_stream_scan(InputStream &is, TagBuilder &builder);
+tag_stream_scan(InputStream &is, TagBuilder &builder) noexcept;
bool
-tag_stream_scan(const char *uri, TagBuilder &builder);
+tag_stream_scan(const char *uri, TagBuilder &builder) noexcept;
#endif
diff --git a/src/command/FileCommands.cxx b/src/command/FileCommands.cxx
index 488c6a798..744db8619 100644
--- a/src/command/FileCommands.cxx
+++ b/src/command/FileCommands.cxx
@@ -137,25 +137,24 @@ IsValidValue(const char *p) noexcept
return true;
}
-static void
-print_pair(const char *key, const char *value, void *ctx)
-{
- auto &r = *(Response *)ctx;
+class PrintCommentHandler final : public NullTagHandler {
+ Response &response;
- if (IsValidName(key) && IsValidValue(value))
- r.Format("%s: %s\n", key, value);
-}
+public:
+ explicit PrintCommentHandler(Response &_response) noexcept
+ :NullTagHandler(WANT_PAIR), response(_response) {}
-static constexpr TagHandler print_comment_handler = {
- nullptr,
- nullptr,
- print_pair,
+ void OnPair(const char *key, const char *value) noexcept override {
+ if (IsValidName(key) && IsValidValue(value))
+ response.Format("%s: %s\n", key, value);
+ }
};
static CommandResult
read_stream_comments(Response &r, const char *uri)
{
- if (!tag_stream_scan(uri, print_comment_handler, &r)) {
+ PrintCommentHandler h(r);
+ if (!tag_stream_scan(uri, h)) {
r.Error(ACK_ERROR_NO_EXIST, "Failed to load file");
return CommandResult::ERROR;
}
@@ -167,12 +166,13 @@ read_stream_comments(Response &r, const char *uri)
static CommandResult
read_file_comments(Response &r, const Path path_fs)
{
- if (!tag_file_scan(path_fs, print_comment_handler, &r)) {
+ PrintCommentHandler h(r);
+ if (!tag_file_scan(path_fs, h)) {
r.Error(ACK_ERROR_NO_EXIST, "Failed to load file");
return CommandResult::ERROR;
}
- ScanGenericTags(path_fs, print_comment_handler, &r);
+ ScanGenericTags(path_fs, h);
return CommandResult::OK;
diff --git a/src/command/OtherCommands.cxx b/src/command/OtherCommands.cxx
index b748ce2ff..b08468aca 100644
--- a/src/command/OtherCommands.cxx
+++ b/src/command/OtherCommands.cxx
@@ -93,15 +93,6 @@ handle_kill(gcc_unused Client &client, gcc_unused Request request,
return CommandResult::KILL;
}
-static void
-print_tag(TagType type, const char *value, void *ctx)
-{
- auto &r = *(Response *)ctx;
-
- if (r.GetClient().tag_mask.Test(type))
- tag_print(r, type, value);
-}
-
CommandResult
handle_listfiles(Client &client, Request args, Response &r)
{
@@ -149,16 +140,24 @@ handle_listfiles(Client &client, Request args, Response &r)
gcc_unreachable();
}
-static constexpr TagHandler print_tag_handler = {
- nullptr,
- print_tag,
- nullptr,
+class PrintTagHandler final : public NullTagHandler {
+ Response &response;
+
+public:
+ explicit PrintTagHandler(Response &_response) noexcept
+ :NullTagHandler(WANT_TAG), response(_response) {}
+
+ void OnTag(TagType type, const char *value) noexcept override {
+ if (response.GetClient().tag_mask.Test(type))
+ tag_print(response, type, value);
+ }
};
static CommandResult
handle_lsinfo_absolute(Response &r, const char *uri)
{
- if (!tag_stream_scan(uri, print_tag_handler, &r)) {
+ PrintTagHandler h(r);
+ if (!tag_stream_scan(uri, h)) {
r.Error(ACK_ERROR_NO_EXIST, "No such file");
return CommandResult::ERROR;
}
diff --git a/src/decoder/DecoderPlugin.hxx b/src/decoder/DecoderPlugin.hxx
index bf2f06376..d41086d8b 100644
--- a/src/decoder/DecoderPlugin.hxx
+++ b/src/decoder/DecoderPlugin.hxx
@@ -26,7 +26,7 @@
struct ConfigBlock;
class InputStream;
-struct TagHandler;
+class TagHandler;
class Path;
class DecoderClient;
class DetachedSong;
@@ -71,18 +71,14 @@ struct DecoderPlugin {
*
* @return false if the operation has failed
*/
- bool (*scan_file)(Path path_fs,
- const TagHandler &handler,
- void *handler_ctx) noexcept;
+ bool (*scan_file)(Path path_fs, TagHandler &handler) noexcept;
/**
* Scan metadata of a file.
*
* @return false if the operation has failed
*/
- bool (*scan_stream)(InputStream &is,
- const TagHandler &handler,
- void *handler_ctx) noexcept;
+ bool (*scan_stream)(InputStream &is, TagHandler &handler) noexcept;
/**
* @brief Return a "virtual" filename for subtracks in
@@ -139,20 +135,18 @@ struct DecoderPlugin {
* Read the tag of a file.
*/
template<typename P>
- bool ScanFile(P path_fs,
- const TagHandler &handler, void *handler_ctx) const noexcept {
+ bool ScanFile(P path_fs, TagHandler &handler) const noexcept {
return scan_file != nullptr
- ? scan_file(path_fs, handler, handler_ctx)
+ ? scan_file(path_fs, handler)
: false;
}
/**
* Read the tag of a stream.
*/
- bool ScanStream(InputStream &is,
- const TagHandler &handler, void *handler_ctx) const noexcept {
+ bool ScanStream(InputStream &is, TagHandler &handler) const noexcept {
return scan_stream != nullptr
- ? scan_stream(is, handler, handler_ctx)
+ ? scan_stream(is, handler)
: false;
}
diff --git a/src/decoder/plugins/AdPlugDecoderPlugin.cxx b/src/decoder/plugins/AdPlugDecoderPlugin.cxx
index d7646d9a4..ed411170c 100644
--- a/src/decoder/plugins/AdPlugDecoderPlugin.cxx
+++ b/src/decoder/plugins/AdPlugDecoderPlugin.cxx
@@ -83,16 +83,14 @@ adplug_file_decode(DecoderClient &client, Path path_fs)
static void
adplug_scan_tag(TagType type, const std::string &value,
- const TagHandler &handler, void *handler_ctx) noexcept
+ TagHandler &handler) noexcept
{
if (!value.empty())
- tag_handler_invoke_tag(handler, handler_ctx,
- type, value.c_str());
+ handler.OnTag(type, value.c_str());
}
static bool
-adplug_scan_file(Path path_fs,
- const TagHandler &handler, void *handler_ctx) noexcept
+adplug_scan_file(Path path_fs, TagHandler &handler) noexcept
{
CEmuopl opl(sample_rate, true, true);
opl.init();
@@ -101,16 +99,15 @@ adplug_scan_file(Path path_fs,
if (player == nullptr)
return false;
- tag_handler_invoke_duration(handler, handler_ctx,
- SongTime::FromMS(player->songlength()));
+ handler.OnDuration(SongTime::FromMS(player->songlength()));
- if (handler.tag != nullptr) {
+ if (handler.WantTag()) {
adplug_scan_tag(TAG_TITLE, player->gettitle(),
- handler, handler_ctx);
+ handler);
adplug_scan_tag(TAG_ARTIST, player->getauthor(),
- handler, handler_ctx);
+ handler);
adplug_scan_tag(TAG_COMMENT, player->getdesc(),
- handler, handler_ctx);
+ handler);
}
delete player;
diff --git a/src/decoder/plugins/AudiofileDecoderPlugin.cxx b/src/decoder/plugins/AudiofileDecoderPlugin.cxx
index 1d369d686..2204fa509 100644
--- a/src/decoder/plugins/AudiofileDecoderPlugin.cxx
+++ b/src/decoder/plugins/AudiofileDecoderPlugin.cxx
@@ -256,14 +256,13 @@ audiofile_get_duration(InputStream &is) noexcept
}
static bool
-audiofile_scan_stream(InputStream &is,
- const TagHandler &handler, void *handler_ctx) noexcept
+audiofile_scan_stream(InputStream &is, TagHandler &handler) noexcept
{
const auto duration = audiofile_get_duration(is);
if (duration.IsNegative())
return false;
- tag_handler_invoke_duration(handler, handler_ctx, SongTime(duration));
+ handler.OnDuration(SongTime(duration));
return true;
}
diff --git a/src/decoder/plugins/DsdLib.cxx b/src/decoder/plugins/DsdLib.cxx
index ce364398b..3108a1142 100644
--- a/src/decoder/plugins/DsdLib.cxx
+++ b/src/decoder/plugins/DsdLib.cxx
@@ -115,9 +115,8 @@ dsdlib_valid_freq(uint32_t samplefreq) noexcept
#ifdef ENABLE_ID3TAG
void
-dsdlib_tag_id3(InputStream &is,
- const TagHandler &handler,
- void *handler_ctx, offset_type tagoffset)
+dsdlib_tag_id3(InputStream &is, TagHandler &handler,
+ offset_type tagoffset)
{
if (tagoffset == 0 || !is.KnownSize())
return;
@@ -150,7 +149,7 @@ dsdlib_tag_id3(InputStream &is,
if (id3_tag == nullptr)
return;
- scan_id3_tag(id3_tag, handler, handler_ctx);
+ scan_id3_tag(id3_tag, handler);
id3_tag_delete(id3_tag);
return;
diff --git a/src/decoder/plugins/DsdLib.hxx b/src/decoder/plugins/DsdLib.hxx
index c1a059c55..06c61e500 100644
--- a/src/decoder/plugins/DsdLib.hxx
+++ b/src/decoder/plugins/DsdLib.hxx
@@ -26,7 +26,7 @@
#include <stdint.h>
-struct TagHandler;
+class TagHandler;
class DecoderClient;
class InputStream;
@@ -79,8 +79,7 @@ dsdlib_valid_freq(uint32_t samplefreq) noexcept;
* DSF and DSDIFF files are imported
*/
void
-dsdlib_tag_id3(InputStream &is,
- const TagHandler &handler,
- void *handler_ctx, offset_type tagoffset);
+dsdlib_tag_id3(InputStream &is, TagHandler &handler,
+ offset_type tagoffset);
#endif
diff --git a/src/decoder/plugins/DsdiffDecoderPlugin.cxx b/src/decoder/plugins/DsdiffDecoderPlugin.cxx
index b63bafd9a..eb8966530 100644
--- a/src/decoder/plugins/DsdiffDecoderPlugin.cxx
+++ b/src/decoder/plugins/DsdiffDecoderPlugin.cxx
@@ -186,8 +186,8 @@ dsdiff_read_prop(DecoderClient *client, InputStream &is,
static void
dsdiff_handle_native_tag(InputStream &is,
- const TagHandler &handler,
- void *handler_ctx, offset_type tagoffset,
+ TagHandler &handler,
+ offset_type tagoffset,
TagType type)
{
if (!dsdlib_skip_to(nullptr, is, tagoffset))
@@ -212,7 +212,7 @@ dsdiff_handle_native_tag(InputStream &is,
return;
string[length] = '\0';
- tag_handler_invoke_tag(handler, handler_ctx, type, label);
+ handler.OnTag(type, label);
return;
}
@@ -228,8 +228,7 @@ static bool
dsdiff_read_metadata_extra(DecoderClient *client, InputStream &is,
DsdiffMetaData *metadata,
DsdiffChunkHeader *chunk_header,
- const TagHandler &handler,
- void *handler_ctx)
+ TagHandler &handler)
{
/* skip from DSD data to next chunk header */
@@ -286,17 +285,17 @@ dsdiff_read_metadata_extra(DecoderClient *client, InputStream &is,
if (id3_offset != 0) {
/* a ID3 tag has preference over the other tags, do not process
other tags if we have one */
- dsdlib_tag_id3(is, handler, handler_ctx, id3_offset);
+ dsdlib_tag_id3(is, handler, id3_offset);
return true;
}
#endif
if (artist_offset != 0)
- dsdiff_handle_native_tag(is, handler, handler_ctx,
+ dsdiff_handle_native_tag(is, handler,
artist_offset, TAG_ARTIST);
if (title_offset != 0)
- dsdiff_handle_native_tag(is, handler, handler_ctx,
+ dsdiff_handle_native_tag(is, handler,
title_offset, TAG_TITLE);
return true;
}
@@ -449,9 +448,7 @@ dsdiff_stream_decode(DecoderClient &client, InputStream &is)
}
static bool
-dsdiff_scan_stream(InputStream &is,
- gcc_unused const TagHandler &handler,
- gcc_unused void *handler_ctx) noexcept
+dsdiff_scan_stream(InputStream &is, TagHandler &handler) noexcept
{
DsdiffMetaData metadata;
DsdiffChunkHeader chunk_header;
@@ -469,11 +466,11 @@ dsdiff_scan_stream(InputStream &is,
uint64_t n_frames = metadata.chunk_size / metadata.channels;
auto songtime = SongTime::FromScale<uint64_t>(n_frames,
sample_rate);
- tag_handler_invoke_duration(handler, handler_ctx, songtime);
+ handler.OnDuration(songtime);
/* Read additional metadata and created tags if available */
dsdiff_read_metadata_extra(nullptr, is, &metadata, &chunk_header,
- handler, handler_ctx);
+ handler);
return true;
}
diff --git a/src/decoder/plugins/DsfDecoderPlugin.cxx b/src/decoder/plugins/DsfDecoderPlugin.cxx
index e49ca479d..70c1c3901 100644
--- a/src/decoder/plugins/DsfDecoderPlugin.cxx
+++ b/src/decoder/plugins/DsfDecoderPlugin.cxx
@@ -325,9 +325,7 @@ dsf_stream_decode(DecoderClient &client, InputStream &is)
}
static bool
-dsf_scan_stream(InputStream &is,
- gcc_unused const TagHandler &handler,
- gcc_unused void *handler_ctx) noexcept
+dsf_scan_stream(InputStream &is, TagHandler &handler) noexcept
{
/* check DSF metadata */
DsfMetaData metadata;
@@ -342,11 +340,11 @@ dsf_scan_stream(InputStream &is,
const auto n_blocks = metadata.n_blocks;
auto songtime = SongTime::FromScale<uint64_t>(n_blocks * DSF_BLOCK_SIZE,
sample_rate);
- tag_handler_invoke_duration(handler, handler_ctx, songtime);
+ handler.OnDuration(songtime);
#ifdef ENABLE_ID3TAG
/* Add available tags from the ID3 tag */
- dsdlib_tag_id3(is, handler, handler_ctx, metadata.id3_offset);
+ dsdlib_tag_id3(is, handler, metadata.id3_offset);
#endif
return true;
}
diff --git a/src/decoder/plugins/FaadDecoderPlugin.cxx b/src/decoder/plugins/FaadDecoderPlugin.cxx
index 92fecf728..7fc56b6a0 100644
--- a/src/decoder/plugins/FaadDecoderPlugin.cxx
+++ b/src/decoder/plugins/FaadDecoderPlugin.cxx
@@ -414,16 +414,14 @@ faad_stream_decode(DecoderClient &client, InputStream &is)
}
static bool
-faad_scan_stream(InputStream &is,
- const TagHandler &handler, void *handler_ctx) noexcept
+faad_scan_stream(InputStream &is, TagHandler &handler) noexcept
{
auto result = faad_get_file_time(is);
if (!result.first)
return false;
if (!result.second.IsNegative())
- tag_handler_invoke_duration(handler, handler_ctx,
- SongTime(result.second));
+ handler.OnDuration(SongTime(result.second));
return true;
}
diff --git a/src/decoder/plugins/FfmpegDecoderPlugin.cxx b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
index 230e7979e..fd643a356 100644
--- a/src/decoder/plugins/FfmpegDecoderPlugin.cxx
+++ b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
@@ -572,21 +572,20 @@ FfmpegParseMetaData(DecoderClient &client,
}
static void
-FfmpegScanMetadata(const AVStream &stream,
- const TagHandler &handler, void *handler_ctx)
+FfmpegScanMetadata(const AVStream &stream, TagHandler &handler) noexcept
{
- FfmpegScanDictionary(stream.metadata, handler, handler_ctx);
+ FfmpegScanDictionary(stream.metadata, handler);
}
static void
FfmpegScanMetadata(const AVFormatContext &format_context, int audio_stream,
- const TagHandler &handler, void *handler_ctx)
+ TagHandler &handler) noexcept
{
assert(audio_stream >= 0);
- FfmpegScanDictionary(format_context.metadata, handler, handler_ctx);
+ FfmpegScanDictionary(format_context.metadata, handler);
FfmpegScanMetadata(*format_context.streams[audio_stream],
- handler, handler_ctx);
+ handler);
}
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(56, 1, 0)
@@ -595,8 +594,8 @@ static void
FfmpegScanTag(const AVFormatContext &format_context, int audio_stream,
TagBuilder &tag)
{
- FfmpegScanMetadata(format_context, audio_stream,
- full_tag_handler, &tag);
+ FullTagHandler h(tag);
+ FfmpegScanMetadata(format_context, audio_stream, h);
}
/**
@@ -828,7 +827,7 @@ ffmpeg_decode(DecoderClient &client, InputStream &input)
static bool
FfmpegScanStream(AVFormatContext &format_context,
- const TagHandler &handler, void *handler_ctx)
+ TagHandler &handler) noexcept
{
const int find_result =
avformat_find_stream_info(&format_context, nullptr);
@@ -841,22 +840,19 @@ FfmpegScanStream(AVFormatContext &format_context,
const AVStream &stream = *format_context.streams[audio_stream];
if (stream.duration != (int64_t)AV_NOPTS_VALUE)
- tag_handler_invoke_duration(handler, handler_ctx,
- FromFfmpegTime(stream.duration,
- stream.time_base));
+ handler.OnDuration(FromFfmpegTime(stream.duration,
+ stream.time_base));
else if (format_context.duration != (int64_t)AV_NOPTS_VALUE)
- tag_handler_invoke_duration(handler, handler_ctx,
- FromFfmpegTime(format_context.duration,
- AV_TIME_BASE_Q));
+ handler.OnDuration(FromFfmpegTime(format_context.duration,
+ AV_TIME_BASE_Q));
- FfmpegScanMetadata(format_context, audio_stream, handler, handler_ctx);
+ FfmpegScanMetadata(format_context, audio_stream, handler);
return true;
}
static bool
-ffmpeg_scan_stream(InputStream &is,
- const TagHandler &handler, void *handler_ctx) noexcept
+ffmpeg_scan_stream(InputStream &is, TagHandler &handler) noexcept
{
AVInputFormat *input_format = ffmpeg_probe(nullptr, is);
if (input_format == nullptr)
@@ -877,7 +873,7 @@ ffmpeg_scan_stream(InputStream &is,
avformat_close_input(&f);
};
- return FfmpegScanStream(*f, handler, handler_ctx);
+ return FfmpegScanStream(*f, handler);
}
/**
diff --git a/src/decoder/plugins/FfmpegMetaData.cxx b/src/decoder/plugins/FfmpegMetaData.cxx
index 07be3cad3..d37086e28 100644
--- a/src/decoder/plugins/FfmpegMetaData.cxx
+++ b/src/decoder/plugins/FfmpegMetaData.cxx
@@ -43,46 +43,42 @@ static constexpr struct tag_table ffmpeg_tags[] = {
static void
FfmpegScanTag(TagType type,
AVDictionary *m, const char *name,
- const TagHandler &handler, void *handler_ctx)
+ TagHandler &handler) noexcept
{
AVDictionaryEntry *mt = nullptr;
while ((mt = av_dict_get(m, name, mt, 0)) != nullptr)
- tag_handler_invoke_tag(handler, handler_ctx,
- type, mt->value);
+ handler.OnTag(type, mt->value);
}
static void
-FfmpegScanPairs(AVDictionary *dict,
- const TagHandler &handler, void *handler_ctx)
+FfmpegScanPairs(AVDictionary *dict, TagHandler &handler) noexcept
{
AVDictionaryEntry *i = nullptr;
while ((i = av_dict_get(dict, "", i, AV_DICT_IGNORE_SUFFIX)) != nullptr)
- tag_handler_invoke_pair(handler, handler_ctx,
- i->key, i->value);
+ handler.OnPair(i->key, i->value);
}
void
-FfmpegScanDictionary(AVDictionary *dict,
- const TagHandler &handler, void *handler_ctx)
+FfmpegScanDictionary(AVDictionary *dict, TagHandler &handler) noexcept
{
- if (handler.tag != nullptr) {
+ if (handler.WantTag()) {
for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i)
FfmpegScanTag(TagType(i), dict, tag_item_names[i],
- handler, handler_ctx);
+ handler);
for (const struct tag_table *i = ffmpeg_tags;
i->name != nullptr; ++i)
FfmpegScanTag(i->type, dict, i->name,
- handler, handler_ctx);
+ handler);
for (const struct tag_table *i = musicbrainz_txxx_tags;
i->name != nullptr; ++i)
FfmpegScanTag(i->type, dict, i->name,
- handler, handler_ctx);
+ handler);
}
- if (handler.pair != nullptr)
- FfmpegScanPairs(dict, handler, handler_ctx);
+ if (handler.WantPair())
+ FfmpegScanPairs(dict, handler);
}
diff --git a/src/decoder/plugins/FfmpegMetaData.hxx b/src/decoder/plugins/FfmpegMetaData.hxx
index f736a3673..418da47f4 100644
--- a/src/decoder/plugins/FfmpegMetaData.hxx
+++ b/src/decoder/plugins/FfmpegMetaData.hxx
@@ -21,10 +21,9 @@
#define MPD_FFMPEG_METADATA_HXX
struct AVDictionary;
-struct TagHandler;
+class TagHandler;
void
-FfmpegScanDictionary(AVDictionary *dict,
- const TagHandler &handler, void *handler_ctx);
+FfmpegScanDictionary(AVDictionary *dict, TagHandler &handler) noexcept;
#endif
diff --git a/src/decoder/plugins/FlacDecoderPlugin.cxx b/src/decoder/plugins/FlacDecoderPlugin.cxx
index 012d28f92..ecbbe131c 100644
--- a/src/decoder/plugins/FlacDecoderPlugin.cxx
+++ b/src/decoder/plugins/FlacDecoderPlugin.cxx
@@ -69,8 +69,7 @@ flac_write_cb(const FLAC__StreamDecoder *dec, const FLAC__Frame *frame,
}
static bool
-flac_scan_file(Path path_fs,
- const TagHandler &handler, void *handler_ctx) noexcept
+flac_scan_file(Path path_fs, TagHandler &handler) noexcept
{
FlacMetadataChain chain;
if (!chain.Read(NarrowPath(path_fs))) {
@@ -80,13 +79,12 @@ flac_scan_file(Path path_fs,
return false;
}
- chain.Scan(handler, handler_ctx);
+ chain.Scan(handler);
return true;
}
static bool
-flac_scan_stream(InputStream &is,
- const TagHandler &handler, void *handler_ctx) noexcept
+flac_scan_stream(InputStream &is, TagHandler &handler) noexcept
{
FlacMetadataChain chain;
if (!chain.Read(is)) {
@@ -96,7 +94,7 @@ flac_scan_stream(InputStream &is,
return false;
}
- chain.Scan(handler, handler_ctx);
+ chain.Scan(handler);
return true;
}
@@ -315,8 +313,7 @@ oggflac_init(gcc_unused const ConfigBlock &block)
}
static bool
-oggflac_scan_file(Path path_fs,
- const TagHandler &handler, void *handler_ctx) noexcept
+oggflac_scan_file(Path path_fs, TagHandler &handler) noexcept
{
FlacMetadataChain chain;
if (!chain.ReadOgg(NarrowPath(path_fs))) {
@@ -326,13 +323,12 @@ oggflac_scan_file(Path path_fs,
return false;
}
- chain.Scan(handler, handler_ctx);
+ chain.Scan(handler);
return true;
}
static bool
-oggflac_scan_stream(InputStream &is,
- const TagHandler &handler, void *handler_ctx) noexcept
+oggflac_scan_stream(InputStream &is, TagHandler &handler) noexcept
{
FlacMetadataChain chain;
if (!chain.ReadOgg(is)) {
@@ -342,7 +338,7 @@ oggflac_scan_stream(InputStream &is,
return false;
}
- chain.Scan(handler, handler_ctx);
+ chain.Scan(handler);
return true;
}
diff --git a/src/decoder/plugins/FlacMetadata.cxx b/src/decoder/plugins/FlacMetadata.cxx
index ee4053b26..a4150f6ef 100644
--- a/src/decoder/plugins/FlacMetadata.cxx
+++ b/src/decoder/plugins/FlacMetadata.cxx
@@ -79,11 +79,11 @@ flac_comment_value(const FLAC__StreamMetadata_VorbisComment_Entry *entry,
static bool
flac_copy_comment(const FLAC__StreamMetadata_VorbisComment_Entry *entry,
const char *name, TagType tag_type,
- const TagHandler &handler, void *handler_ctx)
+ TagHandler &handler) noexcept
{
const char *value = flac_comment_value(entry, name);
if (value != nullptr) {
- tag_handler_invoke_tag(handler, handler_ctx, tag_type, value);
+ handler.OnTag(tag_type, value);
return true;
}
@@ -92,36 +92,33 @@ flac_copy_comment(const FLAC__StreamMetadata_VorbisComment_Entry *entry,
static void
flac_scan_comment(const FLAC__StreamMetadata_VorbisComment_Entry *entry,
- const TagHandler &handler, void *handler_ctx)
+ TagHandler &handler) noexcept
{
- if (handler.pair != nullptr) {
+ if (handler.WantPair()) {
const char *comment = (const char *)entry->entry;
const DivideString split(comment, '=');
if (split.IsDefined() && !split.empty())
- tag_handler_invoke_pair(handler, handler_ctx,
- split.GetFirst(),
- split.GetSecond());
+ handler.OnPair(split.GetFirst(), split.GetSecond());
}
for (const struct tag_table *i = xiph_tags; i->name != nullptr; ++i)
- if (flac_copy_comment(entry, i->name, i->type,
- handler, handler_ctx))
+ if (flac_copy_comment(entry, i->name, i->type, handler))
return;
for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i)
if (flac_copy_comment(entry,
tag_item_names[i], (TagType)i,
- handler, handler_ctx))
+ handler))
return;
}
static void
flac_scan_comments(const FLAC__StreamMetadata_VorbisComment *comment,
- const TagHandler &handler, void *handler_ctx)
+ TagHandler &handler) noexcept
{
for (unsigned i = 0; i < comment->num_comments; ++i)
flac_scan_comment(&comment->comments[i],
- handler, handler_ctx);
+ handler);
}
gcc_pure
@@ -136,18 +133,17 @@ flac_duration(const FLAC__StreamMetadata_StreamInfo *stream_info) noexcept
void
flac_scan_metadata(const FLAC__StreamMetadata *block,
- const TagHandler &handler, void *handler_ctx)
+ TagHandler &handler) noexcept
{
switch (block->type) {
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
flac_scan_comments(&block->data.vorbis_comment,
- handler, handler_ctx);
+ handler);
break;
case FLAC__METADATA_TYPE_STREAMINFO:
if (block->data.stream_info.sample_rate > 0)
- tag_handler_invoke_duration(handler, handler_ctx,
- flac_duration(&block->data.stream_info));
+ handler.OnDuration(flac_duration(&block->data.stream_info));
break;
default:
@@ -159,12 +155,13 @@ Tag
flac_vorbis_comments_to_tag(const FLAC__StreamMetadata_VorbisComment *comment)
{
TagBuilder tag_builder;
- flac_scan_comments(comment, add_tag_handler, &tag_builder);
+ AddTagHandler h(tag_builder);
+ flac_scan_comments(comment, h);
return tag_builder.Commit();
}
void
-FlacMetadataChain::Scan(const TagHandler &handler, void *handler_ctx)
+FlacMetadataChain::Scan(TagHandler &handler) noexcept
{
FLACMetadataIterator iterator(*this);
@@ -173,6 +170,6 @@ FlacMetadataChain::Scan(const TagHandler &handler, void *handler_ctx)
if (block == nullptr)
break;
- flac_scan_metadata(block, handler, handler_ctx);
+ flac_scan_metadata(block, handler);
} while (iterator.Next());
}
diff --git a/src/decoder/plugins/FlacMetadata.hxx b/src/decoder/plugins/FlacMetadata.hxx
index d0ee8c824..02a5f1f6b 100644
--- a/src/decoder/plugins/FlacMetadata.hxx
+++ b/src/decoder/plugins/FlacMetadata.hxx
@@ -25,7 +25,7 @@
#include <FLAC/metadata.h>
-struct TagHandler;
+class TagHandler;
class MixRampInfo;
class FlacMetadataChain {
@@ -82,7 +82,7 @@ public:
return FLAC__Metadata_ChainStatusString[GetStatus()];
}
- void Scan(const TagHandler &handler, void *handler_ctx);
+ void Scan(TagHandler &handler) noexcept;
};
class FLACMetadataIterator {
@@ -126,6 +126,6 @@ flac_vorbis_comments_to_tag(const FLAC__StreamMetadata_VorbisComment *comment);
void
flac_scan_metadata(const FLAC__StreamMetadata *block,
- const TagHandler &handler, void *handler_ctx);
+ TagHandler &handler) noexcept;
#endif
diff --git a/src/decoder/plugins/FluidsynthDecoderPlugin.cxx b/src/decoder/plugins/FluidsynthDecoderPlugin.cxx
index a1161e000..0f106d5a4 100644
--- a/src/decoder/plugins/FluidsynthDecoderPlugin.cxx
+++ b/src/decoder/plugins/FluidsynthDecoderPlugin.cxx
@@ -193,8 +193,7 @@ fluidsynth_file_decode(DecoderClient &client, Path path_fs)
static bool
fluidsynth_scan_file(Path path_fs,
- gcc_unused const TagHandler &handler,
- gcc_unused void *handler_ctx) noexcept
+ gcc_unused TagHandler &handler) noexcept
{
return fluid_is_midifile(path_fs.c_str());
}
diff --git a/src/decoder/plugins/GmeDecoderPlugin.cxx b/src/decoder/plugins/GmeDecoderPlugin.cxx
index 4708afb3a..4cd931274 100644
--- a/src/decoder/plugins/GmeDecoderPlugin.cxx
+++ b/src/decoder/plugins/GmeDecoderPlugin.cxx
@@ -215,15 +215,13 @@ gme_file_decode(DecoderClient &client, Path path_fs)
static void
ScanGmeInfo(const gme_info_t &info, unsigned song_num, int track_count,
- const TagHandler &handler, void *handler_ctx)
+ TagHandler &handler) noexcept
{
if (info.play_length > 0)
- tag_handler_invoke_duration(handler, handler_ctx,
- SongTime::FromMS(info.play_length));
+ handler.OnDuration(SongTime::FromMS(info.play_length));
if (track_count > 1)
- tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK,
- StringFormat<16>("%u", song_num + 1));
+ handler.OnTag(TAG_TRACK, StringFormat<16>("%u", song_num + 1));
if (info.song != nullptr) {
if (track_count > 1) {
@@ -232,33 +230,26 @@ ScanGmeInfo(const gme_info_t &info, unsigned song_num, int track_count,
StringFormat<1024>("%s (%u/%d)",
info.song, song_num + 1,
track_count);
- tag_handler_invoke_tag(handler, handler_ctx,
- TAG_TITLE, tag_title);
+ handler.OnTag(TAG_TITLE, tag_title);
} else
- tag_handler_invoke_tag(handler, handler_ctx,
- TAG_TITLE, info.song);
+ handler.OnTag(TAG_TITLE, info.song);
}
if (info.author != nullptr)
- tag_handler_invoke_tag(handler, handler_ctx,
- TAG_ARTIST, info.author);
+ handler.OnTag(TAG_ARTIST, info.author);
if (info.game != nullptr)
- tag_handler_invoke_tag(handler, handler_ctx,
- TAG_ALBUM, info.game);
+ handler.OnTag(TAG_ALBUM, info.game);
if (info.comment != nullptr)
- tag_handler_invoke_tag(handler, handler_ctx,
- TAG_COMMENT, info.comment);
+ handler.OnTag(TAG_COMMENT, info.comment);
if (info.copyright != nullptr)
- tag_handler_invoke_tag(handler, handler_ctx,
- TAG_DATE, info.copyright);
+ handler.OnTag(TAG_DATE, info.copyright);
}
static bool
-ScanMusicEmu(Music_Emu *emu, unsigned song_num,
- const TagHandler &handler, void *handler_ctx)
+ScanMusicEmu(Music_Emu *emu, unsigned song_num, TagHandler &handler) noexcept
{
gme_info_t *ti;
const char *gme_err = gme_track_info(emu, &ti, song_num);
@@ -271,14 +262,12 @@ ScanMusicEmu(Music_Emu *emu, unsigned song_num,
AtScopeExit(ti) { gme_free_info(ti); };
- ScanGmeInfo(*ti, song_num, gme_track_count(emu),
- handler, handler_ctx);
+ ScanGmeInfo(*ti, song_num, gme_track_count(emu), handler);
return true;
}
static bool
-gme_scan_file(Path path_fs,
- const TagHandler &handler, void *handler_ctx) noexcept
+gme_scan_file(Path path_fs, TagHandler &handler) noexcept
{
const auto container = ParseContainerPath(path_fs);
@@ -289,7 +278,7 @@ gme_scan_file(Path path_fs,
AtScopeExit(emu) { gme_delete(emu); };
- return ScanMusicEmu(emu, container.track, handler, handler_ctx);
+ return ScanMusicEmu(emu, container.track, handler);
}
static std::forward_list<DetachedSong>
@@ -316,8 +305,8 @@ gme_container_scan(Path path_fs)
auto tail = list.before_begin();
for (unsigned i = 0; i < num_songs; ++i) {
- ScanMusicEmu(emu, i,
- add_tag_handler, &tag_builder);
+ AddTagHandler h(tag_builder);
+ ScanMusicEmu(emu, i, h);
const auto track_name =
StringFormat<64>(SUBTUNE_PREFIX "%03u.%s", i+1,
diff --git a/src/decoder/plugins/MadDecoderPlugin.cxx b/src/decoder/plugins/MadDecoderPlugin.cxx
index ddfd12e47..c8dd1fe38 100644
--- a/src/decoder/plugins/MadDecoderPlugin.cxx
+++ b/src/decoder/plugins/MadDecoderPlugin.cxx
@@ -1062,16 +1062,14 @@ mp3_decode(DecoderClient &client, InputStream &input_stream)
}
static bool
-mad_decoder_scan_stream(InputStream &is,
- const TagHandler &handler, void *handler_ctx) noexcept
+mad_decoder_scan_stream(InputStream &is, TagHandler &handler) noexcept
{
const auto result = mad_decoder_total_file_time(is);
if (!result.first)
return false;
if (!result.second.IsNegative())
- tag_handler_invoke_duration(handler, handler_ctx,
- SongTime(result.second));
+ handler.OnDuration(SongTime(result.second));
return true;
}
diff --git a/src/decoder/plugins/MikmodDecoderPlugin.cxx b/src/decoder/plugins/MikmodDecoderPlugin.cxx
index f3e852501..bdea1e920 100644
--- a/src/decoder/plugins/MikmodDecoderPlugin.cxx
+++ b/src/decoder/plugins/MikmodDecoderPlugin.cxx
@@ -185,8 +185,7 @@ mikmod_decoder_file_decode(DecoderClient &client, Path path_fs)
}
static bool
-mikmod_decoder_scan_file(Path path_fs,
- const TagHandler &handler, void *handler_ctx) noexcept
+mikmod_decoder_scan_file(Path path_fs, TagHandler &handler) noexcept
{
/* deconstify the path because libmikmod wants a non-const
string pointer */
@@ -204,8 +203,7 @@ mikmod_decoder_scan_file(Path path_fs,
char *title = Player_LoadTitle(path2);
if (title != nullptr) {
- tag_handler_invoke_tag(handler, handler_ctx,
- TAG_TITLE, title);
+ handler.OnTag(TAG_TITLE, title);
#if (LIBMIKMOD_VERSION >= 0x030200)
MikMod_free(title);
#else
diff --git a/src/decoder/plugins/ModplugDecoderPlugin.cxx b/src/decoder/plugins/ModplugDecoderPlugin.cxx
index b75816fd3..069ee0258 100644
--- a/src/decoder/plugins/ModplugDecoderPlugin.cxx
+++ b/src/decoder/plugins/ModplugDecoderPlugin.cxx
@@ -175,20 +175,17 @@ mod_decode(DecoderClient &client, InputStream &is)
}
static bool
-modplug_scan_stream(InputStream &is,
- const TagHandler &handler, void *handler_ctx) noexcept
+modplug_scan_stream(InputStream &is, TagHandler &handler) noexcept
{
ModPlugFile *f = LoadModPlugFile(nullptr, is);
if (f == nullptr)
return false;
- tag_handler_invoke_duration(handler, handler_ctx,
- SongTime::FromMS(ModPlug_GetLength(f)));
+ handler.OnDuration(SongTime::FromMS(ModPlug_GetLength(f)));
const char *title = ModPlug_GetName(f);
if (title != nullptr)
- tag_handler_invoke_tag(handler, handler_ctx,
- TAG_TITLE, title);
+ handler.OnTag(TAG_TITLE, title);
ModPlug_Unload(f);
diff --git a/src/decoder/plugins/MpcdecDecoderPlugin.cxx b/src/decoder/plugins/MpcdecDecoderPlugin.cxx
index 39483ec82..b83e2bfff 100644
--- a/src/decoder/plugins/MpcdecDecoderPlugin.cxx
+++ b/src/decoder/plugins/MpcdecDecoderPlugin.cxx
@@ -257,14 +257,13 @@ mpcdec_get_file_duration(InputStream &is)
}
static bool
-mpcdec_scan_stream(InputStream &is,
- const TagHandler &handler, void *handler_ctx) noexcept
+mpcdec_scan_stream(InputStream &is, TagHandler &handler) noexcept
{
const auto duration = mpcdec_get_file_duration(is);
if (duration.IsNegative())
return false;
- tag_handler_invoke_duration(handler, handler_ctx, SongTime(duration));
+ handler.OnDuration(SongTime(duration));
return true;
}
diff --git a/src/decoder/plugins/Mpg123DecoderPlugin.cxx b/src/decoder/plugins/Mpg123DecoderPlugin.cxx
index 0834f5fee..d817710a2 100644
--- a/src/decoder/plugins/Mpg123DecoderPlugin.cxx
+++ b/src/decoder/plugins/Mpg123DecoderPlugin.cxx
@@ -279,8 +279,7 @@ mpd_mpg123_file_decode(DecoderClient &client, Path path_fs)
}
static bool
-mpd_mpg123_scan_file(Path path_fs,
- const TagHandler &handler, void *handler_ctx) noexcept
+mpd_mpg123_scan_file(Path path_fs, TagHandler &handler) noexcept
{
int error;
mpg123_handle *const handle = mpg123_new(nullptr, &error);
@@ -316,7 +315,7 @@ mpd_mpg123_scan_file(Path path_fs,
SongTime::FromScale<uint64_t>(num_samples,
audio_format.sample_rate);
- tag_handler_invoke_duration(handler, handler_ctx, duration);
+ handler.OnDuration(duration);
return true;
}
diff --git a/src/decoder/plugins/OpusDecoderPlugin.cxx b/src/decoder/plugins/OpusDecoderPlugin.cxx
index 3b4ef1489..c629a18b3 100644
--- a/src/decoder/plugins/OpusDecoderPlugin.cxx
+++ b/src/decoder/plugins/OpusDecoderPlugin.cxx
@@ -207,10 +207,9 @@ MPDOpusDecoder::HandleTags(const ogg_packet &packet)
rgi.Clear();
TagBuilder tag_builder;
+ AddTagHandler h(tag_builder);
- if (ScanOpusTags(packet.packet, packet.bytes,
- &rgi,
- add_tag_handler, &tag_builder) &&
+ if (ScanOpusTags(packet.packet, packet.bytes, &rgi, h) &&
!tag_builder.empty()) {
client.SubmitReplayGain(&rgi);
@@ -314,7 +313,7 @@ ReadAndParseOpusHead(OggSyncState &sync, OggStreamState &stream,
static bool
ReadAndVisitOpusTags(OggSyncState &sync, OggStreamState &stream,
- const TagHandler &handler, void *handler_ctx)
+ TagHandler &handler)
{
ogg_packet packet;
@@ -322,12 +321,12 @@ ReadAndVisitOpusTags(OggSyncState &sync, OggStreamState &stream,
IsOpusTags(packet) &&
ScanOpusTags(packet.packet, packet.bytes,
nullptr,
- handler, handler_ctx);
+ handler);
}
static void
VisitOpusDuration(InputStream &is, OggSyncState &sync, OggStreamState &stream,
- const TagHandler &handler, void *handler_ctx)
+ TagHandler &handler)
{
ogg_packet packet;
@@ -335,13 +334,12 @@ VisitOpusDuration(InputStream &is, OggSyncState &sync, OggStreamState &stream,
const auto duration =
SongTime::FromScale<uint64_t>(packet.granulepos,
opus_sample_rate);
- tag_handler_invoke_duration(handler, handler_ctx, duration);
+ handler.OnDuration(duration);
}
}
static bool
-mpd_opus_scan_stream(InputStream &is,
- const TagHandler &handler, void *handler_ctx) noexcept
+mpd_opus_scan_stream(InputStream &is, TagHandler &handler) noexcept
{
InputStreamReader reader(is);
OggSyncState oy(reader);
@@ -354,10 +352,10 @@ mpd_opus_scan_stream(InputStream &is,
unsigned channels;
if (!ReadAndParseOpusHead(oy, os, channels) ||
- !ReadAndVisitOpusTags(oy, os, handler, handler_ctx))
+ !ReadAndVisitOpusTags(oy, os, handler))
return false;
- VisitOpusDuration(is, oy, os, handler, handler_ctx);
+ VisitOpusDuration(is, oy, os, handler);
return true;
}
diff --git a/src/decoder/plugins/OpusTags.cxx b/src/decoder/plugins/OpusTags.cxx
index fe3aff304..7f99077bd 100644
--- a/src/decoder/plugins/OpusTags.cxx
+++ b/src/decoder/plugins/OpusTags.cxx
@@ -43,7 +43,7 @@ ParseOpusTagName(const char *name) noexcept
static void
ScanOneOpusTag(const char *name, const char *value,
ReplayGainInfo *rgi,
- const TagHandler &handler, void *ctx)
+ TagHandler &handler) noexcept
{
if (rgi != nullptr && strcmp(name, "R128_TRACK_GAIN") == 0) {
/* R128_TRACK_GAIN is a Q7.8 fixed point number in
@@ -63,25 +63,25 @@ ScanOneOpusTag(const char *name, const char *value,
rgi->album.gain = double(l) / 256.;
}
- tag_handler_invoke_pair(handler, ctx, name, value);
+ handler.OnPair(name, value);
- if (handler.tag != nullptr) {
+ if (handler.WantTag()) {
TagType t = ParseOpusTagName(name);
if (t != TAG_NUM_OF_ITEM_TYPES)
- tag_handler_invoke_tag(handler, ctx, t, value);
+ handler.OnTag(t, value);
}
}
bool
ScanOpusTags(const void *data, size_t size,
ReplayGainInfo *rgi,
- const TagHandler &handler, void *ctx)
+ TagHandler &handler) noexcept
{
OpusReader r(data, size);
if (!r.Expect("OpusTags", 8))
return false;
- if (handler.pair == nullptr && handler.tag == nullptr)
+ if (!handler.WantPair() && !handler.WantTag())
return true;
if (!r.SkipString())
@@ -100,7 +100,7 @@ ScanOpusTags(const void *data, size_t size,
if (eq != nullptr && eq > p) {
*eq = 0;
- ScanOneOpusTag(p, eq + 1, rgi, handler, ctx);
+ ScanOneOpusTag(p, eq + 1, rgi, handler);
}
delete[] p;
diff --git a/src/decoder/plugins/OpusTags.hxx b/src/decoder/plugins/OpusTags.hxx
index 923aeb9c0..2076de39d 100644
--- a/src/decoder/plugins/OpusTags.hxx
+++ b/src/decoder/plugins/OpusTags.hxx
@@ -25,11 +25,11 @@
#include <stddef.h>
struct ReplayGainInfo;
-struct TagHandler;
+class TagHandler;
bool
ScanOpusTags(const void *data, size_t size,
ReplayGainInfo *rgi,
- const TagHandler &handler, void *ctx);
+ TagHandler &handler) noexcept;
#endif
diff --git a/src/decoder/plugins/SidplayDecoderPlugin.cxx b/src/decoder/plugins/SidplayDecoderPlugin.cxx
index f93de4bfb..ac29f4fc8 100644
--- a/src/decoder/plugins/SidplayDecoderPlugin.cxx
+++ b/src/decoder/plugins/SidplayDecoderPlugin.cxx
@@ -405,7 +405,7 @@ GetInfoString(const SidTuneInfo &info, unsigned i) noexcept
static void
ScanSidTuneInfo(const SidTuneInfo &info, unsigned track, unsigned n_tracks,
- const TagHandler &handler, void *handler_ctx)
+ TagHandler &handler) noexcept
{
/* title */
const char *title = GetInfoString(info, 0);
@@ -416,31 +416,26 @@ ScanSidTuneInfo(const SidTuneInfo &info, unsigned track, unsigned n_tracks,
const auto tag_title =
StringFormat<1024>("%s (%u/%u)",
title, track, n_tracks);
- tag_handler_invoke_tag(handler, handler_ctx,
- TAG_TITLE, tag_title);
+ handler.OnTag(TAG_TITLE, tag_title);
} else
- tag_handler_invoke_tag(handler, handler_ctx, TAG_TITLE, title);
+ handler.OnTag(TAG_TITLE, title);
/* artist */
const char *artist = GetInfoString(info, 1);
if (artist != nullptr)
- tag_handler_invoke_tag(handler, handler_ctx, TAG_ARTIST,
- artist);
+ handler.OnTag(TAG_ARTIST, artist);
/* date */
const char *date = GetInfoString(info, 2);
if (date != nullptr)
- tag_handler_invoke_tag(handler, handler_ctx, TAG_DATE,
- date);
+ handler.OnTag(TAG_DATE, date);
/* track */
- tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK,
- StringFormat<16>("%u", track));
+ handler.OnTag(TAG_TRACK, StringFormat<16>("%u", track));
}
static bool
-sidplay_scan_file(Path path_fs,
- const TagHandler &handler, void *handler_ctx) noexcept
+sidplay_scan_file(Path path_fs, TagHandler &handler) noexcept
{
const auto container = ParseContainerPath(path_fs);
const unsigned song_num = container.track;
@@ -463,13 +458,12 @@ sidplay_scan_file(Path path_fs,
const unsigned n_tracks = info.songs;
#endif
- ScanSidTuneInfo(info, song_num, n_tracks, handler, handler_ctx);
+ ScanSidTuneInfo(info, song_num, n_tracks, handler);
/* time */
const auto duration = get_song_length(tune);
if (!duration.IsNegative())
- tag_handler_invoke_duration(handler, handler_ctx,
- SongTime(duration));
+ handler.OnDuration(SongTime(duration));
return true;
}
@@ -506,8 +500,8 @@ sidplay_container_scan(Path path_fs)
for (unsigned i = 1; i <= n_tracks; ++i) {
tune.selectSong(i);
- ScanSidTuneInfo(info, i, n_tracks,
- add_tag_handler, &tag_builder);
+ AddTagHandler h(tag_builder);
+ ScanSidTuneInfo(info, i, n_tracks, h);
char track_name[32];
/* Construct container/tune path names, eg.
diff --git a/src/decoder/plugins/SndfileDecoderPlugin.cxx b/src/decoder/plugins/SndfileDecoderPlugin.cxx
index a71a0e5bd..5506bc4c3 100644
--- a/src/decoder/plugins/SndfileDecoderPlugin.cxx
+++ b/src/decoder/plugins/SndfileDecoderPlugin.cxx
@@ -240,11 +240,11 @@ sndfile_stream_decode(DecoderClient &client, InputStream &is)
static void
sndfile_handle_tag(SNDFILE *sf, int str, TagType tag,
- const TagHandler &handler, void *handler_ctx)
+ TagHandler &handler) noexcept
{
const char *value = sf_get_string(sf, str);
if (value != nullptr)
- tag_handler_invoke_tag(handler, handler_ctx, tag, value);
+ handler.OnTag(tag, value);
}
static constexpr struct {
@@ -261,8 +261,7 @@ static constexpr struct {
};
static bool
-sndfile_scan_stream(InputStream &is,
- const TagHandler &handler, void *handler_ctx) noexcept
+sndfile_scan_stream(InputStream &is, TagHandler &handler) noexcept
{
SF_INFO info;
@@ -280,11 +279,10 @@ sndfile_scan_stream(InputStream &is,
return false;
}
- tag_handler_invoke_duration(handler, handler_ctx,
- sndfile_duration(info));
+ handler.OnDuration(sndfile_duration(info));
for (auto i : sndfile_tags)
- sndfile_handle_tag(sf, i.str, i.tag, handler, handler_ctx);
+ sndfile_handle_tag(sf, i.str, i.tag, handler);
sf_close(sf);
diff --git a/src/decoder/plugins/VorbisDecoderPlugin.cxx b/src/decoder/plugins/VorbisDecoderPlugin.cxx
index d67e2b4e4..bd4de5a55 100644
--- a/src/decoder/plugins/VorbisDecoderPlugin.cxx
+++ b/src/decoder/plugins/VorbisDecoderPlugin.cxx
@@ -348,7 +348,7 @@ static void
VisitVorbisDuration(InputStream &is,
OggSyncState &sync, OggStreamState &stream,
unsigned sample_rate,
- const TagHandler &handler, void *handler_ctx)
+ TagHandler &handler) noexcept
{
ogg_packet packet;
@@ -358,12 +358,11 @@ VisitVorbisDuration(InputStream &is,
const auto duration =
SongTime::FromScale<uint64_t>(packet.granulepos,
sample_rate);
- tag_handler_invoke_duration(handler, handler_ctx, duration);
+ handler.OnDuration(duration);
}
static bool
-vorbis_scan_stream(InputStream &is,
- const TagHandler &handler, void *handler_ctx) noexcept
+vorbis_scan_stream(InputStream &is, TagHandler &handler) noexcept
{
/* initialize libogg */
@@ -397,12 +396,11 @@ vorbis_scan_stream(InputStream &is,
/* visit the Vorbis comments we just read */
- vorbis_comments_scan(vc.user_comments,
- handler, handler_ctx);
+ vorbis_comments_scan(vc.user_comments, handler);
/* check the song duration by locating the e_o_s packet */
- VisitVorbisDuration(is, sync, stream, vi.rate, handler, handler_ctx);
+ VisitVorbisDuration(is, sync, stream, vi.rate, handler);
return true;
}
diff --git a/src/decoder/plugins/WavpackDecoderPlugin.cxx b/src/decoder/plugins/WavpackDecoderPlugin.cxx
index b444a7f80..d327f0280 100644
--- a/src/decoder/plugins/WavpackDecoderPlugin.cxx
+++ b/src/decoder/plugins/WavpackDecoderPlugin.cxx
@@ -578,8 +578,7 @@ wavpack_filedecode(DecoderClient &client, Path path_fs)
* Reads metainfo from the specified file.
*/
static bool
-wavpack_scan_file(Path path_fs,
- const TagHandler &handler, void *handler_ctx) noexcept
+wavpack_scan_file(Path path_fs, TagHandler &handler) noexcept
{
WavpackContext *wpc;
@@ -595,14 +594,13 @@ wavpack_scan_file(Path path_fs,
const auto duration = GetDuration(wpc);
if (!duration.IsNegative())
- tag_handler_invoke_duration(handler, handler_ctx, SongTime(duration));
+ handler.OnDuration(SongTime(duration));
return true;
}
static bool
-wavpack_scan_stream(InputStream &is,
- const TagHandler &handler, void *handler_ctx) noexcept
+wavpack_scan_stream(InputStream &is, TagHandler &handler) noexcept
{
WavpackInput isp(nullptr, is);
@@ -620,7 +618,7 @@ wavpack_scan_stream(InputStream &is,
const auto duration = GetDuration(wpc);
if (!duration.IsNegative())
- tag_handler_invoke_duration(handler, handler_ctx, SongTime(duration));
+ handler.OnDuration(SongTime(duration));
return true;
}
diff --git a/src/decoder/plugins/WildmidiDecoderPlugin.cxx b/src/decoder/plugins/WildmidiDecoderPlugin.cxx
index 0f65ebe6e..8a7c4fe9a 100644
--- a/src/decoder/plugins/WildmidiDecoderPlugin.cxx
+++ b/src/decoder/plugins/WildmidiDecoderPlugin.cxx
@@ -126,8 +126,7 @@ wildmidi_file_decode(DecoderClient &client, Path path_fs)
}
static bool
-wildmidi_scan_file(Path path_fs,
- const TagHandler &handler, void *handler_ctx) noexcept
+wildmidi_scan_file(Path path_fs, TagHandler &handler) noexcept
{
midi *wm = WildMidi_Open(path_fs.c_str());
if (wm == nullptr)
@@ -142,7 +141,7 @@ wildmidi_scan_file(Path path_fs,
const auto duration =
SongTime::FromScale<uint64_t>(info->approx_total_samples,
WILDMIDI_SAMPLE_RATE);
- tag_handler_invoke_duration(handler, handler_ctx, duration);
+ handler.OnDuration(duration);
WildMidi_Close(wm);
diff --git a/src/lib/xiph/VorbisComments.cxx b/src/lib/xiph/VorbisComments.cxx
index 642fa0033..a2761d9fa 100644
--- a/src/lib/xiph/VorbisComments.cxx
+++ b/src/lib/xiph/VorbisComments.cxx
@@ -53,13 +53,13 @@ vorbis_comments_to_replay_gain(ReplayGainInfo &rgi, char **comments) noexcept
static bool
vorbis_copy_comment(const char *comment,
const char *name, TagType tag_type,
- const TagHandler &handler, void *handler_ctx)
+ TagHandler &handler) noexcept
{
const char *value;
value = vorbis_comment_value(comment, name);
if (value != nullptr) {
- tag_handler_invoke_tag(handler, handler_ctx, tag_type, value);
+ handler.OnTag(tag_type, value);
return true;
}
@@ -67,36 +67,31 @@ vorbis_copy_comment(const char *comment,
}
static void
-vorbis_scan_comment(const char *comment,
- const TagHandler &handler, void *handler_ctx)
+vorbis_scan_comment(const char *comment, TagHandler &handler) noexcept
{
- if (handler.pair != nullptr) {
+ if (handler.WantPair()) {
const DivideString split(comment, '=');
if (split.IsDefined() && !split.empty())
- tag_handler_invoke_pair(handler, handler_ctx,
- split.GetFirst(),
- split.GetSecond());
+ handler.OnPair(split.GetFirst(), split.GetSecond());
}
for (const struct tag_table *i = xiph_tags; i->name != nullptr; ++i)
if (vorbis_copy_comment(comment, i->name, i->type,
- handler, handler_ctx))
+ handler))
return;
for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i)
if (vorbis_copy_comment(comment,
tag_item_names[i], TagType(i),
- handler, handler_ctx))
+ handler))
return;
}
void
-vorbis_comments_scan(char **comments,
- const TagHandler &handler, void *handler_ctx)
+vorbis_comments_scan(char **comments, TagHandler &handler) noexcept
{
while (*comments)
- vorbis_scan_comment(*comments++,
- handler, handler_ctx);
+ vorbis_scan_comment(*comments++, handler);
}
@@ -104,7 +99,8 @@ std::unique_ptr<Tag>
vorbis_comments_to_tag(char **comments) noexcept
{
TagBuilder tag_builder;
- vorbis_comments_scan(comments, add_tag_handler, &tag_builder);
+ AddTagHandler h(tag_builder);
+ vorbis_comments_scan(comments, h);
return tag_builder.empty()
? nullptr
: tag_builder.CommitNew();
diff --git a/src/lib/xiph/VorbisComments.hxx b/src/lib/xiph/VorbisComments.hxx
index 2f3285d13..c1a673daa 100644
--- a/src/lib/xiph/VorbisComments.hxx
+++ b/src/lib/xiph/VorbisComments.hxx
@@ -25,15 +25,14 @@
#include <memory>
struct ReplayGainInfo;
-struct TagHandler;
+class TagHandler;
struct Tag;
bool
vorbis_comments_to_replay_gain(ReplayGainInfo &rgi, char **comments) noexcept;
void
-vorbis_comments_scan(char **comments,
- const TagHandler &handler, void *handler_ctx);
+vorbis_comments_scan(char **comments, TagHandler &handler) noexcept;
std::unique_ptr<Tag>
vorbis_comments_to_tag(char **comments) noexcept;
diff --git a/src/playlist/plugins/EmbeddedCuePlaylistPlugin.cxx b/src/playlist/plugins/EmbeddedCuePlaylistPlugin.cxx
index afbf6a55c..63ebe911e 100644
--- a/src/playlist/plugins/EmbeddedCuePlaylistPlugin.cxx
+++ b/src/playlist/plugins/EmbeddedCuePlaylistPlugin.cxx
@@ -71,22 +71,23 @@ public:
virtual std::unique_ptr<DetachedSong> NextSong() override;
};
-static void
-embcue_tag_pair(const char *name, const char *value, void *ctx)
-{
- EmbeddedCuePlaylist *playlist = (EmbeddedCuePlaylist *)ctx;
+class ExtractCuesheetTagHandler final : public NullTagHandler {
+public:
+ std::string cuesheet;
- if (playlist->cuesheet.empty() &&
- StringEqualsCaseASCII(name, "cuesheet"))
- playlist->cuesheet = value;
-}
+ ExtractCuesheetTagHandler() noexcept:NullTagHandler(WANT_PAIR) {}
-static constexpr TagHandler embcue_tag_handler = {
- nullptr,
- nullptr,
- embcue_tag_pair,
+ void OnPair(const char *key, const char *value) noexcept override;
};
+void
+ExtractCuesheetTagHandler::OnPair(const char *name, const char *value) noexcept
+{
+ if (cuesheet.empty() &&
+ StringEqualsCaseASCII(name, "cuesheet"))
+ cuesheet = value;
+}
+
static std::unique_ptr<SongEnumerator>
embcue_playlist_open_uri(const char *uri,
gcc_unused Mutex &mutex)
@@ -97,18 +98,21 @@ embcue_playlist_open_uri(const char *uri,
const auto path_fs = AllocatedPath::FromUTF8Throw(uri);
- auto playlist = std::make_unique<EmbeddedCuePlaylist>();
-
- tag_file_scan(path_fs, embcue_tag_handler, playlist.get());
- if (playlist->cuesheet.empty())
- ScanGenericTags(path_fs, embcue_tag_handler, playlist.get());
+ ExtractCuesheetTagHandler extract_cuesheet;
+ tag_file_scan(path_fs, extract_cuesheet);
+ if (extract_cuesheet.cuesheet.empty())
+ ScanGenericTags(path_fs, extract_cuesheet);
- if (playlist->cuesheet.empty())
+ if (extract_cuesheet.cuesheet.empty())
/* no "CUESHEET" tag found */
return nullptr;
+ auto playlist = std::make_unique<EmbeddedCuePlaylist>();
+
playlist->filename = PathTraitsUTF8::GetBase(uri);
+ playlist->cuesheet = std::move(extract_cuesheet.cuesheet);
+
playlist->next = &playlist->cuesheet[0];
playlist->parser = new CueParser();
diff --git a/src/tag/ApeTag.cxx b/src/tag/ApeTag.cxx
index ff143e7cd..6d8203dc2 100644
--- a/src/tag/ApeTag.cxx
+++ b/src/tag/ApeTag.cxx
@@ -76,7 +76,7 @@ ForEachValue(const char *value, const char *end, C &&callback)
static bool
tag_ape_import_item(unsigned long flags,
const char *key, StringView value,
- const TagHandler &handler, void *handler_ctx)
+ TagHandler &handler) noexcept
{
/* we only care about utf-8 text tags */
if ((flags & (0x3 << 1)) != 0)
@@ -85,36 +85,31 @@ tag_ape_import_item(unsigned long flags,
const auto begin = value.begin();
const auto end = value.end();
- if (handler.pair != nullptr)
- ForEachValue(begin, end, [handler, handler_ctx,
- key](const char *_value) {
- handler.pair(key, _value, handler_ctx);
+ if (handler.WantPair())
+ ForEachValue(begin, end, [&handler, key](const char *_value) {
+ handler.OnPair(key, _value);
});
TagType type = tag_ape_name_parse(key);
if (type == TAG_NUM_OF_ITEM_TYPES)
return false;
- ForEachValue(begin, end, [handler, handler_ctx,
- type](const char *_value) {
- tag_handler_invoke_tag(handler, handler_ctx,
- type, _value);
+ ForEachValue(begin, end, [&handler, type](const char *_value) {
+ handler.OnTag(type, _value);
});
return true;
}
bool
-tag_ape_scan2(InputStream &is,
- const TagHandler &handler, void *handler_ctx)
+tag_ape_scan2(InputStream &is, TagHandler &handler) noexcept
{
bool recognized = false;
- auto callback = [handler, handler_ctx, &recognized]
+ auto callback = [&handler, &recognized]
(unsigned long flags, const char *key,
StringView value) {
- recognized |= tag_ape_import_item(flags, key, value,
- handler, handler_ctx);
+ recognized |= tag_ape_import_item(flags, key, value, handler);
return true;
};
diff --git a/src/tag/ApeTag.hxx b/src/tag/ApeTag.hxx
index 93b8ba126..9d467608d 100644
--- a/src/tag/ApeTag.hxx
+++ b/src/tag/ApeTag.hxx
@@ -20,10 +20,8 @@
#ifndef MPD_APE_TAG_HXX
#define MPD_APE_TAG_HXX
-#include "Table.hxx"
-
class InputStream;
-struct TagHandler;
+class TagHandler;
/**
* Scan the APE tags of a stream.
@@ -31,7 +29,6 @@ struct TagHandler;
* @param path_fs the path of the file in filesystem encoding
*/
bool
-tag_ape_scan2(InputStream &is,
- const TagHandler &handler, void *handler_ctx);
+tag_ape_scan2(InputStream &is, TagHandler &handler) noexcept;
#endif
diff --git a/src/tag/Generic.cxx b/src/tag/Generic.cxx
index 3aff10c79..1ce736505 100644
--- a/src/tag/Generic.cxx
+++ b/src/tag/Generic.cxx
@@ -30,9 +30,9 @@
#include <exception>
bool
-ScanGenericTags(InputStream &is, const TagHandler &handler, void *ctx)
+ScanGenericTags(InputStream &is, TagHandler &handler) noexcept
{
- if (tag_ape_scan2(is, handler, ctx))
+ if (tag_ape_scan2(is, handler))
return true;
#ifdef ENABLE_ID3TAG
@@ -42,19 +42,19 @@ ScanGenericTags(InputStream &is, const TagHandler &handler, void *ctx)
return false;
}
- return tag_id3_scan(is, handler, ctx);
+ return tag_id3_scan(is, handler);
#else
return false;
#endif
}
bool
-ScanGenericTags(Path path, const TagHandler &handler, void *ctx)
+ScanGenericTags(Path path, TagHandler &handler) noexcept
try {
Mutex mutex;
auto is = OpenLocalInputStream(path, mutex);
- return ScanGenericTags(*is, handler, ctx);
+ return ScanGenericTags(*is, handler);
} catch (...) {
LogError(std::current_exception());
return false;
diff --git a/src/tag/Generic.hxx b/src/tag/Generic.hxx
index 568b0b733..415cd2325 100644
--- a/src/tag/Generic.hxx
+++ b/src/tag/Generic.hxx
@@ -22,7 +22,7 @@
#include "check.h"
-struct TagHandler;
+class TagHandler;
class InputStream;
class Path;
@@ -31,12 +31,12 @@ class Path;
* stream does not need to be rewound.
*/
bool
-ScanGenericTags(InputStream &is, const TagHandler &handler, void *ctx);
+ScanGenericTags(InputStream &is, TagHandler &handler) noexcept;
/**
* Attempts to scan APE or ID3 tags from the specified file.
*/
bool
-ScanGenericTags(Path path, const TagHandler &handler, void *ctx);
+ScanGenericTags(Path path, TagHandler &handler) noexcept;
#endif
diff --git a/src/tag/Handler.cxx b/src/tag/Handler.cxx
index 7c4210f7d..ad8404161 100644
--- a/src/tag/Handler.cxx
+++ b/src/tag/Handler.cxx
@@ -25,19 +25,15 @@
#include <stdlib.h>
-static void
-add_tag_duration(SongTime duration, void *ctx)
+void
+AddTagHandler::OnDuration(SongTime duration) noexcept
{
- TagBuilder &tag = *(TagBuilder *)ctx;
-
tag.SetDuration(duration);
}
-static void
-add_tag_tag(TagType type, const char *value, void *ctx)
+void
+AddTagHandler::OnTag(TagType type, const char *value) noexcept
{
- TagBuilder &tag = *(TagBuilder *)ctx;
-
if (type == TAG_TRACK || type == TAG_DISC) {
/* filter out this extra data and leading zeroes */
char *end;
@@ -48,24 +44,10 @@ add_tag_tag(TagType type, const char *value, void *ctx)
tag.AddItem(type, value);
}
-const TagHandler add_tag_handler = {
- add_tag_duration,
- add_tag_tag,
- nullptr,
-};
-
-static void
-full_tag_pair(const char *name, gcc_unused const char *value, void *ctx)
+void
+FullTagHandler::OnPair(const char *name, gcc_unused const char *value) noexcept
{
- TagBuilder &tag = *(TagBuilder *)ctx;
-
if (StringEqualsCaseASCII(name, "cuesheet"))
tag.SetHasPlaylist(true);
}
-const TagHandler full_tag_handler = {
- add_tag_duration,
- add_tag_tag,
- full_tag_pair,
-};
-
diff --git a/src/tag/Handler.hxx b/src/tag/Handler.hxx
index cec04e91d..944c73114 100644
--- a/src/tag/Handler.hxx
+++ b/src/tag/Handler.hxx
@@ -23,19 +23,45 @@
#include "check.h"
#include "Type.h"
#include "Chrono.hxx"
+#include "Compiler.h"
-#include <assert.h>
+class TagBuilder;
/**
- * A callback table for receiving metadata of a song.
+ * An interface for receiving metadata of a song.
*/
-struct TagHandler {
+class TagHandler {
+ const unsigned want_mask;
+
+public:
+ static constexpr unsigned WANT_DURATION = 0x1;
+ static constexpr unsigned WANT_TAG = 0x2;
+ static constexpr unsigned WANT_PAIR = 0x4;
+
+ explicit TagHandler(unsigned _want_mask) noexcept
+ :want_mask(_want_mask) {}
+
+ TagHandler(const TagHandler &) = delete;
+ TagHandler &operator=(const TagHandler &) = delete;
+
+ bool WantDuration() const noexcept {
+ return want_mask & WANT_DURATION;
+ }
+
+ bool WantTag() const noexcept {
+ return want_mask & WANT_TAG;
+ }
+
+ bool WantPair() const noexcept {
+ return want_mask & WANT_PAIR;
+ }
+
/**
* Declare the duration of a song. Do not call
* this when the duration could not be determined, because
* there is no magic value for "unknown duration".
*/
- void (*duration)(SongTime duration, void *ctx);
+ virtual void OnDuration(SongTime duration) noexcept = 0;
/**
* A tag has been read.
@@ -43,56 +69,57 @@ struct TagHandler {
* @param the value of the tag; the pointer will become
* invalid after returning
*/
- void (*tag)(TagType type, const char *value, void *ctx);
+ virtual void OnTag(TagType type, const char *value) noexcept = 0;
/**
* A name-value pair has been read. It is the codec specific
* representation of tags.
*/
- void (*pair)(const char *key, const char *value, void *ctx);
+ virtual void OnPair(const char *key, const char *value) noexcept = 0;
};
-static inline void
-tag_handler_invoke_duration(const TagHandler &handler, void *ctx,
- SongTime duration) noexcept
-{
- if (handler.duration != nullptr)
- handler.duration(duration, ctx);
-}
-
-static inline void
-tag_handler_invoke_tag(const TagHandler &handler, void *ctx,
- TagType type, const char *value) noexcept
-{
- assert((unsigned)type < TAG_NUM_OF_ITEM_TYPES);
- assert(value != nullptr);
-
- if (handler.tag != nullptr)
- handler.tag(type, value, ctx);
-}
-
-static inline void
-tag_handler_invoke_pair(const TagHandler &handler, void *ctx,
- const char *name, const char *value) noexcept
-{
- assert(name != nullptr);
- assert(value != nullptr);
-
- if (handler.pair != nullptr)
- handler.pair(name, value, ctx);
-}
+class NullTagHandler : public TagHandler {
+public:
+ explicit NullTagHandler(unsigned _want_mask) noexcept
+ :TagHandler(_want_mask) {}
+
+ void OnDuration(gcc_unused SongTime duration) noexcept override {}
+ void OnTag(gcc_unused TagType type,
+ gcc_unused const char *value) noexcept override {}
+ void OnPair(gcc_unused const char *key,
+ gcc_unused const char *value) noexcept override {}
+};
/**
- * This #TagHandler implementation adds tag values to a #TagBuilder object
- * (casted from the context pointer).
+ * This #TagHandler implementation adds tag values to a #TagBuilder
+ * object.
*/
-extern const TagHandler add_tag_handler;
+class AddTagHandler : public NullTagHandler {
+protected:
+ TagBuilder &tag;
+
+ AddTagHandler(unsigned _want_mask, TagBuilder &_builder) noexcept
+ :NullTagHandler(_want_mask), tag(_builder) {}
+
+public:
+ explicit AddTagHandler(TagBuilder &_builder) noexcept
+ :AddTagHandler(WANT_DURATION|WANT_TAG, _builder) {}
+
+ void OnDuration(SongTime duration) noexcept override;
+ void OnTag(TagType type, const char *value) noexcept override;
+};
/**
* This #TagHandler implementation adds tag values to a #TagBuilder object
* (casted from the context pointer), and supports the has_playlist
* attribute.
*/
-extern const TagHandler full_tag_handler;
+class FullTagHandler : public AddTagHandler {
+public:
+ explicit FullTagHandler(TagBuilder &_builder) noexcept
+ :AddTagHandler(WANT_DURATION|WANT_TAG|WANT_PAIR, _builder) {}
+
+ void OnPair(const char *key, const char *value) noexcept override;
+};
#endif
diff --git a/src/tag/Id3Scan.cxx b/src/tag/Id3Scan.cxx
index cd35386e4..aa1caba69 100644
--- a/src/tag/Id3Scan.cxx
+++ b/src/tag/Id3Scan.cxx
@@ -100,7 +100,7 @@ import_id3_string(const id3_ucs4_t *ucs4)
static void
tag_id3_import_text_frame(const struct id3_frame *frame,
TagType type,
- const TagHandler &handler, void *handler_ctx)
+ TagHandler &handler) noexcept
{
if (frame->nfields != 2)
return;
@@ -133,8 +133,7 @@ tag_id3_import_text_frame(const struct id3_frame *frame,
AtScopeExit(utf8) { free(utf8); };
- tag_handler_invoke_tag(handler, handler_ctx,
- type, (const char *)utf8);
+ handler.OnTag(type, (const char *)utf8);
}
}
@@ -144,13 +143,13 @@ tag_id3_import_text_frame(const struct id3_frame *frame,
*/
static void
tag_id3_import_text(struct id3_tag *tag, const char *id, TagType type,
- const TagHandler &handler, void *handler_ctx)
+ TagHandler &handler) noexcept
{
const struct id3_frame *frame;
for (unsigned i = 0;
(frame = id3_tag_findframe(tag, id, i)) != nullptr; ++i)
tag_id3_import_text_frame(frame, type,
- handler, handler_ctx);
+ handler);
}
/**
@@ -164,8 +163,7 @@ tag_id3_import_text(struct id3_tag *tag, const char *id, TagType type,
*/
static void
tag_id3_import_comment_frame(const struct id3_frame *frame, TagType type,
- const TagHandler &handler,
- void *handler_ctx)
+ TagHandler &handler) noexcept
{
if (frame->nfields != 4)
return;
@@ -185,7 +183,7 @@ tag_id3_import_comment_frame(const struct id3_frame *frame, TagType type,
AtScopeExit(utf8) { free(utf8); };
- tag_handler_invoke_tag(handler, handler_ctx, type, (const char *)utf8);
+ handler.OnTag(type, (const char *)utf8);
}
/**
@@ -194,13 +192,13 @@ tag_id3_import_comment_frame(const struct id3_frame *frame, TagType type,
*/
static void
tag_id3_import_comment(struct id3_tag *tag, const char *id, TagType type,
- const TagHandler &handler, void *handler_ctx)
+ TagHandler &handler) noexcept
{
const struct id3_frame *frame;
for (unsigned i = 0;
(frame = id3_tag_findframe(tag, id, i)) != nullptr; ++i)
tag_id3_import_comment_frame(frame, type,
- handler, handler_ctx);
+ handler);
}
/**
@@ -220,8 +218,7 @@ tag_id3_parse_txxx_name(const char *name) noexcept
*/
static void
tag_id3_import_musicbrainz(struct id3_tag *id3_tag,
- const TagHandler &handler,
- void *handler_ctx)
+ TagHandler &handler) noexcept
{
for (unsigned i = 0;; ++i) {
const id3_frame *frame = id3_tag_findframe(id3_tag, "TXXX", i);
@@ -240,15 +237,12 @@ tag_id3_import_musicbrainz(struct id3_tag *id3_tag,
AtScopeExit(value) { free(value); };
- tag_handler_invoke_pair(handler, handler_ctx,
- (const char *)name,
- (const char *)value);
+ handler.OnPair((const char *)name, (const char *)value);
TagType type = tag_id3_parse_txxx_name((const char*)name);
if (type != TAG_NUM_OF_ITEM_TYPES)
- tag_handler_invoke_tag(handler, handler_ctx,
- type, (const char*)value);
+ handler.OnTag(type, (const char*)value);
}
}
@@ -257,7 +251,7 @@ tag_id3_import_musicbrainz(struct id3_tag *id3_tag,
*/
static void
tag_id3_import_ufid(struct id3_tag *id3_tag,
- const TagHandler &handler, void *handler_ctx)
+ TagHandler &handler) noexcept
{
for (unsigned i = 0;; ++i) {
const id3_frame *frame = id3_tag_findframe(id3_tag, "UFID", i);
@@ -284,65 +278,63 @@ tag_id3_import_ufid(struct id3_tag *id3_tag,
continue;
std::string p((const char *)value, length);
- tag_handler_invoke_tag(handler, handler_ctx,
- TAG_MUSICBRAINZ_TRACKID, p.c_str());
+ handler.OnTag(TAG_MUSICBRAINZ_TRACKID, p.c_str());
}
}
void
-scan_id3_tag(struct id3_tag *tag,
- const TagHandler &handler, void *handler_ctx)
+scan_id3_tag(struct id3_tag *tag, TagHandler &handler) noexcept
{
tag_id3_import_text(tag, ID3_FRAME_ARTIST, TAG_ARTIST,
- handler, handler_ctx);
+ handler);
tag_id3_import_text(tag, ID3_FRAME_ALBUM_ARTIST,
- TAG_ALBUM_ARTIST, handler, handler_ctx);
+ TAG_ALBUM_ARTIST, handler);
tag_id3_import_text(tag, ID3_FRAME_ARTIST_SORT,
- TAG_ARTIST_SORT, handler, handler_ctx);
+ TAG_ARTIST_SORT, handler);
- tag_id3_import_text(tag, "TSOA", TAG_ALBUM_SORT, handler, handler_ctx);
+ tag_id3_import_text(tag, "TSOA", TAG_ALBUM_SORT, handler);
tag_id3_import_text(tag, ID3_FRAME_ALBUM_ARTIST_SORT,
- TAG_ALBUM_ARTIST_SORT, handler, handler_ctx);
+ TAG_ALBUM_ARTIST_SORT, handler);
tag_id3_import_text(tag, ID3_FRAME_TITLE, TAG_TITLE,
- handler, handler_ctx);
+ handler);
tag_id3_import_text(tag, ID3_FRAME_ALBUM, TAG_ALBUM,
- handler, handler_ctx);
+ handler);
tag_id3_import_text(tag, ID3_FRAME_TRACK, TAG_TRACK,
- handler, handler_ctx);
+ handler);
tag_id3_import_text(tag, ID3_FRAME_YEAR, TAG_DATE,
- handler, handler_ctx);
+ handler);
tag_id3_import_text(tag, ID3_FRAME_ORIGINAL_RELEASE_DATE, TAG_ORIGINAL_DATE,
- handler, handler_ctx);
+ handler);
tag_id3_import_text(tag, ID3_FRAME_GENRE, TAG_GENRE,
- handler, handler_ctx);
+ handler);
tag_id3_import_text(tag, ID3_FRAME_COMPOSER, TAG_COMPOSER,
- handler, handler_ctx);
+ handler);
tag_id3_import_text(tag, "TPE3", TAG_PERFORMER,
- handler, handler_ctx);
- tag_id3_import_text(tag, "TPE4", TAG_PERFORMER, handler, handler_ctx);
+ handler);
+ tag_id3_import_text(tag, "TPE4", TAG_PERFORMER, handler);
tag_id3_import_comment(tag, ID3_FRAME_COMMENT, TAG_COMMENT,
- handler, handler_ctx);
+ handler);
tag_id3_import_text(tag, ID3_FRAME_DISC, TAG_DISC,
- handler, handler_ctx);
+ handler);
- tag_id3_import_musicbrainz(tag, handler, handler_ctx);
- tag_id3_import_ufid(tag, handler, handler_ctx);
+ tag_id3_import_musicbrainz(tag, handler);
+ tag_id3_import_ufid(tag, handler);
}
std::unique_ptr<Tag>
tag_id3_import(struct id3_tag *tag)
{
TagBuilder tag_builder;
- scan_id3_tag(tag, add_tag_handler, &tag_builder);
+ AddTagHandler h(tag_builder);
+ scan_id3_tag(tag, h);
return tag_builder.empty()
? nullptr
: tag_builder.CommitNew();
}
bool
-tag_id3_scan(InputStream &is,
- const TagHandler &handler, void *handler_ctx)
+tag_id3_scan(InputStream &is, TagHandler &handler) noexcept
{
UniqueId3Tag tag;
@@ -355,6 +347,6 @@ tag_id3_scan(InputStream &is,
return false;
}
- scan_id3_tag(tag.get(), handler, handler_ctx);
+ scan_id3_tag(tag.get(), handler);
return true;
}
diff --git a/src/tag/Id3Scan.hxx b/src/tag/Id3Scan.hxx
index d81e154a5..8ce23ad46 100644
--- a/src/tag/Id3Scan.hxx
+++ b/src/tag/Id3Scan.hxx
@@ -25,13 +25,12 @@
#include <memory>
class InputStream;
-struct TagHandler;
+class TagHandler;
struct Tag;
struct id3_tag;
bool
-tag_id3_scan(InputStream &is,
- const TagHandler &handler, void *handler_ctx);
+tag_id3_scan(InputStream &is, TagHandler &handler) noexcept;
std::unique_ptr<Tag>
tag_id3_import(id3_tag *);
@@ -41,7 +40,6 @@ tag_id3_import(id3_tag *);
*
*/
void
-scan_id3_tag(id3_tag *tag,
- const TagHandler &handler, void *handler_ctx);
+scan_id3_tag(id3_tag *tag, TagHandler &handler) noexcept;
#endif
diff --git a/test/read_tags.cxx b/test/read_tags.cxx
index 2268afaf9..e2ea56ad8 100644
--- a/test/read_tags.cxx
+++ b/test/read_tags.cxx
@@ -40,31 +40,29 @@
#include <locale.h>
#endif
-static bool empty = true;
+class DumpTagHandler final : public NullTagHandler {
+ bool empty = true;
-static void
-print_duration(SongTime duration, gcc_unused void *ctx)
-{
- printf("duration=%f\n", duration.ToDoubleS());
-}
+public:
+ DumpTagHandler() noexcept
+ :NullTagHandler(WANT_DURATION|WANT_TAG|WANT_PAIR) {}
-static void
-print_tag(TagType type, const char *value, gcc_unused void *ctx)
-{
- printf("[%s]=%s\n", tag_item_names[type], value);
- empty = false;
-}
+ bool IsEmpty() const noexcept {
+ return empty;
+ }
-static void
-print_pair(const char *name, const char *value, gcc_unused void *ctx)
-{
- printf("\"%s\"=%s\n", name, value);
-}
+ void OnDuration(SongTime duration) noexcept override {
+ printf("duration=%f\n", duration.ToDoubleS());
+ }
+
+ void OnTag(TagType type, const char *value) noexcept override {
+ printf("[%s]=%s\n", tag_item_names[type], value);
+ empty = false;
+ }
-static constexpr TagHandler print_handler = {
- print_duration,
- print_tag,
- print_pair,
+ void OnPair(const char *key, const char *value) noexcept override {
+ printf("\"%s\"=%s\n", key, value);
+ }
};
int main(int argc, char **argv)
@@ -100,9 +98,10 @@ try {
return EXIT_FAILURE;
}
+ DumpTagHandler h;
bool success;
try {
- success = plugin->ScanFile(path, print_handler, nullptr);
+ success = plugin->ScanFile(path, h);
} catch (const std::exception &e) {
LogError(e);
success = false;
@@ -113,7 +112,7 @@ try {
if (!success && plugin->scan_stream != NULL) {
is = InputStream::OpenReady(path.c_str(), mutex);
- success = plugin->ScanStream(*is, print_handler, nullptr);
+ success = plugin->ScanStream(*is, h);
}
if (!success) {
@@ -121,11 +120,11 @@ try {
return EXIT_FAILURE;
}
- if (empty) {
+ if (h.IsEmpty()) {
if (is)
- ScanGenericTags(*is, print_handler, nullptr);
+ ScanGenericTags(*is, h);
else
- ScanGenericTags(path, print_handler, nullptr);
+ ScanGenericTags(path, h);
}
return 0;