summaryrefslogtreecommitdiff
path: root/src/tag/Handler.hxx
blob: 30bab72be9af295c7d2b9c284a6b48831e68082b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/*
 * Copyright 2003-2020 The Music Player Daemon Project
 * http://www.musicpd.org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#ifndef MPD_TAG_HANDLER_HXX
#define MPD_TAG_HANDLER_HXX

#include "Type.h"
#include "Chrono.hxx"
#include "util/Compiler.h"

template<typename T> struct ConstBuffer;
struct StringView;
struct AudioFormat;
class TagBuilder;

/**
 * An interface for receiving metadata of a song.
 */
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;
	static constexpr unsigned WANT_AUDIO_FORMAT = 0x8;
	static constexpr unsigned WANT_PICTURE = 0x10;

	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;
	}

	bool WantAudioFormat() const noexcept {
		return want_mask & WANT_AUDIO_FORMAT;
	}

	bool WantPicture() const noexcept {
		return want_mask & WANT_PICTURE;
	}

	/**
	 * 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".
	 */
	virtual void OnDuration(SongTime duration) noexcept = 0;

	/**
	 * A tag has been read.
	 *
	 * @param the value of the tag; the pointer will become
	 * invalid after returning
	 */
	virtual void OnTag(TagType type, StringView value) noexcept = 0;

	/**
	 * A name-value pair has been read.  It is the codec specific
	 * representation of tags.
	 */
	virtual void OnPair(StringView key, StringView value) noexcept = 0;

	/**
	 * Declare the audio format of a song.
	 *
	 * Because the #AudioFormat type is limited to formats
	 * supported by MPD, the value passed to this method may be an
	 * approximation (should be the one passed to
	 * DecoderClient::Ready()).  For example, some codecs such as
	 * MP3 are bit depth agnostic, so the decoder plugin chooses a
	 * bit depth depending on what the codec library emits.
	 *
	 * This method is only called by those decoder plugins which
	 * implement it.  Some may not have any code for calling it,
	 * and others may decide that determining the audio format is
	 * too expensive.
	 */
	virtual void OnAudioFormat(AudioFormat af) noexcept = 0;

	/**
	 * A picture has been read.
	 *
	 * This method will only be called if #WANT_PICTURE was enabled.
	 *
	 * @param mime_type an optional MIME type string
	 * @param buffer the picture file contents; the buffer will be
	 * invalidated after this method returns
	 */
	virtual void OnPicture(const char *mime_type,
			       ConstBuffer<void> buffer) noexcept = 0;
};

class NullTagHandler : public TagHandler {
public:
	explicit NullTagHandler(unsigned _want_mask) noexcept
		:TagHandler(_want_mask) {}

	void OnDuration([[maybe_unused]] SongTime duration) noexcept override {}
	void OnTag(TagType type, StringView value) noexcept override;
	void OnPair(StringView key, StringView value) noexcept override;
	void OnAudioFormat(AudioFormat af) noexcept override;
	void OnPicture(const char *mime_type,
		       ConstBuffer<void> buffer) noexcept override;
};

/**
 * This #TagHandler implementation adds tag values to a #TagBuilder
 * object.
 */
class AddTagHandler : public NullTagHandler {
protected:
	TagBuilder &tag;

	AddTagHandler(unsigned _want_mask, TagBuilder &_builder) noexcept
		:NullTagHandler(WANT_DURATION|WANT_TAG|_want_mask),
		 tag(_builder) {}

public:
	explicit AddTagHandler(TagBuilder &_builder) noexcept
		:AddTagHandler(0, _builder) {}

	void OnDuration(SongTime duration) noexcept override;
	void OnTag(TagType type, StringView value) noexcept override;
};

/**
 * This #TagHandler implementation adds tag values to a #TagBuilder object
 * (casted from the context pointer), and supports the has_playlist
 * attribute.
 */
class FullTagHandler : public AddTagHandler {
	AudioFormat *const audio_format;

protected:
	FullTagHandler(unsigned _want_mask, TagBuilder &_builder,
		       AudioFormat *_audio_format) noexcept
		:AddTagHandler(WANT_PAIR|_want_mask
			       |(_audio_format ? WANT_AUDIO_FORMAT : 0),
			       _builder),
		 audio_format(_audio_format) {}

public:
	explicit FullTagHandler(TagBuilder &_builder,
				AudioFormat *_audio_format=nullptr) noexcept
		:FullTagHandler(0, _builder, _audio_format) {}

	void OnPair(StringView key, StringView value) noexcept override;
	void OnAudioFormat(AudioFormat af) noexcept override;
};

#endif