tag/Handler: convert to class with virtual methods

This commit is contained in:
Max Kellermann
2018-07-05 19:07:05 +02:00
parent 09d4176210
commit 3d3a1232b1
49 changed files with 414 additions and 496 deletions
+9 -14
View File
@@ -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;
};
+2 -5
View File
@@ -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
+5 -5
View File
@@ -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;
+3 -3
View File
@@ -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
+6 -24
View File
@@ -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,
};
+65 -38
View File
@@ -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);
}
class NullTagHandler : public TagHandler {
public:
explicit NullTagHandler(unsigned _want_mask) noexcept
:TagHandler(_want_mask) {}
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);
}
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
+36 -44
View File
@@ -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;
}
+3 -5
View File
@@ -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