diff options
author | Max Kellermann <max@musicpd.org> | 2018-07-05 19:07:05 +0200 |
---|---|---|
committer | Max Kellermann <max@musicpd.org> | 2018-07-05 19:07:05 +0200 |
commit | 3d3a1232b1d2b58d2cc05b2dd5c37f2256832693 (patch) | |
tree | 250933da4d5dc29145ce18e5a05a7f8da30396fd | |
parent | 09d4176210d66cf9e2d258b563a7811892c560f4 (diff) |
tag/Handler: convert to class with virtual methods
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; |