diff --git a/Makefile.am b/Makefile.am index c26c2347b..14cea53a9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -76,7 +76,6 @@ mpd_headers = \ src/replay_gain_info.h \ src/TimePrint.cxx src/TimePrint.hxx \ src/stats.h \ - src/tag.h \ src/tag_internal.h \ src/Timer.hxx \ src/mpd_error.h @@ -217,7 +216,7 @@ src_mpd_SOURCES = \ src/StateFile.cxx src/StateFile.hxx \ src/Stats.cxx \ src/TagType.h \ - src/Tag.cxx \ + src/Tag.cxx src/Tag.hxx \ src/TagTable.hxx \ src/TagNames.c \ src/TagPool.cxx src/TagPool.hxx \ 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 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 #include @@ -39,7 +39,7 @@ typedef std::set 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 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 #include +#include #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 #include +#include 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 @@ -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 @@ -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 @@ -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 +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 #include +#include #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 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 #include +#include #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 + 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 #include +#include #include #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 +#include + #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 #include +#include 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 #include +#include #include #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 @@ -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 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 #include #include +#include /** * 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) + if (time != other.time) return false; - if (tag1->time != tag2->time) + if (num_items != other.num_items) return false; - if (tag1->num_items != tag2->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) return; - tag_add_item_internal(tag, type, value, len); + if (value == nullptr || len == 0) + return; + + 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 + +#include + +/** + * 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 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 #include +#include 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 -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 @@ -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 #include +#include #include 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 +#include #include /* 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 #include +#include #include #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 #include #include +#include #include #include @@ -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 + 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 #include +#include #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 #include +#include #include /* 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 #include +#include #include #include 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 &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 @@ -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 #include +#include #include #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 #include +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 #include +#include #include #include #include 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 #include +#include + #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 #include +#include #include #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 #include +#include #include #include #include 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 #include +#include #include #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 @@ -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 @@ -71,8 +71,8 @@ pls_parser(GKeyFile *keyfile, std::forward_list &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 &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 @@ -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 #include @@ -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 @@ -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 -#include -#include -#include - -/** - * 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 diff --git a/test/DumpDatabase.cxx b/test/DumpDatabase.cxx index e917ec831..53b95ca22 100644 --- a/test/DumpDatabase.cxx +++ b/test/DumpDatabase.cxx @@ -25,7 +25,7 @@ #include "Song.hxx" #include "PlaylistVector.hxx" #include "conf.h" -#include "tag.h" +#include "Tag.hxx" #include "fs/Path.hxx" #include diff --git a/test/dump_playlist.cxx b/test/dump_playlist.cxx index 8eb1d6078..df7c6d739 100644 --- a/test/dump_playlist.cxx +++ b/test/dump_playlist.cxx @@ -106,7 +106,7 @@ decoder_data(G_GNUC_UNUSED struct decoder *decoder, enum decoder_command decoder_tag(G_GNUC_UNUSED struct decoder *decoder, G_GNUC_UNUSED struct input_stream *is, - G_GNUC_UNUSED const struct tag *tag) + G_GNUC_UNUSED const Tag *tag) { return DECODE_COMMAND_NONE; } @@ -232,7 +232,7 @@ int main(int argc, char **argv) (song->start_ms / 1000) % 60); if (song->tag != NULL) - tag_save(stdout, song->tag); + tag_save(stdout, *song->tag); song->Free(); } diff --git a/test/dump_rva2.cxx b/test/dump_rva2.cxx index c849f6a89..9dbb018d6 100644 --- a/test/dump_rva2.cxx +++ b/test/dump_rva2.cxx @@ -22,7 +22,7 @@ #include "TagRva2.hxx" #include "replay_gain_info.h" #include "conf.h" -#include "tag.h" +#include "Tag.hxx" #include @@ -41,23 +41,13 @@ config_get_string(gcc_unused enum ConfigOption option, return default_value; } -struct tag * -tag_new(void) -{ - return NULL; -} - void -tag_add_item_n(gcc_unused struct tag *tag, gcc_unused enum tag_type type, - gcc_unused const char *value, gcc_unused size_t len) +Tag::AddItem(gcc_unused enum tag_type type, + gcc_unused const char *value) { } -void -tag_free(struct tag *tag) -{ - g_free(tag); -} +Tag::~Tag() {} int main(int argc, char **argv) { diff --git a/test/read_tags.cxx b/test/read_tags.cxx index 9d8adf77e..515a84706 100644 --- a/test/read_tags.cxx +++ b/test/read_tags.cxx @@ -92,7 +92,7 @@ decoder_data(G_GNUC_UNUSED struct decoder *decoder, enum decoder_command decoder_tag(G_GNUC_UNUSED struct decoder *decoder, G_GNUC_UNUSED struct input_stream *is, - G_GNUC_UNUSED const struct tag *tag) + G_GNUC_UNUSED const Tag *tag) { return DECODE_COMMAND_NONE; } diff --git a/test/run_decoder.cxx b/test/run_decoder.cxx index f30914fc5..3c236ab2f 100644 --- a/test/run_decoder.cxx +++ b/test/run_decoder.cxx @@ -113,7 +113,7 @@ decoder_data(G_GNUC_UNUSED struct decoder *decoder, enum decoder_command decoder_tag(G_GNUC_UNUSED struct decoder *decoder, G_GNUC_UNUSED struct input_stream *is, - G_GNUC_UNUSED const struct tag *tag) + G_GNUC_UNUSED const Tag *tag) { return DECODE_COMMAND_NONE; } diff --git a/test/run_input.cxx b/test/run_input.cxx index 43e2f78b4..e93e817d3 100644 --- a/test/run_input.cxx +++ b/test/run_input.cxx @@ -20,7 +20,7 @@ #include "config.h" #include "TagSave.hxx" #include "stdbin.h" -#include "tag.h" +#include "Tag.hxx" #include "conf.h" #include "input_stream.h" #include "InputStream.hxx" @@ -75,11 +75,11 @@ dump_input_stream(struct input_stream *is) /* read data and tags from the stream */ while (!input_stream_eof(is)) { - struct tag *tag = input_stream_tag(is); + Tag *tag = input_stream_tag(is); if (tag != NULL) { g_printerr("Received a tag:\n"); - tag_save(stderr, tag); - tag_free(tag); + tag_save(stderr, *tag); + delete tag; } num_read = input_stream_read(is, buffer, sizeof(buffer), diff --git a/test/test_vorbis_encoder.cxx b/test/test_vorbis_encoder.cxx index 1e3b78065..650480319 100644 --- a/test/test_vorbis_encoder.cxx +++ b/test/test_vorbis_encoder.cxx @@ -23,7 +23,7 @@ #include "audio_format.h" #include "conf.h" #include "stdbin.h" -#include "tag.h" +#include "Tag.hxx" #include @@ -83,15 +83,13 @@ main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv) encoder_to_stdout(*encoder); - struct tag *tag = tag_new(); - tag_add_item(tag, TAG_ARTIST, "Foo"); - tag_add_item(tag, TAG_TITLE, "Bar"); + Tag tag; + tag.AddItem(TAG_ARTIST, "Foo"); + tag.AddItem(TAG_TITLE, "Bar"); - success = encoder_tag(encoder, tag, NULL); + success = encoder_tag(encoder, &tag, NULL); assert(success); - tag_free(tag); - encoder_to_stdout(*encoder); /* write another block of data */ diff --git a/test/visit_archive.cxx b/test/visit_archive.cxx index 8306c7304..047fe62c0 100644 --- a/test/visit_archive.cxx +++ b/test/visit_archive.cxx @@ -19,7 +19,7 @@ #include "config.h" #include "stdbin.h" -#include "tag.h" +#include "Tag.hxx" #include "conf.h" #include "IOThread.hxx" #include "InputInit.hxx"