aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2013-07-30 20:11:57 +0200
committerMax Kellermann <max@duempel.org>2013-07-30 20:19:53 +0200
commit06f898cc1240a29b293de0e97ad95a4fdc971254 (patch)
tree001a6d3db039cdc03323f3bfddc13b94bde31ce4 /src
parent6a9ab8bc0e2f5d34803513bb2d94d041a607a58c (diff)
downloadmpd-06f898cc1240a29b293de0e97ad95a4fdc971254.tar.gz
mpd-06f898cc1240a29b293de0e97ad95a4fdc971254.tar.xz
mpd-06f898cc1240a29b293de0e97ad95a4fdc971254.zip
tag: convert to C++
Diffstat (limited to 'src')
-rw-r--r--src/AllCommands.cxx2
-rw-r--r--src/ApeTag.cxx2
-rw-r--r--src/CrossFade.cxx2
-rw-r--r--src/DatabaseCommands.cxx2
-rw-r--r--src/DatabaseHelpers.cxx8
-rw-r--r--src/DatabasePrint.cxx2
-rw-r--r--src/DatabaseSave.cxx2
-rw-r--r--src/DecoderAPI.cxx41
-rw-r--r--src/DecoderAPI.hxx4
-rw-r--r--src/DecoderBuffer.cxx1
-rw-r--r--src/DecoderInternal.cxx13
-rw-r--r--src/DecoderInternal.hxx10
-rw-r--r--src/DecoderPlugin.hxx2
-rw-r--r--src/DecoderThread.cxx4
-rw-r--r--src/DespotifyUtils.cxx20
-rw-r--r--src/DespotifyUtils.hxx4
-rw-r--r--src/EncoderAPI.hxx2
-rw-r--r--src/EncoderPlugin.hxx6
-rw-r--r--src/IcyMetaDataParser.cxx20
-rw-r--r--src/IcyMetaDataParser.hxx8
-rw-r--r--src/IcyMetaDataServer.cxx7
-rw-r--r--src/IcyMetaDataServer.hxx3
-rw-r--r--src/InputPlugin.hxx2
-rw-r--r--src/InputStream.cxx4
-rw-r--r--src/Main.cxx2
-rw-r--r--src/MusicChunk.cxx5
-rw-r--r--src/MusicChunk.hxx3
-rw-r--r--src/OutputAPI.hxx2
-rw-r--r--src/OutputInit.cxx1
-rw-r--r--src/OutputList.cxx2
-rw-r--r--src/OutputPlugin.cxx2
-rw-r--r--src/OutputPlugin.hxx6
-rw-r--r--src/OutputThread.cxx1
-rw-r--r--src/PlayerThread.cxx24
-rw-r--r--src/PlaylistPlugin.hxx2
-rw-r--r--src/PlaylistSong.cxx8
-rw-r--r--src/Song.cxx8
-rw-r--r--src/Song.hxx4
-rw-r--r--src/SongFilter.cxx7
-rw-r--r--src/SongFilter.hxx10
-rw-r--r--src/SongPrint.cxx4
-rw-r--r--src/SongSave.cxx26
-rw-r--r--src/SongSort.cxx10
-rw-r--r--src/SongUpdate.cxx23
-rw-r--r--src/Tag.cxx243
-rw-r--r--src/Tag.hxx218
-rw-r--r--src/TagHandler.cxx10
-rw-r--r--src/TagId3.cxx11
-rw-r--r--src/TagId3.hxx7
-rw-r--r--src/TagPool.cxx15
-rw-r--r--src/TagPool.hxx10
-rw-r--r--src/TagPrint.cxx14
-rw-r--r--src/TagPrint.hxx5
-rw-r--r--src/TagSave.cxx17
-rw-r--r--src/TagSave.hxx5
-rw-r--r--src/UpdateContainer.cxx4
-rw-r--r--src/cue/CueParser.cxx31
-rw-r--r--src/cue/CueParser.hxx5
-rw-r--r--src/db/ProxyDatabasePlugin.cxx14
-rw-r--r--src/decoder/DsdLib.cxx1
-rw-r--r--src/decoder/FaadDecoderPlugin.cxx1
-rw-r--r--src/decoder/FlacCommon.cxx3
-rw-r--r--src/decoder/FlacCommon.hxx2
-rw-r--r--src/decoder/FlacDecoderPlugin.cxx8
-rw-r--r--src/decoder/FlacMetadata.cxx4
-rw-r--r--src/decoder/FlacMetadata.hxx4
-rw-r--r--src/decoder/MadDecoderPlugin.cxx32
-rw-r--r--src/decoder/OggCodec.cxx2
-rw-r--r--src/decoder/OpusDecoderPlugin.cxx11
-rw-r--r--src/decoder/PcmDecoderPlugin.cxx1
-rw-r--r--src/decoder/VorbisComments.cxx10
-rw-r--r--src/decoder/VorbisComments.hxx3
-rw-r--r--src/decoder/VorbisDecoderPlugin.cxx4
-rw-r--r--src/decoder/sidplay_decoder_plugin.cxx1
-rw-r--r--src/encoder/VorbisEncoderPlugin.cxx12
-rw-r--r--src/input/CurlInputPlugin.cxx28
-rw-r--r--src/input/DespotifyInputPlugin.cxx11
-rw-r--r--src/input/RewindInputPlugin.cxx5
-rw-r--r--src/input_stream.h7
-rw-r--r--src/mixer/OssMixerPlugin.cxx1
-rw-r--r--src/output/AoOutputPlugin.cxx2
-rw-r--r--src/output/HttpdInternal.hxx3
-rw-r--r--src/output/HttpdOutputPlugin.cxx7
-rw-r--r--src/output/JackOutputPlugin.cxx1
-rw-r--r--src/output/RoarOutputPlugin.cxx2
-rw-r--r--src/output/ShoutOutputPlugin.cxx5
-rw-r--r--src/playlist/AsxPlaylistPlugin.cxx8
-rw-r--r--src/playlist/CuePlaylistPlugin.cxx2
-rw-r--r--src/playlist/DespotifyPlaylistPlugin.cxx2
-rw-r--r--src/playlist/EmbeddedCuePlaylistPlugin.cxx2
-rw-r--r--src/playlist/ExtM3uPlaylistPlugin.cxx18
-rw-r--r--src/playlist/PlsPlaylistPlugin.cxx8
-rw-r--r--src/playlist/RssPlaylistPlugin.cxx8
-rw-r--r--src/playlist/SoundCloudPlaylistPlugin.cxx8
-rw-r--r--src/playlist/XspfPlaylistPlugin.cxx7
-rw-r--r--src/tag.h215
96 files changed, 690 insertions, 689 deletions
diff --git a/src/AllCommands.cxx b/src/AllCommands.cxx
index f3243915b..8f651ec04 100644
--- a/src/AllCommands.cxx
+++ b/src/AllCommands.cxx
@@ -28,7 +28,7 @@
#include "MessageCommands.hxx"
#include "OtherCommands.hxx"
#include "Permission.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include "protocol/Result.hxx"
#include "Client.hxx"
#include "util/Tokenizer.hxx"
diff --git a/src/ApeTag.cxx b/src/ApeTag.cxx
index e0ef24c75..34c2b703b 100644
--- a/src/ApeTag.cxx
+++ b/src/ApeTag.cxx
@@ -20,7 +20,7 @@
#include "config.h"
#include "ApeTag.hxx"
#include "ApeLoader.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include "TagTable.hxx"
#include "TagHandler.hxx"
diff --git a/src/CrossFade.cxx b/src/CrossFade.cxx
index 0bdcc43d6..253038b26 100644
--- a/src/CrossFade.cxx
+++ b/src/CrossFade.cxx
@@ -21,7 +21,7 @@
#include "CrossFade.hxx"
#include "MusicChunk.hxx"
#include "audio_format.h"
-#include "tag.h"
+#include "Tag.hxx"
#include <cmath>
diff --git a/src/DatabaseCommands.cxx b/src/DatabaseCommands.cxx
index 039bfefed..42c7d4c32 100644
--- a/src/DatabaseCommands.cxx
+++ b/src/DatabaseCommands.cxx
@@ -25,7 +25,7 @@
#include "DatabaseSelection.hxx"
#include "CommandError.hxx"
#include "ClientInternal.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include "util/UriUtil.hxx"
#include "SongFilter.hxx"
#include "protocol/Result.hxx"
diff --git a/src/DatabaseHelpers.cxx b/src/DatabaseHelpers.cxx
index d6eeb10a1..ecaf44915 100644
--- a/src/DatabaseHelpers.cxx
+++ b/src/DatabaseHelpers.cxx
@@ -20,7 +20,7 @@
#include "DatabaseHelpers.hxx"
#include "DatabasePlugin.hxx"
#include "Song.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include <functional>
#include <set>
@@ -39,7 +39,7 @@ typedef std::set<const char *, StringLess> StringSet;
static bool
CollectTags(StringSet &set, enum tag_type tag_type, Song &song)
{
- struct tag *tag = song.tag;
+ Tag *tag = song.tag;
if (tag == nullptr)
return true;
@@ -79,13 +79,13 @@ VisitUniqueTags(const Database &db, const DatabaseSelection &selection,
static void
StatsVisitTag(DatabaseStats &stats, StringSet &artists, StringSet &albums,
- const struct tag &tag)
+ const Tag &tag)
{
if (tag.time > 0)
stats.total_duration += tag.time;
for (unsigned i = 0; i < tag.num_items; ++i) {
- const struct tag_item &item = *tag.items[i];
+ const TagItem &item = *tag.items[i];
switch (item.type) {
case TAG_ARTIST:
diff --git a/src/DatabasePrint.cxx b/src/DatabasePrint.cxx
index da427c59f..093b0bd46 100644
--- a/src/DatabasePrint.cxx
+++ b/src/DatabasePrint.cxx
@@ -26,7 +26,7 @@
#include "TimePrint.hxx"
#include "Directory.hxx"
#include "Client.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include "Song.hxx"
#include "DatabaseGlue.hxx"
#include "DatabasePlugin.hxx"
diff --git a/src/DatabaseSave.cxx b/src/DatabaseSave.cxx
index fdc2174c0..56dd19129 100644
--- a/src/DatabaseSave.cxx
+++ b/src/DatabaseSave.cxx
@@ -25,7 +25,7 @@
#include "Song.hxx"
#include "TextFile.hxx"
#include "TagInternal.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include "fs/Path.hxx"
#include <glib.h>
diff --git a/src/DecoderAPI.cxx b/src/DecoderAPI.cxx
index 015b11c72..c7a12c68a 100644
--- a/src/DecoderAPI.cxx
+++ b/src/DecoderAPI.cxx
@@ -33,6 +33,7 @@
#include <assert.h>
#include <stdlib.h>
+#include <string.h>
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "decoder"
@@ -312,7 +313,7 @@ decoder_timestamp(struct decoder *decoder, double t)
* (decoder.chunk) if there is one.
*/
static enum decoder_command
-do_send_tag(struct decoder *decoder, const struct tag *tag)
+do_send_tag(struct decoder *decoder, const Tag &tag)
{
struct music_chunk *chunk;
@@ -331,14 +332,14 @@ do_send_tag(struct decoder *decoder, const struct tag *tag)
return decoder->dc->command;
}
- chunk->tag = tag_dup(tag);
+ chunk->tag = new Tag(tag);
return DECODE_COMMAND_NONE;
}
static bool
update_stream_tag(struct decoder *decoder, struct input_stream *is)
{
- struct tag *tag;
+ Tag *tag;
tag = is != NULL
? input_stream_lock_tag(is)
@@ -353,9 +354,7 @@ update_stream_tag(struct decoder *decoder, struct input_stream *is)
decoder->song_tag = NULL;
}
- if (decoder->stream_tag != NULL)
- tag_free(decoder->stream_tag);
-
+ delete decoder->stream_tag;
decoder->stream_tag = tag;
return true;
}
@@ -387,15 +386,13 @@ decoder_data(struct decoder *decoder,
if (update_stream_tag(decoder, is)) {
if (decoder->decoder_tag != NULL) {
/* merge with tag from decoder plugin */
- struct tag *tag;
-
- tag = tag_merge(decoder->decoder_tag,
- decoder->stream_tag);
- cmd = do_send_tag(decoder, tag);
- tag_free(tag);
+ Tag *tag = Tag::Merge(*decoder->decoder_tag,
+ *decoder->stream_tag);
+ cmd = do_send_tag(decoder, *tag);
+ delete tag;
} else
/* send only the stream tag */
- cmd = do_send_tag(decoder, decoder->stream_tag);
+ cmd = do_send_tag(decoder, *decoder->stream_tag);
if (cmd != DECODE_COMMAND_NONE)
return cmd;
@@ -474,7 +471,7 @@ decoder_data(struct decoder *decoder,
enum decoder_command
decoder_tag(G_GNUC_UNUSED struct decoder *decoder, struct input_stream *is,
- const struct tag *tag)
+ const Tag *tag)
{
G_GNUC_UNUSED const struct decoder_control *dc = decoder->dc;
enum decoder_command cmd;
@@ -485,9 +482,8 @@ decoder_tag(G_GNUC_UNUSED struct decoder *decoder, struct input_stream *is,
/* save the tag */
- if (decoder->decoder_tag != NULL)
- tag_free(decoder->decoder_tag);
- decoder->decoder_tag = tag_dup(tag);
+ delete decoder->decoder_tag;
+ decoder->decoder_tag = new Tag(*tag);
/* check for a new stream tag */
@@ -505,14 +501,15 @@ decoder_tag(G_GNUC_UNUSED struct decoder *decoder, struct input_stream *is,
if (decoder->stream_tag != NULL) {
/* merge with tag from input stream */
- struct tag *merged;
+ Tag *merged;
- merged = tag_merge(decoder->stream_tag, decoder->decoder_tag);
- cmd = do_send_tag(decoder, merged);
- tag_free(merged);
+ merged = Tag::Merge(*decoder->stream_tag,
+ *decoder->decoder_tag);
+ cmd = do_send_tag(decoder, *merged);
+ delete merged;
} else
/* send only the decoder tag */
- cmd = do_send_tag(decoder, tag);
+ cmd = do_send_tag(decoder, *tag);
return cmd;
}
diff --git a/src/DecoderAPI.hxx b/src/DecoderAPI.hxx
index 79d733649..d4886d062 100644
--- a/src/DecoderAPI.hxx
+++ b/src/DecoderAPI.hxx
@@ -32,7 +32,7 @@
#include "DecoderPlugin.hxx"
#include "input_stream.h"
#include "replay_gain_info.h"
-#include "tag.h"
+#include "Tag.hxx"
#include "audio_format.h"
#include "conf.h"
@@ -142,7 +142,7 @@ decoder_data(struct decoder *decoder, struct input_stream *is,
*/
enum decoder_command
decoder_tag(struct decoder *decoder, struct input_stream *is,
- const struct tag *tag);
+ const Tag *tag);
/**
* Set replay gain values for the following chunks.
diff --git a/src/DecoderBuffer.cxx b/src/DecoderBuffer.cxx
index 0cc20450f..2125bbebd 100644
--- a/src/DecoderBuffer.cxx
+++ b/src/DecoderBuffer.cxx
@@ -24,6 +24,7 @@
#include <glib.h>
#include <assert.h>
+#include <string.h>
struct DecoderBuffer {
struct decoder *decoder;
diff --git a/src/DecoderInternal.cxx b/src/DecoderInternal.cxx
index e390fdfd7..6c703e227 100644
--- a/src/DecoderInternal.cxx
+++ b/src/DecoderInternal.cxx
@@ -23,7 +23,7 @@
#include "MusicPipe.hxx"
#include "MusicBuffer.hxx"
#include "MusicChunk.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include <assert.h>
@@ -32,14 +32,9 @@ decoder::~decoder()
/* caller must flush the chunk */
assert(chunk == nullptr);
- if (song_tag != nullptr)
- tag_free(song_tag);
-
- if (stream_tag != nullptr)
- tag_free(stream_tag);
-
- if (decoder_tag != nullptr)
- tag_free(decoder_tag);
+ delete song_tag;
+ delete stream_tag;
+ delete decoder_tag;
}
/**
diff --git a/src/DecoderInternal.hxx b/src/DecoderInternal.hxx
index 02ead763b..3715ef427 100644
--- a/src/DecoderInternal.hxx
+++ b/src/DecoderInternal.hxx
@@ -25,6 +25,7 @@
#include "replay_gain_info.h"
struct input_stream;
+struct Tag;
struct decoder {
struct decoder_control *dc;
@@ -62,13 +63,13 @@ struct decoder {
* files, because we expect the stream server to send us a new
* tag each time we play it.
*/
- struct tag *song_tag;
+ Tag *song_tag;
/** the last tag received from the stream */
- struct tag *stream_tag;
+ Tag *stream_tag;
/** the last tag received from the decoder plugin */
- struct tag *decoder_tag;
+ Tag *decoder_tag;
/** the chunk currently being written to */
struct music_chunk *chunk;
@@ -81,8 +82,7 @@ struct decoder {
*/
unsigned replay_gain_serial;
- decoder(decoder_control *_dc, bool _initial_seek_pending,
- struct tag *_tag)
+ decoder(decoder_control *_dc, bool _initial_seek_pending, Tag *_tag)
:dc(_dc),
timestamp(0),
initial_seek_pending(_initial_seek_pending),
diff --git a/src/DecoderPlugin.hxx b/src/DecoderPlugin.hxx
index 37e0d28d7..b250c4274 100644
--- a/src/DecoderPlugin.hxx
+++ b/src/DecoderPlugin.hxx
@@ -22,7 +22,7 @@
struct config_param;
struct input_stream;
-struct tag;
+struct Tag;
struct tag_handler;
/**
diff --git a/src/DecoderThread.cxx b/src/DecoderThread.cxx
index 747319463..3ebd5653e 100644
--- a/src/DecoderThread.cxx
+++ b/src/DecoderThread.cxx
@@ -28,7 +28,7 @@
#include "Mapper.hxx"
#include "fs/Path.hxx"
#include "DecoderAPI.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include "InputStream.hxx"
#include "DecoderList.hxx"
#include "util/UriUtil.hxx"
@@ -381,7 +381,7 @@ decoder_run_song(struct decoder_control *dc,
{
decoder decoder(dc, dc->start_ms > 0,
song->tag != NULL && song->IsFile()
- ? tag_dup(song->tag) : nullptr);
+ ? new Tag(*song->tag) : nullptr);
int ret;
dc->state = DECODE_STATE_START;
diff --git a/src/DespotifyUtils.cxx b/src/DespotifyUtils.cxx
index c9a1edf0c..c45722379 100644
--- a/src/DespotifyUtils.cxx
+++ b/src/DespotifyUtils.cxx
@@ -18,7 +18,7 @@
*/
#include "DespotifyUtils.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include "conf.h"
#include <glib.h>
@@ -77,14 +77,14 @@ void mpd_despotify_unregister_callback(void (*cb)(struct despotify_session *, in
}
-struct tag *mpd_despotify_tag_from_track(struct ds_track *track)
+Tag *
+mpd_despotify_tag_from_track(struct ds_track *track)
{
char tracknum[20];
char comment[80];
char date[20];
- struct tag *tag;
- tag = tag_new();
+ Tag *tag = new Tag();
if (!track->has_meta_data)
return tag;
@@ -93,12 +93,12 @@ struct tag *mpd_despotify_tag_from_track(struct ds_track *track)
g_snprintf(date, sizeof(date), "%d", track->year);
g_snprintf(comment, sizeof(comment), "Bitrate %d Kbps, %sgeo restricted",
track->file_bitrate / 1000, track->geo_restricted ? "" : "not ");
- tag_add_item(tag, TAG_TITLE, track->title);
- tag_add_item(tag, TAG_ARTIST, track->artist->name);
- tag_add_item(tag, TAG_TRACK, tracknum);
- tag_add_item(tag, TAG_ALBUM, track->album);
- tag_add_item(tag, TAG_DATE, date);
- tag_add_item(tag, TAG_COMMENT, comment);
+ tag->AddItem(TAG_TITLE, track->title);
+ tag->AddItem(TAG_ARTIST, track->artist->name);
+ tag->AddItem(TAG_TRACK, tracknum);
+ tag->AddItem(TAG_ALBUM, track->album);
+ tag->AddItem(TAG_DATE, date);
+ tag->AddItem(TAG_COMMENT, comment);
tag->time = track->length / 1000;
return tag;
diff --git a/src/DespotifyUtils.hxx b/src/DespotifyUtils.hxx
index 7e35edc3c..2d78844c0 100644
--- a/src/DespotifyUtils.hxx
+++ b/src/DespotifyUtils.hxx
@@ -20,6 +20,7 @@
#ifndef MPD_DESPOTIFY_H
#define MPD_DESPOTIFY_H
+struct Tag;
struct despotify_session;
struct ds_track;
@@ -41,7 +42,8 @@ struct despotify_session *mpd_despotify_get_session(void);
*
* @return a pointer to the filled in tags structure
*/
-struct tag *mpd_despotify_tag_from_track(struct ds_track *track);
+Tag *
+mpd_despotify_tag_from_track(struct ds_track *track);
/**
* Register a despotify callback.
diff --git a/src/EncoderAPI.hxx b/src/EncoderAPI.hxx
index bd874fa41..d35955f1b 100644
--- a/src/EncoderAPI.hxx
+++ b/src/EncoderAPI.hxx
@@ -27,7 +27,7 @@
#include "EncoderPlugin.hxx"
#include "audio_format.h"
-#include "tag.h"
+#include "Tag.hxx"
#include "conf.h"
#endif
diff --git a/src/EncoderPlugin.hxx b/src/EncoderPlugin.hxx
index 9336b2693..868a9998c 100644
--- a/src/EncoderPlugin.hxx
+++ b/src/EncoderPlugin.hxx
@@ -29,7 +29,7 @@
struct EncoderPlugin;
struct audio_format;
struct config_param;
-struct tag;
+struct Tag;
struct Encoder {
const EncoderPlugin &plugin;
@@ -66,7 +66,7 @@ struct EncoderPlugin {
bool (*pre_tag)(Encoder *encoder, GError **error);
- bool (*tag)(Encoder *encoder, const struct tag *tag,
+ bool (*tag)(Encoder *encoder, const Tag *tag,
GError **error);
bool (*write)(Encoder *encoder,
@@ -246,7 +246,7 @@ encoder_pre_tag(Encoder *encoder, GError **error)
* @return true on success
*/
static inline bool
-encoder_tag(Encoder *encoder, const struct tag *tag, GError **error)
+encoder_tag(Encoder *encoder, const Tag *tag, GError **error)
{
assert(encoder->open);
assert(!encoder->pre_tag);
diff --git a/src/IcyMetaDataParser.cxx b/src/IcyMetaDataParser.cxx
index cda63da44..6e1e18a51 100644
--- a/src/IcyMetaDataParser.cxx
+++ b/src/IcyMetaDataParser.cxx
@@ -19,7 +19,7 @@
#include "config.h"
#include "IcyMetaDataParser.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include <glib.h>
@@ -38,8 +38,7 @@ IcyMetaDataParser::Reset()
if (data_rest == 0 && meta_size > 0)
g_free(meta_data);
- if (tag != nullptr)
- tag_free(tag);
+ delete tag;
data_rest = data_size;
meta_size = 0;
@@ -66,7 +65,7 @@ IcyMetaDataParser::Data(size_t length)
}
static void
-icy_add_item(struct tag *tag, enum tag_type type, const char *value)
+icy_add_item(Tag &tag, enum tag_type type, const char *value)
{
size_t length = strlen(value);
@@ -77,11 +76,11 @@ icy_add_item(struct tag *tag, enum tag_type type, const char *value)
}
if (length > 0)
- tag_add_item_n(tag, type, value, length);
+ tag.AddItem(type, value, length);
}
static void
-icy_parse_tag_item(struct tag *tag, const char *item)
+icy_parse_tag_item(Tag &tag, const char *item)
{
gchar **p = g_strsplit(item, "=", 0);
@@ -95,14 +94,14 @@ icy_parse_tag_item(struct tag *tag, const char *item)
g_strfreev(p);
}
-static struct tag *
+static Tag *
icy_parse_tag(const char *p)
{
- struct tag *tag = tag_new();
+ Tag *tag = new Tag();
gchar **items = g_strsplit(p, ";", 0);
for (unsigned i = 0; items[i] != nullptr; ++i)
- icy_parse_tag_item(tag, items[i]);
+ icy_parse_tag_item(*tag, items[i]);
g_strfreev(items);
@@ -157,8 +156,7 @@ IcyMetaDataParser::Meta(const void *data, size_t length)
/* parse */
- if (tag != nullptr)
- tag_free(tag);
+ delete tag;
tag = icy_parse_tag(meta_data);
g_free(meta_data);
diff --git a/src/IcyMetaDataParser.hxx b/src/IcyMetaDataParser.hxx
index 6ccc73f52..6bcb09668 100644
--- a/src/IcyMetaDataParser.hxx
+++ b/src/IcyMetaDataParser.hxx
@@ -22,13 +22,15 @@
#include <stddef.h>
+struct Tag;
+
class IcyMetaDataParser {
size_t data_size, data_rest;
size_t meta_size, meta_position;
char *meta_data;
- struct tag *tag;
+ Tag *tag;
public:
IcyMetaDataParser():data_size(0) {}
@@ -73,8 +75,8 @@ public:
*/
size_t Meta(const void *data, size_t length);
- struct tag *ReadTag() {
- struct tag *result = tag;
+ Tag *ReadTag() {
+ Tag *result = tag;
tag = nullptr;
return result;
}
diff --git a/src/IcyMetaDataServer.cxx b/src/IcyMetaDataServer.cxx
index 8f02acacb..d0ae0b77a 100644
--- a/src/IcyMetaDataServer.cxx
+++ b/src/IcyMetaDataServer.cxx
@@ -20,11 +20,12 @@
#include "config.h"
#include "IcyMetaDataServer.hxx"
#include "Page.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include <glib.h>
#include <assert.h>
+#include <string.h>
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "icy_server"
@@ -87,7 +88,7 @@ icy_server_metadata_string(const char *stream_title, const char* stream_url)
}
Page *
-icy_server_metadata_page(const struct tag *tag, const enum tag_type *types)
+icy_server_metadata_page(const Tag &tag, const enum tag_type *types)
{
const gchar *tag_items[TAG_NUM_OF_ITEM_TYPES];
gint last_item, item;
@@ -101,7 +102,7 @@ icy_server_metadata_page(const struct tag *tag, const enum tag_type *types)
last_item = -1;
while (*types != TAG_NUM_OF_ITEM_TYPES) {
- const gchar *tag_item = tag_get_value(tag, *types++);
+ const gchar *tag_item = tag.GetValue(*types++);
if (tag_item)
tag_items[++last_item] = tag_item;
}
diff --git a/src/IcyMetaDataServer.hxx b/src/IcyMetaDataServer.hxx
index 3ff493017..ee685adcf 100644
--- a/src/IcyMetaDataServer.hxx
+++ b/src/IcyMetaDataServer.hxx
@@ -22,6 +22,7 @@
#include "TagType.h"
+struct Tag;
class Page;
char*
@@ -30,6 +31,6 @@ icy_server_metadata_header(const char *name,
const char *content_type, int metaint);
Page *
-icy_server_metadata_page(const struct tag *tag, const enum tag_type *types);
+icy_server_metadata_page(const Tag &tag, const enum tag_type *types);
#endif
diff --git a/src/InputPlugin.hxx b/src/InputPlugin.hxx
index c16600810..a5cf912da 100644
--- a/src/InputPlugin.hxx
+++ b/src/InputPlugin.hxx
@@ -66,7 +66,7 @@ struct input_plugin {
*/
void (*update)(struct input_stream *is);
- struct tag *(*tag)(struct input_stream *is);
+ Tag *(*tag)(struct input_stream *is);
/**
* Returns true if the next read operation will not block:
diff --git a/src/InputStream.cxx b/src/InputStream.cxx
index c079b4961..872d54fb7 100644
--- a/src/InputStream.cxx
+++ b/src/InputStream.cxx
@@ -182,7 +182,7 @@ input_stream_lock_seek(struct input_stream *is, goffset offset, int whence,
return input_stream_seek(is, offset, whence, error_r);
}
-struct tag *
+Tag *
input_stream_tag(struct input_stream *is)
{
assert(is != NULL);
@@ -192,7 +192,7 @@ input_stream_tag(struct input_stream *is)
: NULL;
}
-struct tag *
+Tag *
input_stream_lock_tag(struct input_stream *is)
{
assert(is != NULL);
diff --git a/src/Main.cxx b/src/Main.cxx
index 47160a575..1cde2a908 100644
--- a/src/Main.cxx
+++ b/src/Main.cxx
@@ -38,7 +38,7 @@
#include "Partition.hxx"
#include "Volume.hxx"
#include "OutputAll.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include "conf.h"
#include "replay_gain_config.h"
#include "Idle.hxx"
diff --git a/src/MusicChunk.cxx b/src/MusicChunk.cxx
index eefda24b5..55d2f7f30 100644
--- a/src/MusicChunk.cxx
+++ b/src/MusicChunk.cxx
@@ -20,14 +20,13 @@
#include "config.h"
#include "MusicChunk.hxx"
#include "audio_format.h"
-#include "tag.h"
+#include "Tag.hxx"
#include <assert.h>
music_chunk::~music_chunk()
{
- if (tag != NULL)
- tag_free(tag);
+ delete tag;
}
#ifndef NDEBUG
diff --git a/src/MusicChunk.hxx b/src/MusicChunk.hxx
index c03e45517..a15b3a702 100644
--- a/src/MusicChunk.hxx
+++ b/src/MusicChunk.hxx
@@ -34,6 +34,7 @@ enum {
};
struct audio_format;
+struct Tag;
/**
* A chunk of music data. Its format is defined by the
@@ -70,7 +71,7 @@ struct music_chunk {
* object is owned by this chunk, and must be freed when this
* chunk is deinitialized in music_chunk_free()
*/
- struct tag *tag;
+ Tag *tag;
/**
* Replay gain information associated with this chunk.
diff --git a/src/OutputAPI.hxx b/src/OutputAPI.hxx
index 3aa4f7567..951d723ea 100644
--- a/src/OutputAPI.hxx
+++ b/src/OutputAPI.hxx
@@ -23,7 +23,7 @@
#include "OutputPlugin.hxx"
#include "OutputInternal.hxx"
#include "audio_format.h"
-#include "tag.h"
+#include "Tag.hxx"
#include "conf.h"
#endif
diff --git a/src/OutputInit.cxx b/src/OutputInit.cxx
index 6f637f538..da243b54a 100644
--- a/src/OutputInit.cxx
+++ b/src/OutputInit.cxx
@@ -38,6 +38,7 @@
#include <glib.h>
#include <assert.h>
+#include <string.h>
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "output"
diff --git a/src/OutputList.cxx b/src/OutputList.cxx
index aebfcc963..670131ed9 100644
--- a/src/OutputList.cxx
+++ b/src/OutputList.cxx
@@ -37,6 +37,8 @@
#include "output/SolarisOutputPlugin.hxx"
#include "output/WinmmOutputPlugin.hxx"
+#include <string.h>
+
const struct audio_output_plugin *const audio_output_plugins[] = {
#ifdef HAVE_SHOUT
&shout_output_plugin,
diff --git a/src/OutputPlugin.cxx b/src/OutputPlugin.cxx
index 8482a1d4f..1e49ddbaa 100644
--- a/src/OutputPlugin.cxx
+++ b/src/OutputPlugin.cxx
@@ -75,7 +75,7 @@ ao_plugin_delay(struct audio_output *ao)
}
void
-ao_plugin_send_tag(struct audio_output *ao, const struct tag *tag)
+ao_plugin_send_tag(struct audio_output *ao, const Tag *tag)
{
if (ao->plugin->send_tag != NULL)
ao->plugin->send_tag(ao, tag);
diff --git a/src/OutputPlugin.hxx b/src/OutputPlugin.hxx
index 8bf34849d..8eb125029 100644
--- a/src/OutputPlugin.hxx
+++ b/src/OutputPlugin.hxx
@@ -27,7 +27,7 @@
struct config_param;
struct audio_format;
-struct tag;
+struct Tag;
/**
* A plugin which controls an audio output device.
@@ -111,7 +111,7 @@ struct audio_output_plugin {
* Display metadata for the next chunk. Optional method,
* because not all devices can display metadata.
*/
- void (*send_tag)(struct audio_output *data, const struct tag *tag);
+ void (*send_tag)(struct audio_output *data, const Tag *tag);
/**
* Play a chunk of audio data.
@@ -192,7 +192,7 @@ unsigned
ao_plugin_delay(struct audio_output *ao);
void
-ao_plugin_send_tag(struct audio_output *ao, const struct tag *tag);
+ao_plugin_send_tag(struct audio_output *ao, const Tag *tag);
size_t
ao_plugin_play(struct audio_output *ao, const void *chunk, size_t size,
diff --git a/src/OutputThread.cxx b/src/OutputThread.cxx
index 9bee3a821..a57fe7f60 100644
--- a/src/OutputThread.cxx
+++ b/src/OutputThread.cxx
@@ -37,6 +37,7 @@
#include <assert.h>
#include <stdlib.h>
+#include <string.h>
#include <errno.h>
#undef G_LOG_DOMAIN
diff --git a/src/PlayerThread.cxx b/src/PlayerThread.cxx
index 3033bce51..d838d4ba9 100644
--- a/src/PlayerThread.cxx
+++ b/src/PlayerThread.cxx
@@ -30,7 +30,7 @@
#include "CrossFade.hxx"
#include "PlayerControl.hxx"
#include "OutputAll.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include "Idle.hxx"
#include "GlobalEvents.hxx"
@@ -38,6 +38,8 @@
#include <glib.h>
+#include <string.h>
+
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "player_thread"
@@ -108,7 +110,7 @@ struct player {
* postponed, and sent to the output thread when the new song
* really begins.
*/
- struct tag *cross_fade_tag;
+ Tag *cross_fade_tag;
/**
* The current audio format for the audio outputs.
@@ -656,18 +658,17 @@ static void player_process_command(struct player *player)
}
static void
-update_song_tag(Song *song, const struct tag *new_tag)
+update_song_tag(Song *song, const Tag &new_tag)
{
if (song->IsFile())
/* don't update tags of local files, only remote
streams may change tags dynamically */
return;
- struct tag *old_tag = song->tag;
- song->tag = tag_dup(new_tag);
+ Tag *old_tag = song->tag;
+ song->tag = new Tag(new_tag);
- if (old_tag != NULL)
- tag_free(old_tag);
+ delete old_tag;
/* the main thread will update the playlist version when he
receives this event */
@@ -694,7 +695,7 @@ play_chunk(struct player_control *pc,
assert(chunk->CheckFormat(*format));
if (chunk->tag != NULL)
- update_song_tag(song, chunk->tag);
+ update_song_tag(song, *chunk->tag);
if (chunk->length == 0) {
music_buffer_return(player_buffer, chunk);
@@ -760,7 +761,7 @@ play_next_chunk(struct player *player)
is being faded in) yet; postpone it until
the current song is faded out */
player->cross_fade_tag =
- tag_merge_replace(player->cross_fade_tag,
+ Tag::MergeReplace(player->cross_fade_tag,
other_chunk->tag);
other_chunk->tag = NULL;
@@ -815,7 +816,7 @@ play_next_chunk(struct player *player)
/* insert the postponed tag if cross-fading is finished */
if (player->xfade != XFADE_ENABLED && player->cross_fade_tag != NULL) {
- chunk->tag = tag_merge_replace(chunk->tag,
+ chunk->tag = Tag::MergeReplace(chunk->tag,
player->cross_fade_tag);
player->cross_fade_tag = NULL;
}
@@ -1080,8 +1081,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
music_pipe_clear(player.pipe, player_buffer);
music_pipe_free(player.pipe);
- if (player.cross_fade_tag != NULL)
- tag_free(player.cross_fade_tag);
+ delete player.cross_fade_tag;
if (player.song != NULL)
player.song->Free();
diff --git a/src/PlaylistPlugin.hxx b/src/PlaylistPlugin.hxx
index 56adceedc..ea39f6258 100644
--- a/src/PlaylistPlugin.hxx
+++ b/src/PlaylistPlugin.hxx
@@ -27,7 +27,7 @@
struct config_param;
struct input_stream;
-struct tag;
+struct Tag;
struct Song;
/**
diff --git a/src/PlaylistSong.cxx b/src/PlaylistSong.cxx
index 510124215..5de1f5c8c 100644
--- a/src/PlaylistSong.cxx
+++ b/src/PlaylistSong.cxx
@@ -23,7 +23,7 @@
#include "DatabasePlugin.hxx"
#include "DatabaseGlue.hxx"
#include "ls.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include "fs/Path.hxx"
#include "util/UriUtil.hxx"
#include "Song.hxx"
@@ -39,10 +39,10 @@ merge_song_metadata(Song *dest, const Song *base,
{
dest->tag = base->tag != NULL
? (add->tag != NULL
- ? tag_merge(base->tag, add->tag)
- : tag_dup(base->tag))
+ ? Tag::Merge(*base->tag, *add->tag)
+ : new Tag(*base->tag))
: (add->tag != NULL
- ? tag_dup(add->tag)
+ ? new Tag(*add->tag)
: NULL);
dest->mtime = base->mtime;
diff --git a/src/Song.cxx b/src/Song.cxx
index 90ddcf518..023d52071 100644
--- a/src/Song.cxx
+++ b/src/Song.cxx
@@ -20,11 +20,12 @@
#include "config.h"
#include "Song.hxx"
#include "Directory.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include <glib.h>
#include <assert.h>
+#include <string.h>
Directory detached_root;
@@ -94,7 +95,7 @@ Song::DupDetached() const
} else
song = song_alloc(uri, nullptr);
- song->tag = tag_dup(tag);
+ song->tag = tag != nullptr ? new Tag(*tag) : nullptr;
song->mtime = mtime;
song->start_ms = start_ms;
song->end_ms = end_ms;
@@ -105,8 +106,7 @@ Song::DupDetached() const
void
Song::Free()
{
- if (tag != nullptr)
- tag_free(tag);
+ delete tag;
g_free(this);
}
diff --git a/src/Song.hxx b/src/Song.hxx
index 30996ccda..c1122f43b 100644
--- a/src/Song.hxx
+++ b/src/Song.hxx
@@ -29,6 +29,8 @@
#define SONG_FILE "file: "
#define SONG_TIME "Time: "
+struct Tag;
+
/**
* A dummy #directory instance that is used for "detached" song
* copies.
@@ -46,7 +48,7 @@ struct Song {
*/
struct list_head siblings;
- struct tag *tag;
+ Tag *tag;
Directory *parent;
time_t mtime;
diff --git a/src/SongFilter.cxx b/src/SongFilter.cxx
index ce9cea246..c928c793d 100644
--- a/src/SongFilter.cxx
+++ b/src/SongFilter.cxx
@@ -20,11 +20,12 @@
#include "config.h"
#include "SongFilter.hxx"
#include "Song.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include <glib.h>
#include <assert.h>
+#include <string.h>
#include <stdlib.h>
#define LOCATE_TAG_FILE_KEY "file"
@@ -74,14 +75,14 @@ SongFilter::Item::StringMatch(const char *s) const
}
bool
-SongFilter::Item::Match(const tag_item &item) const
+SongFilter::Item::Match(const TagItem &item) const
{
return (tag == LOCATE_TAG_ANY_TYPE || (unsigned)item.type == tag) &&
StringMatch(item.value);
}
bool
-SongFilter::Item::Match(const struct tag &_tag) const
+SongFilter::Item::Match(const Tag &_tag) const
{
bool visited_types[TAG_NUM_OF_ITEM_TYPES];
std::fill(visited_types, visited_types + TAG_NUM_OF_ITEM_TYPES, false);
diff --git a/src/SongFilter.hxx b/src/SongFilter.hxx
index 2b53d4524..88378d710 100644
--- a/src/SongFilter.hxx
+++ b/src/SongFilter.hxx
@@ -29,8 +29,8 @@
#define LOCATE_TAG_FILE_TYPE TAG_NUM_OF_ITEM_TYPES+10
#define LOCATE_TAG_ANY_TYPE TAG_NUM_OF_ITEM_TYPES+20
-struct tag;
-struct tag_item;
+struct Tag;
+struct TagItem;
struct Song;
class SongFilter {
@@ -65,10 +65,10 @@ class SongFilter {
bool StringMatch(const char *s) const;
gcc_pure
- bool Match(const tag_item &tag_item) const;
+ bool Match(const TagItem &tag_item) const;
gcc_pure
- bool Match(const struct tag &tag) const;
+ bool Match(const Tag &tag) const;
gcc_pure
bool Match(const Song &song) const;
@@ -91,7 +91,7 @@ public:
bool Parse(unsigned argc, char *argv[], bool fold_case=false);
gcc_pure
- bool Match(const tag &tag) const;
+ bool Match(const Tag &tag) const;
gcc_pure
bool Match(const Song &song) const;
diff --git a/src/SongPrint.cxx b/src/SongPrint.cxx
index b6b66e1f6..65d27ca77 100644
--- a/src/SongPrint.cxx
+++ b/src/SongPrint.cxx
@@ -69,6 +69,6 @@ song_print_info(Client *client, Song *song)
if (song->mtime > 0)
time_print(client, "Last-Modified", song->mtime);
- if (song->tag)
- tag_print(client, song->tag);
+ if (song->tag != nullptr)
+ tag_print(client, *song->tag);
}
diff --git a/src/SongSave.cxx b/src/SongSave.cxx
index d6860d1b0..fcad320df 100644
--- a/src/SongSave.cxx
+++ b/src/SongSave.cxx
@@ -23,7 +23,7 @@
#include "TagSave.hxx"
#include "Directory.hxx"
#include "TextFile.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include "util/StringUtil.hxx"
#include <glib.h>
@@ -52,8 +52,8 @@ song_save(FILE *fp, const Song *song)
else if (song->start_ms > 0)
fprintf(fp, "Range: %u-\n", song->start_ms);
- if (song->tag != NULL)
- tag_save(fp, song->tag);
+ if (song->tag != nullptr)
+ tag_save(fp, *song->tag);
fprintf(fp, SONG_MTIME ": %li\n", (long)song->mtime);
fprintf(fp, SONG_END "\n");
@@ -75,7 +75,7 @@ song_load(TextFile &file, Directory *parent, const char *uri,
colon = strchr(line, ':');
if (colon == NULL || colon == line) {
if (song->tag != NULL)
- tag_end_add(song->tag);
+ song->tag->EndAdd();
song->Free();
g_set_error(error_r, song_save_quark(), 0,
@@ -88,22 +88,22 @@ song_load(TextFile &file, Directory *parent, const char *uri,
if ((type = tag_name_parse(line)) != TAG_NUM_OF_ITEM_TYPES) {
if (!song->tag) {
- song->tag = tag_new();
- tag_begin_add(song->tag);
+ song->tag = new Tag();
+ song->tag->BeginAdd();
}
- tag_add_item(song->tag, type, value);
+ song->tag->AddItem(type, value);
} else if (strcmp(line, "Time") == 0) {
if (!song->tag) {
- song->tag = tag_new();
- tag_begin_add(song->tag);
+ song->tag = new Tag();
+ song->tag->BeginAdd();
}
song->tag->time = atoi(value);
} else if (strcmp(line, "Playlist") == 0) {
if (!song->tag) {
- song->tag = tag_new();
- tag_begin_add(song->tag);
+ song->tag = new Tag();
+ song->tag->BeginAdd();
}
song->tag->has_playlist = strcmp(value, "yes") == 0;
@@ -117,7 +117,7 @@ song_load(TextFile &file, Directory *parent, const char *uri,
song->end_ms = strtoul(endptr + 1, NULL, 10);
} else {
if (song->tag != NULL)
- tag_end_add(song->tag);
+ song->tag->EndAdd();
song->Free();
g_set_error(error_r, song_save_quark(), 0,
@@ -127,7 +127,7 @@ song_load(TextFile &file, Directory *parent, const char *uri,
}
if (song->tag != NULL)
- tag_end_add(song->tag);
+ song->tag->EndAdd();
return song;
}
diff --git a/src/SongSort.cxx b/src/SongSort.cxx
index 299a72042..0c154c763 100644
--- a/src/SongSort.cxx
+++ b/src/SongSort.cxx
@@ -21,7 +21,7 @@
#include "SongSort.hxx"
#include "Song.hxx"
#include "util/list.h"
-#include "tag.h"
+#include "Tag.hxx"
extern "C" {
#include "util/list_sort.h"
@@ -33,10 +33,10 @@ extern "C" {
#include <stdlib.h>
static const char *
-tag_get_value_checked(const struct tag *tag, enum tag_type type)
+tag_get_value_checked(const Tag *tag, enum tag_type type)
{
return tag != NULL
- ? tag_get_value(tag, type)
+ ? tag->GetValue(type)
: NULL;
}
@@ -57,7 +57,7 @@ compare_utf8_string(const char *a, const char *b)
* NULL.
*/
static int
-compare_string_tag_item(const struct tag *a, const struct tag *b,
+compare_string_tag_item(const Tag *a, const Tag *b,
enum tag_type type)
{
return compare_utf8_string(tag_get_value_checked(a, type),
@@ -84,7 +84,7 @@ compare_number_string(const char *a, const char *b)
}
static int
-compare_tag_item(const struct tag *a, const struct tag *b, enum tag_type type)
+compare_tag_item(const Tag *a, const Tag *b, enum tag_type type)
{
return compare_number_string(tag_get_value_checked(a, type),
tag_get_value_checked(b, type));
diff --git a/src/SongUpdate.cxx b/src/SongUpdate.cxx
index 13d08fecc..9c4d44227 100644
--- a/src/SongUpdate.cxx
+++ b/src/SongUpdate.cxx
@@ -24,7 +24,7 @@
#include "Mapper.hxx"
#include "fs/Path.hxx"
#include "fs/FileSystem.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include "input_stream.h"
#include "DecoderPlugin.hxx"
#include "DecoderList.hxx"
@@ -100,10 +100,8 @@ Song::UpdateFile()
if (path_fs.IsNull())
return false;
- if (tag != NULL) {
- tag_free(tag);
- tag = NULL;
- }
+ delete tag;
+ tag = nullptr;
if (!StatFile(path_fs, st) || !S_ISREG(st.st_mode)) {
return false;
@@ -116,12 +114,12 @@ Song::UpdateFile()
do {
/* load file tag */
- tag = tag_new();
+ tag = new Tag();
if (decoder_plugin_scan_file(plugin, path_fs.c_str(),
&full_tag_handler, tag))
break;
- tag_free(tag);
+ delete tag;
tag = nullptr;
/* fall back to stream tag */
@@ -136,13 +134,13 @@ Song::UpdateFile()
/* now try the stream_tag() method */
if (is != NULL) {
- tag = tag_new();
+ tag = new Tag();
if (decoder_plugin_scan_stream(plugin, is,
&full_tag_handler,
tag))
break;
- tag_free(tag);
+ delete tag;
tag = nullptr;
input_stream_lock_seek(is, 0, SEEK_SET, NULL);
@@ -155,7 +153,7 @@ Song::UpdateFile()
if (is != NULL)
input_stream_close(is);
- if (tag != nullptr && tag_is_empty(tag))
+ if (tag != nullptr && tag->IsEmpty())
tag_scan_fallback(path_fs.c_str(), &full_tag_handler, tag);
return tag != nullptr;
@@ -179,13 +177,12 @@ Song::UpdateFileInArchive()
if (plugin == NULL)
return false;
- if (tag != nullptr)
- tag_free(tag);
+ delete tag;
//accept every file that has music suffix
//because we don't support tag reading through
//input streams
- tag = tag_new();
+ tag = new Tag();
return true;
}
diff --git a/src/Tag.cxx b/src/Tag.cxx
index 0cf9c32c7..b473c367e 100644
--- a/src/Tag.cxx
+++ b/src/Tag.cxx
@@ -18,7 +18,7 @@
*/
#include "config.h"
-#include "tag.h"
+#include "Tag.hxx"
#include "TagInternal.hxx"
#include "TagPool.hxx"
#include "conf.h"
@@ -29,6 +29,7 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
/**
* Maximum number of items managed in the bulk list; if it is
@@ -40,7 +41,7 @@ static struct {
#ifndef NDEBUG
bool busy;
#endif
- struct tag_item *items[BULK_MAX];
+ TagItem *items[BULK_MAX];
} bulk;
bool ignore_tag_items[TAG_NUM_OF_ITEM_TYPES];
@@ -75,9 +76,10 @@ tag_name_parse_i(const char *name)
return TAG_NUM_OF_ITEM_TYPES;
}
-static size_t items_size(const struct tag *tag)
+static size_t
+items_size(const Tag &tag)
{
- return tag->num_items * sizeof(struct tag_item *);
+ return tag.num_items * sizeof(TagItem *);
}
void tag_lib_init(void)
@@ -130,127 +132,101 @@ void tag_lib_init(void)
g_free(temp);
}
-struct tag *tag_new(void)
+void
+Tag::DeleteItem(unsigned idx)
{
- struct tag *ret = g_new(struct tag, 1);
- ret->items = nullptr;
- ret->time = -1;
- ret->has_playlist = false;
- ret->num_items = 0;
- return ret;
-}
-
-static void tag_delete_item(struct tag *tag, unsigned idx)
-{
- assert(idx < tag->num_items);
- tag->num_items--;
+ assert(idx < num_items);
+ --num_items;
tag_pool_lock.lock();
- tag_pool_put_item(tag->items[idx]);
+ tag_pool_put_item(items[idx]);
tag_pool_lock.unlock();
- if (tag->num_items - idx > 0) {
- memmove(tag->items + idx, tag->items + idx + 1,
- (tag->num_items - idx) * sizeof(tag->items[0]));
+ if (num_items - idx > 0) {
+ memmove(items + idx, items + idx + 1,
+ (num_items - idx) * sizeof(items[0]));
}
- if (tag->num_items > 0) {
- tag->items = (struct tag_item **)
- g_realloc(tag->items, items_size(tag));
+ if (num_items > 0) {
+ items = (TagItem **)
+ g_realloc(items, items_size(*this));
} else {
- g_free(tag->items);
- tag->items = nullptr;
+ g_free(items);
+ items = nullptr;
}
}
-void tag_clear_items_by_type(struct tag *tag, enum tag_type type)
+void
+Tag::ClearItemsByType(tag_type type)
{
- for (unsigned i = 0; i < tag->num_items; i++) {
- if (tag->items[i]->type == type) {
- tag_delete_item(tag, i);
+ for (unsigned i = 0; i < num_items; i++) {
+ if (items[i]->type == type) {
+ DeleteItem(i);
/* decrement since when just deleted this node */
i--;
}
}
}
-void tag_free(struct tag *tag)
+Tag::~Tag()
{
- int i;
-
- assert(tag != nullptr);
-
tag_pool_lock.lock();
- for (i = tag->num_items; --i >= 0; )
- tag_pool_put_item(tag->items[i]);
+ for (int i = num_items; --i >= 0; )
+ tag_pool_put_item(items[i]);
tag_pool_lock.unlock();
- if (tag->items == bulk.items) {
+ if (items == bulk.items) {
#ifndef NDEBUG
assert(bulk.busy);
bulk.busy = false;
#endif
} else
- g_free(tag->items);
-
- g_free(tag);
+ g_free(items);
}
-struct tag *tag_dup(const struct tag *tag)
+Tag::Tag(const Tag &other)
+ :time(other.time), has_playlist(other.has_playlist),
+ items(nullptr),
+ num_items(other.num_items)
{
- struct tag *ret;
+ if (num_items > 0) {
+ items = (TagItem **)g_malloc(items_size(other));
- if (!tag)
- return nullptr;
-
- ret = tag_new();
- ret->time = tag->time;
- ret->has_playlist = tag->has_playlist;
- ret->num_items = tag->num_items;
- ret->items = ret->num_items > 0
- ? (struct tag_item **)g_malloc(items_size(tag))
- : nullptr;
-
- tag_pool_lock.lock();
- for (unsigned i = 0; i < tag->num_items; i++)
- ret->items[i] = tag_pool_dup_item(tag->items[i]);
- tag_pool_lock.unlock();
-
- return ret;
+ tag_pool_lock.lock();
+ for (unsigned i = 0; i < num_items; i++)
+ items[i] = tag_pool_dup_item(other.items[i]);
+ tag_pool_lock.unlock();
+ }
}
-struct tag *
-tag_merge(const struct tag *base, const struct tag *add)
+Tag *
+Tag::Merge(const Tag &base, const Tag &add)
{
- struct tag *ret;
unsigned n;
- assert(base != nullptr);
- assert(add != nullptr);
-
/* allocate new tag object */
- ret = tag_new();
- ret->time = add->time > 0 ? add->time : base->time;
- ret->num_items = base->num_items + add->num_items;
+ Tag *ret = new Tag();
+ ret->time = add.time > 0 ? add.time : base.time;
+ ret->num_items = base.num_items + add.num_items;
ret->items = ret->num_items > 0
- ? (struct tag_item **)g_malloc(items_size(ret))
+ ? (TagItem **)g_malloc(items_size(*ret))
: nullptr;
tag_pool_lock.lock();
/* copy all items from "add" */
- for (unsigned i = 0; i < add->num_items; ++i)
- ret->items[i] = tag_pool_dup_item(add->items[i]);
+ for (unsigned i = 0; i < add.num_items; ++i)
+ ret->items[i] = tag_pool_dup_item(add.items[i]);
- n = add->num_items;
+ n = add.num_items;
/* copy additional items from "base" */
- for (unsigned i = 0; i < base->num_items; ++i)
- if (!tag_has_type(add, base->items[i]->type))
- ret->items[n++] = tag_pool_dup_item(base->items[i]);
+ for (unsigned i = 0; i < base.num_items; ++i)
+ if (!add.HasType(base.items[i]->type))
+ ret->items[n++] = tag_pool_dup_item(base.items[i]);
tag_pool_lock.unlock();
@@ -261,15 +237,15 @@ tag_merge(const struct tag *base, const struct tag *add)
assert(n > 0);
ret->num_items = n;
- ret->items = (struct tag_item **)
- g_realloc(ret->items, items_size(ret));
+ ret->items = (TagItem **)
+ g_realloc(ret->items, items_size(*ret));
}
return ret;
}
-struct tag *
-tag_merge_replace(struct tag *base, struct tag *add)
+Tag *
+Tag::MergeReplace(Tag *base, Tag *add)
{
if (add == nullptr)
return base;
@@ -277,48 +253,44 @@ tag_merge_replace(struct tag *base, struct tag *add)
if (base == nullptr)
return add;
- struct tag *tag = tag_merge(base, add);
- tag_free(base);
- tag_free(add);
+ Tag *tag = Merge(*base, *add);
+ delete base;
+ delete add;
return tag;
}
const char *
-tag_get_value(const struct tag *tag, enum tag_type type)
+Tag::GetValue(tag_type type) const
{
- assert(tag != nullptr);
assert(type < TAG_NUM_OF_ITEM_TYPES);
- for (unsigned i = 0; i < tag->num_items; i++)
- if (tag->items[i]->type == type)
- return tag->items[i]->value;
+ for (unsigned i = 0; i < num_items; i++)
+ if (items[i]->type == type)
+ return items[i]->value;
return nullptr;
}
-bool tag_has_type(const struct tag *tag, enum tag_type type)
+bool
+Tag::HasType(tag_type type) const
{
- return tag_get_value(tag, type) != nullptr;
+ return GetValue(type) != nullptr;
}
-bool tag_equal(const struct tag *tag1, const struct tag *tag2)
+bool
+Tag::Equals(const Tag &other) const
{
- if (tag1 == nullptr && tag2 == nullptr)
- return true;
- else if (!tag1 || !tag2)
- return false;
-
- if (tag1->time != tag2->time)
+ if (time != other.time)
return false;
- if (tag1->num_items != tag2->num_items)
+ if (num_items != other.num_items)
return false;
- for (unsigned i = 0; i < tag1->num_items; i++) {
- if (tag1->items[i]->type != tag2->items[i]->type)
+ for (unsigned i = 0; i < num_items; i++) {
+ if (items[i]->type != other.items[i]->type)
return false;
- if (strcmp(tag1->items[i]->value, tag2->items[i]->value)) {
+ if (strcmp(items[i]->value, other.items[i]->value)) {
return false;
}
}
@@ -368,32 +340,33 @@ fix_utf8(const char *str, size_t length)
return patch_utf8(str, length, end);
}
-void tag_begin_add(struct tag *tag)
+void
+Tag::BeginAdd()
{
assert(!bulk.busy);
- assert(tag != nullptr);
- assert(tag->items == nullptr);
- assert(tag->num_items == 0);
+ assert(items == nullptr);
+ assert(num_items == 0);
#ifndef NDEBUG
bulk.busy = true;
#endif
- tag->items = bulk.items;
+ items = bulk.items;
}
-void tag_end_add(struct tag *tag)
+void
+Tag::EndAdd()
{
- if (tag->items == bulk.items) {
- assert(tag->num_items <= BULK_MAX);
+ if (items == bulk.items) {
+ assert(num_items <= BULK_MAX);
- if (tag->num_items > 0) {
+ if (num_items > 0) {
/* copy the tag items from the bulk list over
to a new list (which fits exactly) */
- tag->items = (struct tag_item **)
- g_malloc(items_size(tag));
- memcpy(tag->items, bulk.items, items_size(tag));
+ items = (TagItem **)
+ g_malloc(items_size(*this));
+ memcpy(items, bulk.items, items_size(*this));
} else
- tag->items = nullptr;
+ items = nullptr;
}
#ifndef NDEBUG
@@ -459,11 +432,10 @@ fix_tag_value(const char *p, size_t length)
return cleared;
}
-static void
-tag_add_item_internal(struct tag *tag, enum tag_type type,
- const char *value, size_t len)
+void
+Tag::AddItemInternal(tag_type type, const char *value, size_t len)
{
- unsigned int i = tag->num_items;
+ unsigned int i = num_items;
char *p;
p = fix_tag_value(value, len);
@@ -472,37 +444,42 @@ tag_add_item_internal(struct tag *tag, enum tag_type type,
len = strlen(value);
}
- tag->num_items++;
+ num_items++;
- if (tag->items != bulk.items)
+ if (items != bulk.items)
/* bulk mode disabled */
- tag->items = (struct tag_item **)
- g_realloc(tag->items, items_size(tag));
- else if (tag->num_items >= BULK_MAX) {
+ items = (TagItem **)
+ g_realloc(items, items_size(*this));
+ else if (num_items >= BULK_MAX) {
/* bulk list already full - switch back to non-bulk */
assert(bulk.busy);
- tag->items = (struct tag_item **)g_malloc(items_size(tag));
- memcpy(tag->items, bulk.items,
- items_size(tag) - sizeof(struct tag_item *));
+ items = (TagItem **)g_malloc(items_size(*this));
+ memcpy(items, bulk.items,
+ items_size(*this) - sizeof(TagItem *));
}
tag_pool_lock.lock();
- tag->items[i] = tag_pool_get_item(type, value, len);
+ items[i] = tag_pool_get_item(type, value, len);
tag_pool_lock.unlock();
g_free(p);
}
-void tag_add_item_n(struct tag *tag, enum tag_type type,
- const char *value, size_t len)
+void
+Tag::AddItem(tag_type type, const char *value, size_t len)
{
if (ignore_tag_items[type])
- {
return;
- }
- if (!value || !len)
+
+ if (value == nullptr || len == 0)
return;
- tag_add_item_internal(tag, type, value, len);
+ AddItemInternal(type, value, len);
+}
+
+void
+Tag::AddItem(tag_type type, const char *value)
+{
+ AddItem(type, value, strlen(value));
}
diff --git a/src/Tag.hxx b/src/Tag.hxx
new file mode 100644
index 000000000..5f1702994
--- /dev/null
+++ b/src/Tag.hxx
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2003-2013 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_HXX
+#define MPD_TAG_HXX
+
+#include "TagType.h"
+#include "gcc.h"
+
+#include <algorithm>
+
+#include <stddef.h>
+
+/**
+ * One tag value. It is a mapping of #tag_type to am arbitrary string
+ * value. Each tag can have multiple items of one tag type (although
+ * few clients support that).
+ */
+struct TagItem {
+ /** the type of this item */
+ enum tag_type type;
+
+ /**
+ * the value of this tag; this is a variable length string
+ */
+ char value[sizeof(long)];
+} gcc_packed;
+
+/**
+ * The meta information about a song file. It is a MPD specific
+ * subset of tags (e.g. from ID3, vorbis comments, ...).
+ */
+struct Tag {
+ /**
+ * The duration of the song (in seconds). A value of zero
+ * means that the length is unknown. If the duration is
+ * really between zero and one second, you should round up to
+ * 1.
+ */
+ int time;
+
+ /**
+ * Does this file have an embedded playlist (e.g. embedded CUE
+ * sheet)?
+ */
+ bool has_playlist;
+
+ /** an array of tag items */
+ TagItem **items;
+
+ /** the total number of tag items in the #items array */
+ unsigned num_items;
+
+ /**
+ * Create an empty tag.
+ */
+ Tag():time(-1), has_playlist(false),
+ items(nullptr), num_items(0) {}
+
+ Tag(const Tag &other);
+
+ Tag(Tag &&other)
+ :time(other.time), has_playlist(other.has_playlist),
+ items(other.items), num_items(other.num_items) {
+ other.items = nullptr;
+ other.num_items = 0;
+ }
+
+ /**
+ * Free the tag object and all its items.
+ */
+ ~Tag();
+
+ Tag &operator=(const Tag &other) = delete;
+
+ Tag &operator=(Tag &&other) {
+ time = other.time;
+ has_playlist = other.has_playlist;
+ std::swap(items, other.items);
+ std::swap(num_items, other.num_items);
+ return *this;
+ }
+
+ /**
+ * Returns true if the tag contains no items. This ignores the "time"
+ * attribute.
+ */
+ bool IsEmpty() const {
+ return num_items == 0;
+ }
+
+ /**
+ * Returns true if the tag contains any information.
+ */
+ bool IsDefined() const {
+ return !IsEmpty() || time >= 0;
+ }
+
+ void DeleteItem(unsigned i);
+
+ /**
+ * Clear all tag items with the specified type.
+ */
+ void ClearItemsByType(tag_type type);
+
+ /**
+ * Gives an optional hint to the tag library that we will now
+ * add several tag items; this is used by the library to
+ * optimize memory allocation. Only one tag may be in this
+ * state, and this tag must not have any items yet. You must
+ * call tag_end_add() when you are done.
+ */
+ void BeginAdd();
+
+ /**
+ * Finishes the operation started with tag_begin_add().
+ */
+ void EndAdd();
+
+ /**
+ * Appends a new tag item.
+ *
+ * @param type the type of the new tag item
+ * @param value the value of the tag item (not null-terminated)
+ * @param len the length of #value
+ */
+ void AddItem(tag_type type, const char *value, size_t len);
+
+ /**
+ * Appends a new tag item.
+ *
+ * @param tag the #tag object
+ * @param type the type of the new tag item
+ * @param value the value of the tag item (null-terminated)
+ */
+ void AddItem(tag_type type, const char *value);
+
+ /**
+ * Merges the data from two tags. If both tags share data for the
+ * same tag_type, only data from "add" is used.
+ *
+ * @return a newly allocated tag
+ */
+ gcc_malloc
+ static Tag *Merge(const Tag &base, const Tag &add);
+
+ /**
+ * Merges the data from two tags. Any of the two may be NULL. Both
+ * are freed by this function.
+ *
+ * @return a newly allocated tag
+ */
+ gcc_malloc
+ static Tag *MergeReplace(Tag *base, Tag *add);
+
+ /**
+ * Returns the first value of the specified tag type, or NULL if none
+ * is present in this tag object.
+ */
+ gcc_pure
+ const char *GetValue(tag_type type) const;
+
+ /**
+ * Checks whether the tag contains one or more items with
+ * the specified type.
+ */
+ bool HasType(tag_type type) const;
+
+ /**
+ * Compares two tags, including the duration and all tag items. The
+ * order of the tag items matters.
+ */
+ gcc_pure
+ bool Equals(const Tag &other) const;
+
+private:
+ void AddItemInternal(tag_type type, const char *value, size_t len);
+};
+
+/**
+ * Parse the string, and convert it into a #tag_type. Returns
+ * #TAG_NUM_OF_ITEM_TYPES if the string could not be recognized.
+ */
+enum tag_type
+tag_name_parse(const char *name);
+
+/**
+ * Parse the string, and convert it into a #tag_type. Returns
+ * #TAG_NUM_OF_ITEM_TYPES if the string could not be recognized.
+ *
+ * Case does not matter.
+ */
+enum tag_type
+tag_name_parse_i(const char *name);
+
+/**
+ * Initializes the tag library.
+ */
+void
+tag_lib_init();
+
+#endif
diff --git a/src/TagHandler.cxx b/src/TagHandler.cxx
index d3dfef497..227c48c9c 100644
--- a/src/TagHandler.cxx
+++ b/src/TagHandler.cxx
@@ -19,14 +19,14 @@
#include "config.h"
#include "TagHandler.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include <glib.h>
static void
add_tag_duration(unsigned seconds, void *ctx)
{
- struct tag *tag = (struct tag *)ctx;
+ Tag *tag = (Tag *)ctx;
tag->time = seconds;
}
@@ -34,9 +34,9 @@ add_tag_duration(unsigned seconds, void *ctx)
static void
add_tag_tag(enum tag_type type, const char *value, void *ctx)
{
- struct tag *tag = (struct tag *)ctx;
+ Tag *tag = (Tag *)ctx;
- tag_add_item(tag, type, value);
+ tag->AddItem(type, value);
}
const struct tag_handler add_tag_handler = {
@@ -48,7 +48,7 @@ const struct tag_handler add_tag_handler = {
static void
full_tag_pair(const char *name, G_GNUC_UNUSED const char *value, void *ctx)
{
- struct tag *tag = (struct tag *)ctx;
+ Tag *tag = (Tag *)ctx;
if (g_ascii_strcasecmp(name, "cuesheet") == 0)
tag->has_playlist = true;
diff --git a/src/TagId3.cxx b/src/TagId3.cxx
index 7f033b5c4..6b2174fe5 100644
--- a/src/TagId3.cxx
+++ b/src/TagId3.cxx
@@ -21,7 +21,7 @@
#include "TagId3.hxx"
#include "TagHandler.hxx"
#include "TagTable.hxx"
-#include "tag.h"
+#include "Tag.hxx"
extern "C" {
#include "riff.h"
@@ -385,14 +385,15 @@ scan_id3_tag(struct id3_tag *tag,
tag_id3_import_ufid(tag, handler, handler_ctx);
}
-struct tag *tag_id3_import(struct id3_tag * tag)
+Tag *
+tag_id3_import(struct id3_tag *tag)
{
- struct tag *ret = tag_new();
+ Tag *ret = new Tag();
scan_id3_tag(tag, &add_tag_handler, ret);
- if (tag_is_empty(ret)) {
- tag_free(ret);
+ if (ret->IsEmpty()) {
+ delete ret;
ret = nullptr;
}
diff --git a/src/TagId3.hxx b/src/TagId3.hxx
index 00824a3e4..d359306e9 100644
--- a/src/TagId3.hxx
+++ b/src/TagId3.hxx
@@ -25,7 +25,8 @@
#include "gerror.h"
struct tag_handler;
-struct tag;
+struct Tag;
+struct id3_tag;
#ifdef HAVE_ID3TAG
@@ -33,8 +34,8 @@ bool
tag_id3_scan(const char *path_fs,
const struct tag_handler *handler, void *handler_ctx);
-struct id3_tag;
-struct tag *tag_id3_import(struct id3_tag *);
+Tag *
+tag_id3_import(struct id3_tag *);
/**
* Loads the ID3 tags from the file into a libid3tag object. The
diff --git a/src/TagPool.cxx b/src/TagPool.cxx
index 030f90225..5a0b33c47 100644
--- a/src/TagPool.cxx
+++ b/src/TagPool.cxx
@@ -19,11 +19,12 @@
#include "config.h"
#include "TagPool.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include <glib.h>
#include <assert.h>
+#include <string.h>
Mutex tag_pool_lock;
@@ -32,7 +33,7 @@ Mutex tag_pool_lock;
struct slot {
struct slot *next;
unsigned char ref;
- struct tag_item item;
+ TagItem item;
} mpd_packed;
static struct slot *slots[NUM_SLOTS];
@@ -64,7 +65,7 @@ calc_hash(enum tag_type type, const char *p)
}
static inline struct slot *
-tag_item_to_slot(struct tag_item *item)
+tag_item_to_slot(TagItem *item)
{
return (struct slot*)(((char*)item) - offsetof(struct slot, item));
}
@@ -85,7 +86,7 @@ static struct slot *slot_alloc(struct slot *next,
return slot;
}
-struct tag_item *
+TagItem *
tag_pool_get_item(enum tag_type type, const char *value, size_t length)
{
struct slot **slot_p, *slot;
@@ -107,7 +108,8 @@ tag_pool_get_item(enum tag_type type, const char *value, size_t length)
return &slot->item;
}
-struct tag_item *tag_pool_dup_item(struct tag_item *item)
+TagItem *
+tag_pool_dup_item(TagItem *item)
{
struct slot *slot = tag_item_to_slot(item);
@@ -130,7 +132,8 @@ struct tag_item *tag_pool_dup_item(struct tag_item *item)
}
}
-void tag_pool_put_item(struct tag_item *item)
+void
+tag_pool_put_item(TagItem *item)
{
struct slot **slot_p, *slot;
diff --git a/src/TagPool.hxx b/src/TagPool.hxx
index 3a6897607..a6b28b355 100644
--- a/src/TagPool.hxx
+++ b/src/TagPool.hxx
@@ -25,13 +25,15 @@
extern Mutex tag_pool_lock;
-struct tag_item;
+struct TagItem;
-struct tag_item *
+TagItem *
tag_pool_get_item(enum tag_type type, const char *value, size_t length);
-struct tag_item *tag_pool_dup_item(struct tag_item *item);
+TagItem *
+tag_pool_dup_item(TagItem *item);
-void tag_pool_put_item(struct tag_item *item);
+void
+tag_pool_put_item(TagItem *item);
#endif
diff --git a/src/TagPrint.cxx b/src/TagPrint.cxx
index acbb14e8c..18490792c 100644
--- a/src/TagPrint.cxx
+++ b/src/TagPrint.cxx
@@ -19,7 +19,7 @@
#include "config.h"
#include "TagPrint.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include "TagInternal.hxx"
#include "Song.hxx"
#include "Client.hxx"
@@ -35,14 +35,14 @@ void tag_print_types(Client *client)
}
}
-void tag_print(Client *client, const struct tag *tag)
+void tag_print(Client *client, const Tag &tag)
{
- if (tag->time >= 0)
- client_printf(client, SONG_TIME "%i\n", tag->time);
+ if (tag.time >= 0)
+ client_printf(client, SONG_TIME "%i\n", tag.time);
- for (unsigned i = 0; i < tag->num_items; i++) {
+ for (unsigned i = 0; i < tag.num_items; i++) {
client_printf(client, "%s: %s\n",
- tag_item_names[tag->items[i]->type],
- tag->items[i]->value);
+ tag_item_names[tag.items[i]->type],
+ tag.items[i]->value);
}
}
diff --git a/src/TagPrint.hxx b/src/TagPrint.hxx
index 99e1d0850..48bfc72cc 100644
--- a/src/TagPrint.hxx
+++ b/src/TagPrint.hxx
@@ -20,11 +20,12 @@
#ifndef MPD_TAG_PRINT_HXX
#define MPD_TAG_PRINT_HXX
-struct tag;
+struct Tag;
class Client;
void tag_print_types(Client *client);
-void tag_print(Client *client, const struct tag *tag);
+void
+tag_print(Client *client, const Tag &tag);
#endif
diff --git a/src/TagSave.cxx b/src/TagSave.cxx
index 51ae53444..4a9b98a90 100644
--- a/src/TagSave.cxx
+++ b/src/TagSave.cxx
@@ -19,20 +19,21 @@
#include "config.h"
#include "TagSave.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include "TagInternal.hxx"
#include "Song.hxx"
-void tag_save(FILE *file, const struct tag *tag)
+void
+tag_save(FILE *file, const Tag &tag)
{
- if (tag->time >= 0)
- fprintf(file, SONG_TIME "%i\n", tag->time);
+ if (tag.time >= 0)
+ fprintf(file, SONG_TIME "%i\n", tag.time);
- if (tag->has_playlist)
+ if (tag.has_playlist)
fprintf(file, "Playlist: yes\n");
- for (unsigned i = 0; i < tag->num_items; i++)
+ for (unsigned i = 0; i < tag.num_items; i++)
fprintf(file, "%s: %s\n",
- tag_item_names[tag->items[i]->type],
- tag->items[i]->value);
+ tag_item_names[tag.items[i]->type],
+ tag.items[i]->value);
}
diff --git a/src/TagSave.hxx b/src/TagSave.hxx
index a7ccfa613..0b1359c89 100644
--- a/src/TagSave.hxx
+++ b/src/TagSave.hxx
@@ -22,8 +22,9 @@
#include <stdio.h>
-struct tag;
+struct Tag;
-void tag_save(FILE *file, const struct tag *tag);
+void
+tag_save(FILE *file, const Tag &tag);
#endif
diff --git a/src/UpdateContainer.cxx b/src/UpdateContainer.cxx
index 6a6d756aa..44c961a2b 100644
--- a/src/UpdateContainer.cxx
+++ b/src/UpdateContainer.cxx
@@ -28,7 +28,7 @@
#include "Mapper.hxx"
#include "fs/Path.hxx"
#include "TagHandler.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include <glib.h>
@@ -95,7 +95,7 @@ update_container_file(Directory *directory,
const Path child_path_fs =
map_directory_child_fs(contdir, vtrack);
- song->tag = tag_new();
+ song->tag = new Tag();
decoder_plugin_scan_file(plugin, child_path_fs.c_str(),
&add_tag_handler, song->tag);
diff --git a/src/cue/CueParser.cxx b/src/cue/CueParser.cxx
index ae1445abc..e2ae6f2dd 100644
--- a/src/cue/CueParser.cxx
+++ b/src/cue/CueParser.cxx
@@ -21,15 +21,16 @@
#include "CueParser.hxx"
#include "util/StringUtil.hxx"
#include "Song.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include <glib.h>
#include <assert.h>
+#include <string.h>
#include <stdlib.h>
CueParser::CueParser()
- :state(HEADER), tag(tag_new()),
+ :state(HEADER), tag(new Tag()),
filename(nullptr),
current(nullptr),
previous(nullptr),
@@ -38,7 +39,7 @@ CueParser::CueParser()
CueParser::~CueParser()
{
- tag_free(tag);
+ delete tag;
g_free(filename);
if (current != nullptr)
@@ -109,16 +110,16 @@ cue_next_value(char **pp)
}
static void
-cue_add_tag(struct tag *tag, enum tag_type type, char *p)
+cue_add_tag(Tag &tag, enum tag_type type, char *p)
{
const char *value = cue_next_value(&p);
if (value != nullptr)
- tag_add_item(tag, type, value);
+ tag.AddItem(type, value);
}
static void
-cue_parse_rem(char *p, struct tag *tag)
+cue_parse_rem(char *p, Tag &tag)
{
const char *type = cue_next_token(&p);
if (type == nullptr)
@@ -129,7 +130,7 @@ cue_parse_rem(char *p, struct tag *tag)
cue_add_tag(tag, type2, p);
}
-struct tag *
+Tag *
CueParser::GetCurrentTag()
{
if (state == HEADER)
@@ -188,9 +189,9 @@ CueParser::Feed2(char *p)
return;
if (strcmp(command, "REM") == 0) {
- struct tag *current_tag = GetCurrentTag();
+ Tag *current_tag = GetCurrentTag();
if (current_tag != nullptr)
- cue_parse_rem(p, current_tag);
+ cue_parse_rem(p, *current_tag);
} else if (strcmp(command, "PERFORMER") == 0) {
/* MPD knows a "performer" tag, but it is not a good
match for this CUE tag; from the Hydrogenaudio
@@ -202,14 +203,14 @@ CueParser::Feed2(char *p)
? TAG_ARTIST
: TAG_ALBUM_ARTIST;
- struct tag *current_tag = GetCurrentTag();
+ Tag *current_tag = GetCurrentTag();
if (current_tag != nullptr)
- cue_add_tag(current_tag, type, p);
+ cue_add_tag(*current_tag, type, p);
} else if (strcmp(command, "TITLE") == 0) {
if (state == HEADER)
- cue_add_tag(tag, TAG_ALBUM, p);
+ cue_add_tag(*tag, TAG_ALBUM, p);
else if (state == TRACK)
- cue_add_tag(current->tag, TAG_TITLE, p);
+ cue_add_tag(*current->tag, TAG_TITLE, p);
} else if (strcmp(command, "FILE") == 0) {
Commit();
@@ -252,8 +253,8 @@ CueParser::Feed2(char *p)
state = TRACK;
current = Song::NewRemote(filename);
assert(current->tag == nullptr);
- current->tag = tag_dup(tag);
- tag_add_item(current->tag, TAG_TRACK, nr);
+ current->tag = new Tag(*tag);
+ current->tag->AddItem(TAG_TRACK, nr);
last_updated = false;
} else if (state == IGNORE_TRACK) {
return;
diff --git a/src/cue/CueParser.hxx b/src/cue/CueParser.hxx
index ad2a6f34c..5cb51200f 100644
--- a/src/cue/CueParser.hxx
+++ b/src/cue/CueParser.hxx
@@ -24,6 +24,7 @@
#include "gcc.h"
struct Song;
+struct Tag;
class CueParser {
enum {
@@ -53,7 +54,7 @@ class CueParser {
IGNORE_TRACK,
} state;
- struct tag *tag;
+ Tag *tag;
char *filename;
@@ -115,7 +116,7 @@ public:
private:
gcc_pure
- struct tag *GetCurrentTag();
+ Tag *GetCurrentTag();
/**
* Commit the current song. It will be moved to "previous",
diff --git a/src/db/ProxyDatabasePlugin.cxx b/src/db/ProxyDatabasePlugin.cxx
index 21224e022..6acdb4170 100644
--- a/src/db/ProxyDatabasePlugin.cxx
+++ b/src/db/ProxyDatabasePlugin.cxx
@@ -26,7 +26,7 @@
#include "Song.hxx"
#include "gcc.h"
#include "conf.h"
-#include "tag.h"
+#include "Tag.hxx"
extern "C" {
#include "db_error.h"
@@ -256,7 +256,7 @@ Visit(struct mpd_connection *connection,
}
static void
-Copy(struct tag *tag, enum tag_type d_tag,
+Copy(Tag &tag, enum tag_type d_tag,
const struct mpd_song *song, enum mpd_tag_type s_tag)
{
@@ -265,7 +265,7 @@ Copy(struct tag *tag, enum tag_type d_tag,
if (value == NULL)
break;
- tag_add_item(tag, d_tag, value);
+ tag.AddItem(d_tag, value);
}
}
@@ -278,13 +278,13 @@ Convert(const struct mpd_song *song)
s->start_ms = mpd_song_get_start(song) * 1000;
s->end_ms = mpd_song_get_end(song) * 1000;
- struct tag *tag = tag_new();
+ Tag *tag = new Tag();
tag->time = mpd_song_get_duration(song);
- tag_begin_add(tag);
+ tag->BeginAdd();
for (const auto *i = &tag_table[0]; i->d != TAG_NUM_OF_ITEM_TYPES; ++i)
- Copy(tag, i->d, song, i->s);
- tag_end_add(tag);
+ Copy(*tag, i->d, song, i->s);
+ tag->EndAdd();
s->tag = tag;
diff --git a/src/decoder/DsdLib.cxx b/src/decoder/DsdLib.cxx
index cc23c490b..d18131184 100644
--- a/src/decoder/DsdLib.cxx
+++ b/src/decoder/DsdLib.cxx
@@ -31,6 +31,7 @@
#include "TagId3.hxx"
#include <unistd.h>
+#include <string.h>
#include <stdio.h> /* for SEEK_SET, SEEK_CUR */
#ifdef HAVE_ID3TAG
diff --git a/src/decoder/FaadDecoderPlugin.cxx b/src/decoder/FaadDecoderPlugin.cxx
index d87c48628..1b7edb49f 100644
--- a/src/decoder/FaadDecoderPlugin.cxx
+++ b/src/decoder/FaadDecoderPlugin.cxx
@@ -29,6 +29,7 @@
#include <glib.h>
#include <assert.h>
+#include <string.h>
#include <unistd.h>
#undef G_LOG_DOMAIN
diff --git a/src/decoder/FlacCommon.cxx b/src/decoder/FlacCommon.cxx
index 74a0347f2..6b6c20d3c 100644
--- a/src/decoder/FlacCommon.cxx
+++ b/src/decoder/FlacCommon.cxx
@@ -43,8 +43,7 @@ flac_data::flac_data(struct decoder *_decoder,
flac_data::~flac_data()
{
- if (tag != nullptr)
- tag_free(tag);
+ delete tag;
}
static enum sample_format
diff --git a/src/decoder/FlacCommon.hxx b/src/decoder/FlacCommon.hxx
index ca6c9a8f9..e3555efba 100644
--- a/src/decoder/FlacCommon.hxx
+++ b/src/decoder/FlacCommon.hxx
@@ -81,7 +81,7 @@ struct flac_data : public FlacInput {
struct decoder *decoder;
struct input_stream *input_stream;
- struct tag *tag;
+ Tag *tag;
flac_data(struct decoder *decoder, struct input_stream *input_stream);
~flac_data();
diff --git a/src/decoder/FlacDecoderPlugin.cxx b/src/decoder/FlacDecoderPlugin.cxx
index cd15b4b29..3bc50aa4e 100644
--- a/src/decoder/FlacDecoderPlugin.cxx
+++ b/src/decoder/FlacDecoderPlugin.cxx
@@ -172,11 +172,11 @@ flac_decoder_loop(struct flac_data *data, FLAC__StreamDecoder *flac_dec,
data->first_frame = t_start;
while (true) {
- if (data->tag != nullptr && !tag_is_empty(data->tag)) {
+ if (data->tag != nullptr && !data->tag->IsEmpty()) {
cmd = decoder_tag(data->decoder, data->input_stream,
data->tag);
- tag_free(data->tag);
- data->tag = tag_new();
+ delete data->tag;
+ data->tag = new Tag();
} else
cmd = decoder_get_command(decoder);
@@ -260,7 +260,7 @@ flac_decode_internal(struct decoder * decoder,
return;
struct flac_data data(decoder, input_stream);
- data.tag = tag_new();
+ data.tag = new Tag();
FLAC__StreamDecoderInitStatus status =
stream_init(flac_dec, &data, is_ogg);
diff --git a/src/decoder/FlacMetadata.cxx b/src/decoder/FlacMetadata.cxx
index 64f091c04..3c0120ab4 100644
--- a/src/decoder/FlacMetadata.cxx
+++ b/src/decoder/FlacMetadata.cxx
@@ -20,7 +20,7 @@
#include "config.h"
#include "FlacMetadata.hxx"
#include "XiphTags.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include "TagHandler.hxx"
#include "TagTable.hxx"
#include "replay_gain_info.h"
@@ -228,7 +228,7 @@ flac_scan_metadata(const FLAC__StreamMetadata *block,
}
void
-flac_vorbis_comments_to_tag(struct tag *tag,
+flac_vorbis_comments_to_tag(Tag *tag,
const FLAC__StreamMetadata_VorbisComment *comment)
{
flac_scan_comments(comment, &add_tag_handler, tag);
diff --git a/src/decoder/FlacMetadata.hxx b/src/decoder/FlacMetadata.hxx
index cce34c3a7..52c6abbce 100644
--- a/src/decoder/FlacMetadata.hxx
+++ b/src/decoder/FlacMetadata.hxx
@@ -109,7 +109,7 @@ public:
};
struct tag_handler;
-struct tag;
+struct Tag;
struct replay_gain_info;
static inline unsigned
@@ -130,7 +130,7 @@ flac_parse_mixramp(char **mixramp_start, char **mixramp_end,
const FLAC__StreamMetadata *block);
void
-flac_vorbis_comments_to_tag(struct tag *tag,
+flac_vorbis_comments_to_tag(Tag *tag,
const FLAC__StreamMetadata_VorbisComment *comment);
void
diff --git a/src/decoder/MadDecoderPlugin.cxx b/src/decoder/MadDecoderPlugin.cxx
index c9b2f0a6c..9f36fd86b 100644
--- a/src/decoder/MadDecoderPlugin.cxx
+++ b/src/decoder/MadDecoderPlugin.cxx
@@ -30,6 +30,7 @@
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
#include <glib.h>
#include <mad.h>
@@ -143,8 +144,8 @@ struct MadDecoder {
bool Seek(long offset);
bool FillBuffer();
- void ParseId3(size_t tagsize, struct tag **mpd_tag);
- enum mp3_action DecodeNextFrameHeader(struct tag **tag);
+ void ParseId3(size_t tagsize, Tag **mpd_tag);
+ enum mp3_action DecodeNextFrameHeader(Tag **tag);
enum mp3_action DecodeNextFrame();
gcc_pure
@@ -158,7 +159,7 @@ struct MadDecoder {
*/
void FileSizeToSongLength();
- bool DecodeFirstFrame(struct tag **tag);
+ bool DecodeFirstFrame(Tag **tag);
gcc_pure
long TimeToFrame(double t) const;
@@ -334,7 +335,7 @@ parse_id3_mixramp(char **mixramp_start, char **mixramp_end,
#endif
inline void
-MadDecoder::ParseId3(size_t tagsize, struct tag **mpd_tag)
+MadDecoder::ParseId3(size_t tagsize, Tag **mpd_tag)
{
#ifdef HAVE_ID3TAG
struct id3_tag *id3_tag = nullptr;
@@ -379,10 +380,9 @@ MadDecoder::ParseId3(size_t tagsize, struct tag **mpd_tag)
}
if (mpd_tag) {
- struct tag *tmp_tag = tag_id3_import(id3_tag);
+ Tag *tmp_tag = tag_id3_import(id3_tag);
if (tmp_tag != nullptr) {
- if (*mpd_tag != nullptr)
- tag_free(*mpd_tag);
+ delete *mpd_tag;
*mpd_tag = tmp_tag;
}
}
@@ -453,7 +453,7 @@ id3_tag_query(const void *p0, size_t length)
#endif /* !HAVE_ID3TAG */
enum mp3_action
-MadDecoder::DecodeNextFrameHeader(struct tag **tag)
+MadDecoder::DecodeNextFrameHeader(Tag **tag)
{
if ((stream.buffer == nullptr || stream.error == MAD_ERROR_BUFLEN) &&
!FillBuffer())
@@ -807,7 +807,7 @@ MadDecoder::FileSizeToSongLength()
}
inline bool
-MadDecoder::DecodeFirstFrame(struct tag **tag)
+MadDecoder::DecodeFirstFrame(Tag **tag)
{
struct xing xing;
struct lame lame;
@@ -1079,13 +1079,13 @@ MadDecoder::Read()
bool skip = false;
do {
- struct tag *tag = nullptr;
+ Tag *tag = nullptr;
ret = DecodeNextFrameHeader(&tag);
if (tag != nullptr) {
decoder_tag(decoder, input_stream, tag);
- tag_free(tag);
+ delete tag;
}
} while (ret == DECODE_CONT);
if (ret == DECODE_BREAK)
@@ -1113,10 +1113,9 @@ mp3_decode(struct decoder *decoder, struct input_stream *input_stream)
{
MadDecoder data(decoder, input_stream);
- struct tag *tag = nullptr;
+ Tag *tag = nullptr;
if (!data.DecodeFirstFrame(&tag)) {
- if (tag != nullptr)
- tag_free(tag);
+ delete tag;
if (decoder_get_command(decoder) == DECODE_COMMAND_NONE)
g_warning
@@ -1134,8 +1133,7 @@ mp3_decode(struct decoder *decoder, struct input_stream *input_stream)
g_warning("%s", error->message);
g_error_free(error);
- if (tag != nullptr)
- tag_free(tag);
+ delete tag;
return;
}
@@ -1145,7 +1143,7 @@ mp3_decode(struct decoder *decoder, struct input_stream *input_stream)
if (tag != nullptr) {
decoder_tag(decoder, input_stream, tag);
- tag_free(tag);
+ delete tag;
}
while (data.Read()) {}
diff --git a/src/decoder/OggCodec.cxx b/src/decoder/OggCodec.cxx
index 5ad9c69d6..d7e5b7642 100644
--- a/src/decoder/OggCodec.cxx
+++ b/src/decoder/OggCodec.cxx
@@ -24,6 +24,8 @@
#include "config.h"
#include "OggCodec.hxx"
+#include <string.h>
+
enum ogg_codec
ogg_codec_detect(struct decoder *decoder, struct input_stream *is)
{
diff --git a/src/decoder/OpusDecoderPlugin.cxx b/src/decoder/OpusDecoderPlugin.cxx
index 84467371c..148125347 100644
--- a/src/decoder/OpusDecoderPlugin.cxx
+++ b/src/decoder/OpusDecoderPlugin.cxx
@@ -36,6 +36,7 @@
#include <glib.h>
#include <stdio.h>
+#include <string.h>
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "opus"
@@ -221,16 +222,16 @@ MPDOpusDecoder::HandleBOS(const ogg_packet &packet)
inline enum decoder_command
MPDOpusDecoder::HandleTags(const ogg_packet &packet)
{
- struct tag *tag = tag_new();
+ Tag tag;
enum decoder_command cmd;
- if (ScanOpusTags(packet.packet, packet.bytes, &add_tag_handler, tag) &&
- !tag_is_empty(tag))
- cmd = decoder_tag(decoder, input_stream, tag);
+ if (ScanOpusTags(packet.packet, packet.bytes,
+ &add_tag_handler, &tag) &&
+ !tag.IsEmpty())
+ cmd = decoder_tag(decoder, input_stream, &tag);
else
cmd = decoder_get_command(decoder);
- tag_free(tag);
return cmd;
}
diff --git a/src/decoder/PcmDecoderPlugin.cxx b/src/decoder/PcmDecoderPlugin.cxx
index c86d0fa3b..f64357e68 100644
--- a/src/decoder/PcmDecoderPlugin.cxx
+++ b/src/decoder/PcmDecoderPlugin.cxx
@@ -27,6 +27,7 @@ extern "C" {
#include <glib.h>
#include <unistd.h>
+#include <string.h>
#include <stdio.h> /* for SEEK_SET */
#undef G_LOG_DOMAIN
diff --git a/src/decoder/VorbisComments.cxx b/src/decoder/VorbisComments.cxx
index a2bec30f1..88a8dc772 100644
--- a/src/decoder/VorbisComments.cxx
+++ b/src/decoder/VorbisComments.cxx
@@ -20,7 +20,7 @@
#include "config.h"
#include "VorbisComments.hxx"
#include "XiphTags.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include "TagTable.hxx"
#include "TagHandler.hxx"
#include "replay_gain_info.h"
@@ -135,14 +135,14 @@ vorbis_comments_scan(char **comments,
}
-struct tag *
+Tag *
vorbis_comments_to_tag(char **comments)
{
- struct tag *tag = tag_new();
+ Tag *tag = new Tag();
vorbis_comments_scan(comments, &add_tag_handler, tag);
- if (tag_is_empty(tag)) {
- tag_free(tag);
+ if (tag->IsEmpty()) {
+ delete tag;
tag = NULL;
}
diff --git a/src/decoder/VorbisComments.hxx b/src/decoder/VorbisComments.hxx
index 2abb7c6a5..7a8374785 100644
--- a/src/decoder/VorbisComments.hxx
+++ b/src/decoder/VorbisComments.hxx
@@ -24,6 +24,7 @@
struct replay_gain_info;
struct tag_handler;
+struct Tag;
bool
vorbis_comments_to_replay_gain(struct replay_gain_info *rgi, char **comments);
@@ -32,7 +33,7 @@ void
vorbis_comments_scan(char **comments,
const struct tag_handler *handler, void *handler_ctx);
-struct tag *
+Tag *
vorbis_comments_to_tag(char **comments);
#endif
diff --git a/src/decoder/VorbisDecoderPlugin.cxx b/src/decoder/VorbisDecoderPlugin.cxx
index 7e039ab1e..36b3e3139 100644
--- a/src/decoder/VorbisDecoderPlugin.cxx
+++ b/src/decoder/VorbisDecoderPlugin.cxx
@@ -154,12 +154,12 @@ static void
vorbis_send_comments(struct decoder *decoder, struct input_stream *is,
char **comments)
{
- struct tag *tag = vorbis_comments_to_tag(comments);
+ Tag *tag = vorbis_comments_to_tag(comments);
if (!tag)
return;
decoder_tag(decoder, is, tag);
- tag_free(tag);
+ delete tag;
}
#ifndef HAVE_TREMOR
diff --git a/src/decoder/sidplay_decoder_plugin.cxx b/src/decoder/sidplay_decoder_plugin.cxx
index 565274d83..cfe82cf57 100644
--- a/src/decoder/sidplay_decoder_plugin.cxx
+++ b/src/decoder/sidplay_decoder_plugin.cxx
@@ -26,6 +26,7 @@ extern "C" {
#include <errno.h>
#include <stdlib.h>
+#include <string.h>
#include <glib.h>
#include <sidplay/sidplay2.h>
diff --git a/src/encoder/VorbisEncoderPlugin.cxx b/src/encoder/VorbisEncoderPlugin.cxx
index 8996a57d6..1fc9bde67 100644
--- a/src/encoder/VorbisEncoderPlugin.cxx
+++ b/src/encoder/VorbisEncoderPlugin.cxx
@@ -21,7 +21,7 @@
#include "VorbisEncoderPlugin.hxx"
#include "OggStream.hxx"
#include "EncoderAPI.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include "audio_format.h"
#include "mpd_error.h"
@@ -278,18 +278,18 @@ vorbis_encoder_pre_tag(Encoder *_encoder, G_GNUC_UNUSED GError **error)
}
static void
-copy_tag_to_vorbis_comment(vorbis_comment *vc, const struct tag *tag)
+copy_tag_to_vorbis_comment(vorbis_comment *vc, const Tag *tag)
{
for (unsigned i = 0; i < tag->num_items; i++) {
- struct tag_item *item = tag->items[i];
- char *name = g_ascii_strup(tag_item_names[item->type], -1);
- vorbis_comment_add_tag(vc, name, item->value);
+ const TagItem &item = *tag->items[i];
+ char *name = g_ascii_strup(tag_item_names[item.type], -1);
+ vorbis_comment_add_tag(vc, name, item.value);
g_free(name);
}
}
static bool
-vorbis_encoder_tag(Encoder *_encoder, const struct tag *tag,
+vorbis_encoder_tag(Encoder *_encoder, const Tag *tag,
G_GNUC_UNUSED GError **error)
{
struct vorbis_encoder *encoder = (struct vorbis_encoder *)_encoder;
diff --git a/src/input/CurlInputPlugin.cxx b/src/input/CurlInputPlugin.cxx
index fe944b752..33bacffc5 100644
--- a/src/input/CurlInputPlugin.cxx
+++ b/src/input/CurlInputPlugin.cxx
@@ -23,7 +23,7 @@
#include "InputStream.hxx"
#include "InputPlugin.hxx"
#include "conf.h"
-#include "tag.h"
+#include "Tag.hxx"
#include "IcyMetaDataParser.hxx"
#include "event/MultiSocketMonitor.hxx"
#include "event/Loop.hxx"
@@ -160,7 +160,7 @@ struct input_curl {
/** the tag object ready to be requested via
input_stream_tag() */
- struct tag *tag;
+ Tag *tag;
GError *postponed_error;
@@ -696,8 +696,8 @@ curl_total_buffer_size(const struct input_curl *c)
input_curl::~input_curl()
{
- if (tag != NULL)
- tag_free(tag);
+ delete tag;
+
g_free(meta_name);
input_curl_easy_free_indirect(this);
@@ -720,11 +720,11 @@ input_curl_check(struct input_stream *is, GError **error_r)
return success;
}
-static struct tag *
+static Tag *
input_curl_tag(struct input_stream *is)
{
struct input_curl *c = (struct input_curl *)is;
- struct tag *tag = c->tag;
+ Tag *tag = c->tag;
c->tag = NULL;
return tag;
@@ -798,16 +798,15 @@ read_from_buffer(IcyMetaDataParser &icy, std::list<CurlInputBuffer> &buffers,
static void
copy_icy_tag(struct input_curl *c)
{
- struct tag *tag = c->icy.ReadTag();
+ Tag *tag = c->icy.ReadTag();
if (tag == NULL)
return;
- if (c->tag != NULL)
- tag_free(c->tag);
+ delete c->tag;
- if (c->meta_name != NULL && !tag_has_type(tag, TAG_NAME))
- tag_add_item(tag, TAG_NAME, c->meta_name);
+ if (c->meta_name != NULL && !tag->HasType(TAG_NAME))
+ tag->AddItem(TAG_NAME, c->meta_name);
c->tag = tag;
}
@@ -931,11 +930,10 @@ input_curl_headerfunction(void *ptr, size_t size, size_t nmemb, void *stream)
g_free(c->meta_name);
c->meta_name = g_strndup(value, end - value);
- if (c->tag != NULL)
- tag_free(c->tag);
+ delete c->tag;
- c->tag = tag_new();
- tag_add_item(c->tag, TAG_NAME, c->meta_name);
+ c->tag = new Tag();
+ c->tag->AddItem(TAG_NAME, c->meta_name);
} else if (g_ascii_strcasecmp(name, "icy-metaint") == 0) {
char buffer[64];
size_t icy_metaint;
diff --git a/src/input/DespotifyInputPlugin.cxx b/src/input/DespotifyInputPlugin.cxx
index 1e5a8c606..18e896608 100644
--- a/src/input/DespotifyInputPlugin.cxx
+++ b/src/input/DespotifyInputPlugin.cxx
@@ -23,7 +23,7 @@
#include "InputInternal.hxx"
#include "InputStream.hxx"
#include "InputPlugin.hxx"
-#include "tag.h"
+#include "Tag.hxx"
extern "C" {
#include <despotify.h>
@@ -42,7 +42,7 @@ struct DespotifyInputStream {
struct despotify_session *session;
struct ds_track *track;
- struct tag *tag;
+ Tag *tag;
struct ds_pcm_data pcm;
size_t len_available;
bool eof;
@@ -64,8 +64,7 @@ struct DespotifyInputStream {
}
~DespotifyInputStream() {
- if (tag != NULL)
- tag_free(tag);
+ delete tag;
despotify_free_track(track);
}
@@ -216,11 +215,11 @@ input_despotify_seek(G_GNUC_UNUSED struct input_stream *is,
return false;
}
-static struct tag *
+static Tag *
input_despotify_tag(struct input_stream *is)
{
DespotifyInputStream *ctx = (DespotifyInputStream *)is;
- struct tag *tag = ctx->tag;
+ Tag *tag = ctx->tag;
ctx->tag = NULL;
diff --git a/src/input/RewindInputPlugin.cxx b/src/input/RewindInputPlugin.cxx
index d93d7d1ce..d68fd3d73 100644
--- a/src/input/RewindInputPlugin.cxx
+++ b/src/input/RewindInputPlugin.cxx
@@ -22,11 +22,12 @@
#include "InputInternal.hxx"
#include "InputStream.hxx"
#include "InputPlugin.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include <glib.h>
#include <assert.h>
+#include <string.h>
#include <stdio.h>
#undef G_LOG_DOMAIN
@@ -127,7 +128,7 @@ input_rewind_update(struct input_stream *is)
r->CopyAttributes();
}
-static struct tag *
+static Tag *
input_rewind_tag(struct input_stream *is)
{
RewindInputStream *r = (RewindInputStream *)is;
diff --git a/src/input_stream.h b/src/input_stream.h
index 811aae3f9..b5b251f59 100644
--- a/src/input_stream.h
+++ b/src/input_stream.h
@@ -29,6 +29,7 @@
#include <stdbool.h>
#include <sys/types.h>
+struct Tag;
struct input_stream;
#ifdef __cplusplus
@@ -174,12 +175,12 @@ input_stream_lock_eof(struct input_stream *is);
*
* The caller must lock the mutex.
*
- * @return a tag object which must be freed with tag_free(), or NULL
+ * @return a tag object which must be freed by the caller, or nullptr
* if the tag has not changed since the last call
*/
gcc_nonnull(1)
gcc_malloc
-struct tag *
+Tag *
input_stream_tag(struct input_stream *is);
/**
@@ -188,7 +189,7 @@ input_stream_tag(struct input_stream *is);
*/
gcc_nonnull(1)
gcc_malloc
-struct tag *
+Tag *
input_stream_lock_tag(struct input_stream *is);
/**
diff --git a/src/mixer/OssMixerPlugin.cxx b/src/mixer/OssMixerPlugin.cxx
index 4de1e2e45..5c2bdec8d 100644
--- a/src/mixer/OssMixerPlugin.cxx
+++ b/src/mixer/OssMixerPlugin.cxx
@@ -25,6 +25,7 @@
#include <glib.h>
#include <assert.h>
+#include <string.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
diff --git a/src/output/AoOutputPlugin.cxx b/src/output/AoOutputPlugin.cxx
index 85f0ca5cb..b534ddf08 100644
--- a/src/output/AoOutputPlugin.cxx
+++ b/src/output/AoOutputPlugin.cxx
@@ -24,6 +24,8 @@
#include <ao/ao.h>
#include <glib.h>
+#include <string.h>
+
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "ao"
diff --git a/src/output/HttpdInternal.hxx b/src/output/HttpdInternal.hxx
index d7394d051..c2ac96be5 100644
--- a/src/output/HttpdInternal.hxx
+++ b/src/output/HttpdInternal.hxx
@@ -38,6 +38,7 @@ class ServerSocket;
class HttpdClient;
class Page;
struct Encoder;
+struct Tag;
struct HttpdOutput final : private ServerSocket {
struct audio_output base;
@@ -195,7 +196,7 @@ struct HttpdOutput final : private ServerSocket {
bool EncodeAndPlay(const void *chunk, size_t size, GError **error_r);
- void SendTag(const struct tag *tag);
+ void SendTag(const Tag *tag);
private:
virtual void OnAccept(int fd, const sockaddr &address,
diff --git a/src/output/HttpdOutputPlugin.cxx b/src/output/HttpdOutputPlugin.cxx
index 2ac462842..36bd1aee1 100644
--- a/src/output/HttpdOutputPlugin.cxx
+++ b/src/output/HttpdOutputPlugin.cxx
@@ -34,6 +34,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <string.h>
#include <errno.h>
#ifdef HAVE_LIBWRAP
@@ -484,7 +485,7 @@ httpd_output_pause(struct audio_output *ao)
}
inline void
-HttpdOutput::SendTag(const struct tag *tag)
+HttpdOutput::SendTag(const Tag *tag)
{
assert(tag != NULL);
@@ -523,7 +524,7 @@ HttpdOutput::SendTag(const struct tag *tag)
TAG_NUM_OF_ITEM_TYPES
};
- metadata = icy_server_metadata_page(tag, &types[0]);
+ metadata = icy_server_metadata_page(*tag, &types[0]);
if (metadata != NULL) {
const ScopeLock protect(mutex);
for (auto &client : clients)
@@ -533,7 +534,7 @@ HttpdOutput::SendTag(const struct tag *tag)
}
static void
-httpd_output_tag(struct audio_output *ao, const struct tag *tag)
+httpd_output_tag(struct audio_output *ao, const Tag *tag)
{
HttpdOutput *httpd = Cast(ao);
diff --git a/src/output/JackOutputPlugin.cxx b/src/output/JackOutputPlugin.cxx
index c32fb914b..3bc9cee8f 100644
--- a/src/output/JackOutputPlugin.cxx
+++ b/src/output/JackOutputPlugin.cxx
@@ -29,6 +29,7 @@
#include <jack/ringbuffer.h>
#include <stdlib.h>
+#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
diff --git a/src/output/RoarOutputPlugin.cxx b/src/output/RoarOutputPlugin.cxx
index 328ef3922..835c7cdd9 100644
--- a/src/output/RoarOutputPlugin.cxx
+++ b/src/output/RoarOutputPlugin.cxx
@@ -329,7 +329,7 @@ roar_tag_convert(enum tag_type type, bool *is_uuid)
}
static void
-roar_send_tag(struct audio_output *ao, const struct tag *meta)
+roar_send_tag(struct audio_output *ao, const Tag *meta)
{
RoarOutput *self = (RoarOutput *)ao;
diff --git a/src/output/ShoutOutputPlugin.cxx b/src/output/ShoutOutputPlugin.cxx
index 0a46d8bee..a0f75da1d 100644
--- a/src/output/ShoutOutputPlugin.cxx
+++ b/src/output/ShoutOutputPlugin.cxx
@@ -29,6 +29,7 @@
#include <assert.h>
#include <stdlib.h>
+#include <string.h>
#include <stdio.h>
#undef G_LOG_DOMAIN
@@ -482,7 +483,7 @@ my_shout_pause(struct audio_output *ao)
}
static void
-shout_tag_to_metadata(const struct tag *tag, char *dest, size_t size)
+shout_tag_to_metadata(const Tag *tag, char *dest, size_t size)
{
char artist[size];
char title[size];
@@ -508,7 +509,7 @@ shout_tag_to_metadata(const struct tag *tag, char *dest, size_t size)
}
static void my_shout_set_tag(struct audio_output *ao,
- const struct tag *tag)
+ const Tag *tag)
{
ShoutOutput *sd = (ShoutOutput *)ao;
GError *error = nullptr;
diff --git a/src/playlist/AsxPlaylistPlugin.cxx b/src/playlist/AsxPlaylistPlugin.cxx
index 198b1d581..be94f81ff 100644
--- a/src/playlist/AsxPlaylistPlugin.cxx
+++ b/src/playlist/AsxPlaylistPlugin.cxx
@@ -22,7 +22,7 @@
#include "MemoryPlaylistProvider.hxx"
#include "input_stream.h"
#include "Song.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include <glib.h>
@@ -169,9 +169,9 @@ asx_text(G_GNUC_UNUSED GMarkupParseContext *context,
case AsxParser::ENTRY:
if (parser->tag != TAG_NUM_OF_ITEM_TYPES) {
if (parser->song->tag == NULL)
- parser->song->tag = tag_new();
- tag_add_item_n(parser->song->tag, parser->tag,
- text, text_len);
+ parser->song->tag = new Tag();
+ parser->song->tag->AddItem(parser->tag,
+ text, text_len);
}
break;
diff --git a/src/playlist/CuePlaylistPlugin.cxx b/src/playlist/CuePlaylistPlugin.cxx
index 23f2aa82a..fd9c2de09 100644
--- a/src/playlist/CuePlaylistPlugin.cxx
+++ b/src/playlist/CuePlaylistPlugin.cxx
@@ -20,7 +20,7 @@
#include "config.h"
#include "CuePlaylistPlugin.hxx"
#include "PlaylistPlugin.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include "Song.hxx"
#include "input_stream.h"
#include "cue/CueParser.hxx"
diff --git a/src/playlist/DespotifyPlaylistPlugin.cxx b/src/playlist/DespotifyPlaylistPlugin.cxx
index 444a41a13..99724292e 100644
--- a/src/playlist/DespotifyPlaylistPlugin.cxx
+++ b/src/playlist/DespotifyPlaylistPlugin.cxx
@@ -21,7 +21,7 @@
#include "DespotifyPlaylistPlugin.hxx"
#include "DespotifyUtils.hxx"
#include "MemoryPlaylistProvider.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include "Song.hxx"
extern "C" {
diff --git a/src/playlist/EmbeddedCuePlaylistPlugin.cxx b/src/playlist/EmbeddedCuePlaylistPlugin.cxx
index 8a5eb10d7..3d69ed72b 100644
--- a/src/playlist/EmbeddedCuePlaylistPlugin.cxx
+++ b/src/playlist/EmbeddedCuePlaylistPlugin.cxx
@@ -26,7 +26,7 @@
#include "config.h"
#include "EmbeddedCuePlaylistPlugin.hxx"
#include "PlaylistPlugin.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include "TagHandler.hxx"
#include "TagId3.hxx"
#include "ApeTag.hxx"
diff --git a/src/playlist/ExtM3uPlaylistPlugin.cxx b/src/playlist/ExtM3uPlaylistPlugin.cxx
index 72be308a1..fc79ba26b 100644
--- a/src/playlist/ExtM3uPlaylistPlugin.cxx
+++ b/src/playlist/ExtM3uPlaylistPlugin.cxx
@@ -21,7 +21,7 @@
#include "ExtM3uPlaylistPlugin.hxx"
#include "PlaylistPlugin.hxx"
#include "Song.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include "util/StringUtil.hxx"
#include "TextInputStream.hxx"
@@ -70,13 +70,13 @@ extm3u_close(struct playlist_provider *_playlist)
*
* @param line the rest of the input line after the colon
*/
-static struct tag *
+static Tag *
extm3u_parse_tag(const char *line)
{
long duration;
char *endptr;
const char *name;
- struct tag *tag;
+ Tag *tag;
duration = strtol(line, &endptr, 10);
if (endptr[0] != ',')
@@ -93,14 +93,14 @@ extm3u_parse_tag(const char *line)
object */
return NULL;
- tag = tag_new();
+ tag = new Tag();
tag->time = duration;
/* unfortunately, there is no real specification for the
EXTM3U format, so we must assume that the string after the
comma is opaque, and is just the song name*/
if (*name != 0)
- tag_add_item(tag, TAG_NAME, name);
+ tag->AddItem(TAG_NAME, name);
return tag;
}
@@ -109,23 +109,21 @@ static Song *
extm3u_read(struct playlist_provider *_playlist)
{
ExtM3uPlaylist *playlist = (ExtM3uPlaylist *)_playlist;
- struct tag *tag = NULL;
+ Tag *tag = NULL;
std::string line;
const char *line_s;
Song *song;
do {
if (!playlist->tis->ReadLine(line)) {
- if (tag != NULL)
- tag_free(tag);
+ delete tag;
return NULL;
}
line_s = line.c_str();
if (g_str_has_prefix(line_s, "#EXTINF:")) {
- if (tag != NULL)
- tag_free(tag);
+ delete tag;
tag = extm3u_parse_tag(line_s + 8);
continue;
}
diff --git a/src/playlist/PlsPlaylistPlugin.cxx b/src/playlist/PlsPlaylistPlugin.cxx
index 268211b59..fdb7db77a 100644
--- a/src/playlist/PlsPlaylistPlugin.cxx
+++ b/src/playlist/PlsPlaylistPlugin.cxx
@@ -22,7 +22,7 @@
#include "MemoryPlaylistProvider.hxx"
#include "input_stream.h"
#include "Song.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include <glib.h>
@@ -71,8 +71,8 @@ pls_parser(GKeyFile *keyfile, std::forward_list<SongPointer> &songs)
g_free(key);
if(error == NULL && value){
if (song->tag == NULL)
- song->tag = tag_new();
- tag_add_item(song->tag,TAG_TITLE, value);
+ song->tag = new Tag();
+ song->tag->AddItem(TAG_TITLE, value);
}
/* Ignore errors? Most likely value not present */
if(error) g_error_free(error);
@@ -85,7 +85,7 @@ pls_parser(GKeyFile *keyfile, std::forward_list<SongPointer> &songs)
g_free(key);
if(error == NULL && length > 0){
if (song->tag == NULL)
- song->tag = tag_new();
+ song->tag = new Tag();
song->tag->time = length;
}
/* Ignore errors? Most likely value not present */
diff --git a/src/playlist/RssPlaylistPlugin.cxx b/src/playlist/RssPlaylistPlugin.cxx
index f96b54ae3..e8f279bb2 100644
--- a/src/playlist/RssPlaylistPlugin.cxx
+++ b/src/playlist/RssPlaylistPlugin.cxx
@@ -22,7 +22,7 @@
#include "MemoryPlaylistProvider.hxx"
#include "input_stream.h"
#include "Song.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include <glib.h>
@@ -166,9 +166,9 @@ rss_text(G_GNUC_UNUSED GMarkupParseContext *context,
case RssParser::ITEM:
if (parser->tag != TAG_NUM_OF_ITEM_TYPES) {
if (parser->song->tag == NULL)
- parser->song->tag = tag_new();
- tag_add_item_n(parser->song->tag, parser->tag,
- text, text_len);
+ parser->song->tag = new Tag();
+ parser->song->tag->AddItem(parser->tag,
+ text, text_len);
}
break;
diff --git a/src/playlist/SoundCloudPlaylistPlugin.cxx b/src/playlist/SoundCloudPlaylistPlugin.cxx
index 7c93a57b3..01055d1c9 100644
--- a/src/playlist/SoundCloudPlaylistPlugin.cxx
+++ b/src/playlist/SoundCloudPlaylistPlugin.cxx
@@ -23,7 +23,7 @@
#include "conf.h"
#include "input_stream.h"
#include "Song.hxx"
-#include "tag.h"
+#include "Tag.hxx"
#include <glib.h>
#include <yajl/yajl_parse.h>
@@ -204,16 +204,16 @@ static int handle_end_map(void *ctx)
data->got_url = 0;
Song *s;
- struct tag *t;
char *u;
u = g_strconcat(data->stream_url, "?client_id=", soundcloud_config.apikey, NULL);
s = Song::NewRemote(u);
g_free(u);
- t = tag_new();
+
+ Tag *t = new Tag();
t->time = data->duration / 1000;
if (data->title != NULL)
- tag_add_item(t, TAG_NAME, data->title);
+ t->AddItem(TAG_NAME, data->title);
s->tag = t;
data->songs.emplace_front(s);
diff --git a/src/playlist/XspfPlaylistPlugin.cxx b/src/playlist/XspfPlaylistPlugin.cxx
index a0bb33f1c..cb3d19033 100644
--- a/src/playlist/XspfPlaylistPlugin.cxx
+++ b/src/playlist/XspfPlaylistPlugin.cxx
@@ -21,7 +21,7 @@
#include "XspfPlaylistPlugin.hxx"
#include "MemoryPlaylistProvider.hxx"
#include "input_stream.h"
-#include "tag.h"
+#include "Tag.hxx"
#include <glib.h>
@@ -177,9 +177,8 @@ xspf_text(G_GNUC_UNUSED GMarkupParseContext *context,
if (parser->song != NULL &&
parser->tag != TAG_NUM_OF_ITEM_TYPES) {
if (parser->song->tag == NULL)
- parser->song->tag = tag_new();
- tag_add_item_n(parser->song->tag, parser->tag,
- text, text_len);
+ parser->song->tag = new Tag();
+ parser->song->tag->AddItem(parser->tag, text, text_len);
}
break;
diff --git a/src/tag.h b/src/tag.h
deleted file mode 100644
index bd376a1f5..000000000
--- a/src/tag.h
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2003-2013 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_H
-#define MPD_TAG_H
-
-#include "TagType.h"
-#include "gcc.h"
-
-#include <stdint.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <string.h>
-
-/**
- * One tag value. It is a mapping of #tag_type to am arbitrary string
- * value. Each tag can have multiple items of one tag type (although
- * few clients support that).
- */
-struct tag_item {
- /** the type of this item */
- enum tag_type type;
-
- /**
- * the value of this tag; this is a variable length string
- */
- char value[sizeof(long)];
-} gcc_packed;
-
-/**
- * The meta information about a song file. It is a MPD specific
- * subset of tags (e.g. from ID3, vorbis comments, ...).
- */
-struct tag {
- /**
- * The duration of the song (in seconds). A value of zero
- * means that the length is unknown. If the duration is
- * really between zero and one second, you should round up to
- * 1.
- */
- int time;
-
- /**
- * Does this file have an embedded playlist (e.g. embedded CUE
- * sheet)?
- */
- bool has_playlist;
-
- /** an array of tag items */
- struct tag_item **items;
-
- /** the total number of tag items in the #items array */
- unsigned num_items;
-};
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Parse the string, and convert it into a #tag_type. Returns
- * #TAG_NUM_OF_ITEM_TYPES if the string could not be recognized.
- */
-enum tag_type
-tag_name_parse(const char *name);
-
-/**
- * Parse the string, and convert it into a #tag_type. Returns
- * #TAG_NUM_OF_ITEM_TYPES if the string could not be recognized.
- *
- * Case does not matter.
- */
-enum tag_type
-tag_name_parse_i(const char *name);
-
-/**
- * Creates an empty #tag.
- */
-struct tag *tag_new(void);
-
-/**
- * Initializes the tag library.
- */
-void tag_lib_init(void);
-
-/**
- * Clear all tag items with the specified type.
- */
-void tag_clear_items_by_type(struct tag *tag, enum tag_type type);
-
-/**
- * Frees a #tag object and all its items.
- */
-void tag_free(struct tag *tag);
-
-/**
- * Gives an optional hint to the tag library that we will now add
- * several tag items; this is used by the library to optimize memory
- * allocation. Only one tag may be in this state, and this tag must
- * not have any items yet. You must call tag_end_add() when you are
- * done.
- */
-void tag_begin_add(struct tag *tag);
-
-/**
- * Finishes the operation started with tag_begin_add().
- */
-void tag_end_add(struct tag *tag);
-
-/**
- * Appends a new tag item.
- *
- * @param tag the #tag object
- * @param type the type of the new tag item
- * @param value the value of the tag item (not null-terminated)
- * @param len the length of #value
- */
-void tag_add_item_n(struct tag *tag, enum tag_type type,
- const char *value, size_t len);
-
-/**
- * Appends a new tag item.
- *
- * @param tag the #tag object
- * @param type the type of the new tag item
- * @param value the value of the tag item (null-terminated)
- */
-static inline void
-tag_add_item(struct tag *tag, enum tag_type type, const char *value)
-{
- tag_add_item_n(tag, type, value, strlen(value));
-}
-
-/**
- * Duplicates a #tag object.
- */
-struct tag *tag_dup(const struct tag *tag);
-
-/**
- * Merges the data from two tags. If both tags share data for the
- * same tag_type, only data from "add" is used.
- *
- * @return a newly allocated tag, which must be freed with tag_free()
- */
-struct tag *
-tag_merge(const struct tag *base, const struct tag *add);
-
-/**
- * Merges the data from two tags. Any of the two may be NULL. Both
- * are freed by this function.
- *
- * @return a newly allocated tag, which must be freed with tag_free()
- */
-struct tag *
-tag_merge_replace(struct tag *base, struct tag *add);
-
-/**
- * Returns true if the tag contains no items. This ignores the "time"
- * attribute.
- */
-static inline bool
-tag_is_empty(const struct tag *tag)
-{
- return tag->num_items == 0;
-}
-
-/**
- * Returns true if the tag contains any information.
- */
-static inline bool
-tag_is_defined(const struct tag *tag)
-{
- return !tag_is_empty(tag) || tag->time >= 0;
-}
-
-/**
- * Returns the first value of the specified tag type, or NULL if none
- * is present in this tag object.
- */
-const char *
-tag_get_value(const struct tag *tag, enum tag_type type);
-
-/**
- * Checks whether the tag contains one or more items with
- * the specified type.
- */
-bool tag_has_type(const struct tag *tag, enum tag_type type);
-
-/**
- * Compares two tags, including the duration and all tag items. The
- * order of the tag items matters.
- */
-bool tag_equal(const struct tag *tag1, const struct tag *tag2);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif