Commit 06f898cc authored by Max Kellermann's avatar Max Kellermann

tag: convert to C++

parent 6a9ab8bc
...@@ -76,7 +76,6 @@ mpd_headers = \ ...@@ -76,7 +76,6 @@ mpd_headers = \
src/replay_gain_info.h \ src/replay_gain_info.h \
src/TimePrint.cxx src/TimePrint.hxx \ src/TimePrint.cxx src/TimePrint.hxx \
src/stats.h \ src/stats.h \
src/tag.h \
src/tag_internal.h \ src/tag_internal.h \
src/Timer.hxx \ src/Timer.hxx \
src/mpd_error.h src/mpd_error.h
...@@ -217,7 +216,7 @@ src_mpd_SOURCES = \ ...@@ -217,7 +216,7 @@ src_mpd_SOURCES = \
src/StateFile.cxx src/StateFile.hxx \ src/StateFile.cxx src/StateFile.hxx \
src/Stats.cxx \ src/Stats.cxx \
src/TagType.h \ src/TagType.h \
src/Tag.cxx \ src/Tag.cxx src/Tag.hxx \
src/TagTable.hxx \ src/TagTable.hxx \
src/TagNames.c \ src/TagNames.c \
src/TagPool.cxx src/TagPool.hxx \ src/TagPool.cxx src/TagPool.hxx \
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include "MessageCommands.hxx" #include "MessageCommands.hxx"
#include "OtherCommands.hxx" #include "OtherCommands.hxx"
#include "Permission.hxx" #include "Permission.hxx"
#include "tag.h" #include "Tag.hxx"
#include "protocol/Result.hxx" #include "protocol/Result.hxx"
#include "Client.hxx" #include "Client.hxx"
#include "util/Tokenizer.hxx" #include "util/Tokenizer.hxx"
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include "config.h" #include "config.h"
#include "ApeTag.hxx" #include "ApeTag.hxx"
#include "ApeLoader.hxx" #include "ApeLoader.hxx"
#include "tag.h" #include "Tag.hxx"
#include "TagTable.hxx" #include "TagTable.hxx"
#include "TagHandler.hxx" #include "TagHandler.hxx"
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include "CrossFade.hxx" #include "CrossFade.hxx"
#include "MusicChunk.hxx" #include "MusicChunk.hxx"
#include "audio_format.h" #include "audio_format.h"
#include "tag.h" #include "Tag.hxx"
#include <cmath> #include <cmath>
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include "DatabaseSelection.hxx" #include "DatabaseSelection.hxx"
#include "CommandError.hxx" #include "CommandError.hxx"
#include "ClientInternal.hxx" #include "ClientInternal.hxx"
#include "tag.h" #include "Tag.hxx"
#include "util/UriUtil.hxx" #include "util/UriUtil.hxx"
#include "SongFilter.hxx" #include "SongFilter.hxx"
#include "protocol/Result.hxx" #include "protocol/Result.hxx"
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include "DatabaseHelpers.hxx" #include "DatabaseHelpers.hxx"
#include "DatabasePlugin.hxx" #include "DatabasePlugin.hxx"
#include "Song.hxx" #include "Song.hxx"
#include "tag.h" #include "Tag.hxx"
#include <functional> #include <functional>
#include <set> #include <set>
...@@ -39,7 +39,7 @@ typedef std::set<const char *, StringLess> StringSet; ...@@ -39,7 +39,7 @@ typedef std::set<const char *, StringLess> StringSet;
static bool static bool
CollectTags(StringSet &set, enum tag_type tag_type, Song &song) CollectTags(StringSet &set, enum tag_type tag_type, Song &song)
{ {
struct tag *tag = song.tag; Tag *tag = song.tag;
if (tag == nullptr) if (tag == nullptr)
return true; return true;
...@@ -79,13 +79,13 @@ VisitUniqueTags(const Database &db, const DatabaseSelection &selection, ...@@ -79,13 +79,13 @@ VisitUniqueTags(const Database &db, const DatabaseSelection &selection,
static void static void
StatsVisitTag(DatabaseStats &stats, StringSet &artists, StringSet &albums, StatsVisitTag(DatabaseStats &stats, StringSet &artists, StringSet &albums,
const struct tag &tag) const Tag &tag)
{ {
if (tag.time > 0) if (tag.time > 0)
stats.total_duration += tag.time; stats.total_duration += tag.time;
for (unsigned i = 0; i < tag.num_items; ++i) { 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) { switch (item.type) {
case TAG_ARTIST: case TAG_ARTIST:
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include "TimePrint.hxx" #include "TimePrint.hxx"
#include "Directory.hxx" #include "Directory.hxx"
#include "Client.hxx" #include "Client.hxx"
#include "tag.h" #include "Tag.hxx"
#include "Song.hxx" #include "Song.hxx"
#include "DatabaseGlue.hxx" #include "DatabaseGlue.hxx"
#include "DatabasePlugin.hxx" #include "DatabasePlugin.hxx"
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include "Song.hxx" #include "Song.hxx"
#include "TextFile.hxx" #include "TextFile.hxx"
#include "TagInternal.hxx" #include "TagInternal.hxx"
#include "tag.h" #include "Tag.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include <glib.h> #include <glib.h>
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#undef G_LOG_DOMAIN #undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "decoder" #define G_LOG_DOMAIN "decoder"
...@@ -312,7 +313,7 @@ decoder_timestamp(struct decoder *decoder, double t) ...@@ -312,7 +313,7 @@ decoder_timestamp(struct decoder *decoder, double t)
* (decoder.chunk) if there is one. * (decoder.chunk) if there is one.
*/ */
static enum decoder_command 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; struct music_chunk *chunk;
...@@ -331,14 +332,14 @@ do_send_tag(struct decoder *decoder, const struct tag *tag) ...@@ -331,14 +332,14 @@ do_send_tag(struct decoder *decoder, const struct tag *tag)
return decoder->dc->command; return decoder->dc->command;
} }
chunk->tag = tag_dup(tag); chunk->tag = new Tag(tag);
return DECODE_COMMAND_NONE; return DECODE_COMMAND_NONE;
} }
static bool static bool
update_stream_tag(struct decoder *decoder, struct input_stream *is) update_stream_tag(struct decoder *decoder, struct input_stream *is)
{ {
struct tag *tag; Tag *tag;
tag = is != NULL tag = is != NULL
? input_stream_lock_tag(is) ? input_stream_lock_tag(is)
...@@ -353,9 +354,7 @@ update_stream_tag(struct decoder *decoder, struct input_stream *is) ...@@ -353,9 +354,7 @@ update_stream_tag(struct decoder *decoder, struct input_stream *is)
decoder->song_tag = NULL; decoder->song_tag = NULL;
} }
if (decoder->stream_tag != NULL) delete decoder->stream_tag;
tag_free(decoder->stream_tag);
decoder->stream_tag = tag; decoder->stream_tag = tag;
return true; return true;
} }
...@@ -387,15 +386,13 @@ decoder_data(struct decoder *decoder, ...@@ -387,15 +386,13 @@ decoder_data(struct decoder *decoder,
if (update_stream_tag(decoder, is)) { if (update_stream_tag(decoder, is)) {
if (decoder->decoder_tag != NULL) { if (decoder->decoder_tag != NULL) {
/* merge with tag from decoder plugin */ /* merge with tag from decoder plugin */
struct tag *tag; Tag *tag = Tag::Merge(*decoder->decoder_tag,
*decoder->stream_tag);
tag = tag_merge(decoder->decoder_tag, cmd = do_send_tag(decoder, *tag);
decoder->stream_tag); delete tag;
cmd = do_send_tag(decoder, tag);
tag_free(tag);
} else } else
/* send only the stream tag */ /* 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) if (cmd != DECODE_COMMAND_NONE)
return cmd; return cmd;
...@@ -474,7 +471,7 @@ decoder_data(struct decoder *decoder, ...@@ -474,7 +471,7 @@ decoder_data(struct decoder *decoder,
enum decoder_command enum decoder_command
decoder_tag(G_GNUC_UNUSED struct decoder *decoder, struct input_stream *is, 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; G_GNUC_UNUSED const struct decoder_control *dc = decoder->dc;
enum decoder_command cmd; enum decoder_command cmd;
...@@ -485,9 +482,8 @@ decoder_tag(G_GNUC_UNUSED struct decoder *decoder, struct input_stream *is, ...@@ -485,9 +482,8 @@ decoder_tag(G_GNUC_UNUSED struct decoder *decoder, struct input_stream *is,
/* save the tag */ /* save the tag */
if (decoder->decoder_tag != NULL) delete decoder->decoder_tag;
tag_free(decoder->decoder_tag); decoder->decoder_tag = new Tag(*tag);
decoder->decoder_tag = tag_dup(tag);
/* check for a new stream tag */ /* check for a new stream tag */
...@@ -505,14 +501,15 @@ decoder_tag(G_GNUC_UNUSED struct decoder *decoder, struct input_stream *is, ...@@ -505,14 +501,15 @@ decoder_tag(G_GNUC_UNUSED struct decoder *decoder, struct input_stream *is,
if (decoder->stream_tag != NULL) { if (decoder->stream_tag != NULL) {
/* merge with tag from input stream */ /* merge with tag from input stream */
struct tag *merged; Tag *merged;
merged = tag_merge(decoder->stream_tag, decoder->decoder_tag); merged = Tag::Merge(*decoder->stream_tag,
cmd = do_send_tag(decoder, merged); *decoder->decoder_tag);
tag_free(merged); cmd = do_send_tag(decoder, *merged);
delete merged;
} else } else
/* send only the decoder tag */ /* send only the decoder tag */
cmd = do_send_tag(decoder, tag); cmd = do_send_tag(decoder, *tag);
return cmd; return cmd;
} }
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
#include "DecoderPlugin.hxx" #include "DecoderPlugin.hxx"
#include "input_stream.h" #include "input_stream.h"
#include "replay_gain_info.h" #include "replay_gain_info.h"
#include "tag.h" #include "Tag.hxx"
#include "audio_format.h" #include "audio_format.h"
#include "conf.h" #include "conf.h"
...@@ -142,7 +142,7 @@ decoder_data(struct decoder *decoder, struct input_stream *is, ...@@ -142,7 +142,7 @@ decoder_data(struct decoder *decoder, struct input_stream *is,
*/ */
enum decoder_command enum decoder_command
decoder_tag(struct decoder *decoder, struct input_stream *is, decoder_tag(struct decoder *decoder, struct input_stream *is,
const struct tag *tag); const Tag *tag);
/** /**
* Set replay gain values for the following chunks. * Set replay gain values for the following chunks.
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <glib.h> #include <glib.h>
#include <assert.h> #include <assert.h>
#include <string.h>
struct DecoderBuffer { struct DecoderBuffer {
struct decoder *decoder; struct decoder *decoder;
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include "MusicPipe.hxx" #include "MusicPipe.hxx"
#include "MusicBuffer.hxx" #include "MusicBuffer.hxx"
#include "MusicChunk.hxx" #include "MusicChunk.hxx"
#include "tag.h" #include "Tag.hxx"
#include <assert.h> #include <assert.h>
...@@ -32,14 +32,9 @@ decoder::~decoder() ...@@ -32,14 +32,9 @@ decoder::~decoder()
/* caller must flush the chunk */ /* caller must flush the chunk */
assert(chunk == nullptr); assert(chunk == nullptr);
if (song_tag != nullptr) delete song_tag;
tag_free(song_tag); delete stream_tag;
delete decoder_tag;
if (stream_tag != nullptr)
tag_free(stream_tag);
if (decoder_tag != nullptr)
tag_free(decoder_tag);
} }
/** /**
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "replay_gain_info.h" #include "replay_gain_info.h"
struct input_stream; struct input_stream;
struct Tag;
struct decoder { struct decoder {
struct decoder_control *dc; struct decoder_control *dc;
...@@ -62,13 +63,13 @@ struct decoder { ...@@ -62,13 +63,13 @@ struct decoder {
* files, because we expect the stream server to send us a new * files, because we expect the stream server to send us a new
* tag each time we play it. * tag each time we play it.
*/ */
struct tag *song_tag; Tag *song_tag;
/** the last tag received from the stream */ /** the last tag received from the stream */
struct tag *stream_tag; Tag *stream_tag;
/** the last tag received from the decoder plugin */ /** the last tag received from the decoder plugin */
struct tag *decoder_tag; Tag *decoder_tag;
/** the chunk currently being written to */ /** the chunk currently being written to */
struct music_chunk *chunk; struct music_chunk *chunk;
...@@ -81,8 +82,7 @@ struct decoder { ...@@ -81,8 +82,7 @@ struct decoder {
*/ */
unsigned replay_gain_serial; unsigned replay_gain_serial;
decoder(decoder_control *_dc, bool _initial_seek_pending, decoder(decoder_control *_dc, bool _initial_seek_pending, Tag *_tag)
struct tag *_tag)
:dc(_dc), :dc(_dc),
timestamp(0), timestamp(0),
initial_seek_pending(_initial_seek_pending), initial_seek_pending(_initial_seek_pending),
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
struct config_param; struct config_param;
struct input_stream; struct input_stream;
struct tag; struct Tag;
struct tag_handler; struct tag_handler;
/** /**
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include "Mapper.hxx" #include "Mapper.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "DecoderAPI.hxx" #include "DecoderAPI.hxx"
#include "tag.h" #include "Tag.hxx"
#include "InputStream.hxx" #include "InputStream.hxx"
#include "DecoderList.hxx" #include "DecoderList.hxx"
#include "util/UriUtil.hxx" #include "util/UriUtil.hxx"
...@@ -381,7 +381,7 @@ decoder_run_song(struct decoder_control *dc, ...@@ -381,7 +381,7 @@ decoder_run_song(struct decoder_control *dc,
{ {
decoder decoder(dc, dc->start_ms > 0, decoder decoder(dc, dc->start_ms > 0,
song->tag != NULL && song->IsFile() song->tag != NULL && song->IsFile()
? tag_dup(song->tag) : nullptr); ? new Tag(*song->tag) : nullptr);
int ret; int ret;
dc->state = DECODE_STATE_START; dc->state = DECODE_STATE_START;
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
*/ */
#include "DespotifyUtils.hxx" #include "DespotifyUtils.hxx"
#include "tag.h" #include "Tag.hxx"
#include "conf.h" #include "conf.h"
#include <glib.h> #include <glib.h>
...@@ -77,14 +77,14 @@ void mpd_despotify_unregister_callback(void (*cb)(struct despotify_session *, in ...@@ -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 tracknum[20];
char comment[80]; char comment[80];
char date[20]; char date[20];
struct tag *tag;
tag = tag_new(); Tag *tag = new Tag();
if (!track->has_meta_data) if (!track->has_meta_data)
return tag; return tag;
...@@ -93,12 +93,12 @@ struct tag *mpd_despotify_tag_from_track(struct ds_track *track) ...@@ -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(date, sizeof(date), "%d", track->year);
g_snprintf(comment, sizeof(comment), "Bitrate %d Kbps, %sgeo restricted", g_snprintf(comment, sizeof(comment), "Bitrate %d Kbps, %sgeo restricted",
track->file_bitrate / 1000, track->geo_restricted ? "" : "not "); track->file_bitrate / 1000, track->geo_restricted ? "" : "not ");
tag_add_item(tag, TAG_TITLE, track->title); tag->AddItem(TAG_TITLE, track->title);
tag_add_item(tag, TAG_ARTIST, track->artist->name); tag->AddItem(TAG_ARTIST, track->artist->name);
tag_add_item(tag, TAG_TRACK, tracknum); tag->AddItem(TAG_TRACK, tracknum);
tag_add_item(tag, TAG_ALBUM, track->album); tag->AddItem(TAG_ALBUM, track->album);
tag_add_item(tag, TAG_DATE, date); tag->AddItem(TAG_DATE, date);
tag_add_item(tag, TAG_COMMENT, comment); tag->AddItem(TAG_COMMENT, comment);
tag->time = track->length / 1000; tag->time = track->length / 1000;
return tag; return tag;
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#ifndef MPD_DESPOTIFY_H #ifndef MPD_DESPOTIFY_H
#define MPD_DESPOTIFY_H #define MPD_DESPOTIFY_H
struct Tag;
struct despotify_session; struct despotify_session;
struct ds_track; struct ds_track;
...@@ -41,7 +42,8 @@ struct despotify_session *mpd_despotify_get_session(void); ...@@ -41,7 +42,8 @@ struct despotify_session *mpd_despotify_get_session(void);
* *
* @return a pointer to the filled in tags structure * @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. * Register a despotify callback.
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include "EncoderPlugin.hxx" #include "EncoderPlugin.hxx"
#include "audio_format.h" #include "audio_format.h"
#include "tag.h" #include "Tag.hxx"
#include "conf.h" #include "conf.h"
#endif #endif
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
struct EncoderPlugin; struct EncoderPlugin;
struct audio_format; struct audio_format;
struct config_param; struct config_param;
struct tag; struct Tag;
struct Encoder { struct Encoder {
const EncoderPlugin &plugin; const EncoderPlugin &plugin;
...@@ -66,7 +66,7 @@ struct EncoderPlugin { ...@@ -66,7 +66,7 @@ struct EncoderPlugin {
bool (*pre_tag)(Encoder *encoder, GError **error); bool (*pre_tag)(Encoder *encoder, GError **error);
bool (*tag)(Encoder *encoder, const struct tag *tag, bool (*tag)(Encoder *encoder, const Tag *tag,
GError **error); GError **error);
bool (*write)(Encoder *encoder, bool (*write)(Encoder *encoder,
...@@ -246,7 +246,7 @@ encoder_pre_tag(Encoder *encoder, GError **error) ...@@ -246,7 +246,7 @@ encoder_pre_tag(Encoder *encoder, GError **error)
* @return true on success * @return true on success
*/ */
static inline bool 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->open);
assert(!encoder->pre_tag); assert(!encoder->pre_tag);
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include "config.h" #include "config.h"
#include "IcyMetaDataParser.hxx" #include "IcyMetaDataParser.hxx"
#include "tag.h" #include "Tag.hxx"
#include <glib.h> #include <glib.h>
...@@ -38,8 +38,7 @@ IcyMetaDataParser::Reset() ...@@ -38,8 +38,7 @@ IcyMetaDataParser::Reset()
if (data_rest == 0 && meta_size > 0) if (data_rest == 0 && meta_size > 0)
g_free(meta_data); g_free(meta_data);
if (tag != nullptr) delete tag;
tag_free(tag);
data_rest = data_size; data_rest = data_size;
meta_size = 0; meta_size = 0;
...@@ -66,7 +65,7 @@ IcyMetaDataParser::Data(size_t length) ...@@ -66,7 +65,7 @@ IcyMetaDataParser::Data(size_t length)
} }
static void 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); size_t length = strlen(value);
...@@ -77,11 +76,11 @@ icy_add_item(struct tag *tag, enum tag_type type, const char *value) ...@@ -77,11 +76,11 @@ icy_add_item(struct tag *tag, enum tag_type type, const char *value)
} }
if (length > 0) if (length > 0)
tag_add_item_n(tag, type, value, length); tag.AddItem(type, value, length);
} }
static void 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); gchar **p = g_strsplit(item, "=", 0);
...@@ -95,14 +94,14 @@ icy_parse_tag_item(struct tag *tag, const char *item) ...@@ -95,14 +94,14 @@ icy_parse_tag_item(struct tag *tag, const char *item)
g_strfreev(p); g_strfreev(p);
} }
static struct tag * static Tag *
icy_parse_tag(const char *p) icy_parse_tag(const char *p)
{ {
struct tag *tag = tag_new(); Tag *tag = new Tag();
gchar **items = g_strsplit(p, ";", 0); gchar **items = g_strsplit(p, ";", 0);
for (unsigned i = 0; items[i] != nullptr; ++i) 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); g_strfreev(items);
...@@ -157,8 +156,7 @@ IcyMetaDataParser::Meta(const void *data, size_t length) ...@@ -157,8 +156,7 @@ IcyMetaDataParser::Meta(const void *data, size_t length)
/* parse */ /* parse */
if (tag != nullptr) delete tag;
tag_free(tag);
tag = icy_parse_tag(meta_data); tag = icy_parse_tag(meta_data);
g_free(meta_data); g_free(meta_data);
......
...@@ -22,13 +22,15 @@ ...@@ -22,13 +22,15 @@
#include <stddef.h> #include <stddef.h>
struct Tag;
class IcyMetaDataParser { class IcyMetaDataParser {
size_t data_size, data_rest; size_t data_size, data_rest;
size_t meta_size, meta_position; size_t meta_size, meta_position;
char *meta_data; char *meta_data;
struct tag *tag; Tag *tag;
public: public:
IcyMetaDataParser():data_size(0) {} IcyMetaDataParser():data_size(0) {}
...@@ -73,8 +75,8 @@ public: ...@@ -73,8 +75,8 @@ public:
*/ */
size_t Meta(const void *data, size_t length); size_t Meta(const void *data, size_t length);
struct tag *ReadTag() { Tag *ReadTag() {
struct tag *result = tag; Tag *result = tag;
tag = nullptr; tag = nullptr;
return result; return result;
} }
......
...@@ -20,11 +20,12 @@ ...@@ -20,11 +20,12 @@
#include "config.h" #include "config.h"
#include "IcyMetaDataServer.hxx" #include "IcyMetaDataServer.hxx"
#include "Page.hxx" #include "Page.hxx"
#include "tag.h" #include "Tag.hxx"
#include <glib.h> #include <glib.h>
#include <assert.h> #include <assert.h>
#include <string.h>
#undef G_LOG_DOMAIN #undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "icy_server" #define G_LOG_DOMAIN "icy_server"
...@@ -87,7 +88,7 @@ icy_server_metadata_string(const char *stream_title, const char* stream_url) ...@@ -87,7 +88,7 @@ icy_server_metadata_string(const char *stream_title, const char* stream_url)
} }
Page * 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]; const gchar *tag_items[TAG_NUM_OF_ITEM_TYPES];
gint last_item, item; gint last_item, item;
...@@ -101,7 +102,7 @@ icy_server_metadata_page(const struct tag *tag, const enum tag_type *types) ...@@ -101,7 +102,7 @@ icy_server_metadata_page(const struct tag *tag, const enum tag_type *types)
last_item = -1; last_item = -1;
while (*types != TAG_NUM_OF_ITEM_TYPES) { 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) if (tag_item)
tag_items[++last_item] = tag_item; tag_items[++last_item] = tag_item;
} }
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "TagType.h" #include "TagType.h"
struct Tag;
class Page; class Page;
char* char*
...@@ -30,6 +31,6 @@ icy_server_metadata_header(const char *name, ...@@ -30,6 +31,6 @@ icy_server_metadata_header(const char *name,
const char *content_type, int metaint); const char *content_type, int metaint);
Page * 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 #endif
...@@ -66,7 +66,7 @@ struct input_plugin { ...@@ -66,7 +66,7 @@ struct input_plugin {
*/ */
void (*update)(struct input_stream *is); 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: * Returns true if the next read operation will not block:
......
...@@ -182,7 +182,7 @@ input_stream_lock_seek(struct input_stream *is, goffset offset, int whence, ...@@ -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); return input_stream_seek(is, offset, whence, error_r);
} }
struct tag * Tag *
input_stream_tag(struct input_stream *is) input_stream_tag(struct input_stream *is)
{ {
assert(is != NULL); assert(is != NULL);
...@@ -192,7 +192,7 @@ input_stream_tag(struct input_stream *is) ...@@ -192,7 +192,7 @@ input_stream_tag(struct input_stream *is)
: NULL; : NULL;
} }
struct tag * Tag *
input_stream_lock_tag(struct input_stream *is) input_stream_lock_tag(struct input_stream *is)
{ {
assert(is != NULL); assert(is != NULL);
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
#include "Partition.hxx" #include "Partition.hxx"
#include "Volume.hxx" #include "Volume.hxx"
#include "OutputAll.hxx" #include "OutputAll.hxx"
#include "tag.h" #include "Tag.hxx"
#include "conf.h" #include "conf.h"
#include "replay_gain_config.h" #include "replay_gain_config.h"
#include "Idle.hxx" #include "Idle.hxx"
......
...@@ -20,14 +20,13 @@ ...@@ -20,14 +20,13 @@
#include "config.h" #include "config.h"
#include "MusicChunk.hxx" #include "MusicChunk.hxx"
#include "audio_format.h" #include "audio_format.h"
#include "tag.h" #include "Tag.hxx"
#include <assert.h> #include <assert.h>
music_chunk::~music_chunk() music_chunk::~music_chunk()
{ {
if (tag != NULL) delete tag;
tag_free(tag);
} }
#ifndef NDEBUG #ifndef NDEBUG
......
...@@ -34,6 +34,7 @@ enum { ...@@ -34,6 +34,7 @@ enum {
}; };
struct audio_format; struct audio_format;
struct Tag;
/** /**
* A chunk of music data. Its format is defined by the * A chunk of music data. Its format is defined by the
...@@ -70,7 +71,7 @@ struct music_chunk { ...@@ -70,7 +71,7 @@ struct music_chunk {
* object is owned by this chunk, and must be freed when this * object is owned by this chunk, and must be freed when this
* chunk is deinitialized in music_chunk_free() * chunk is deinitialized in music_chunk_free()
*/ */
struct tag *tag; Tag *tag;
/** /**
* Replay gain information associated with this chunk. * Replay gain information associated with this chunk.
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include "OutputPlugin.hxx" #include "OutputPlugin.hxx"
#include "OutputInternal.hxx" #include "OutputInternal.hxx"
#include "audio_format.h" #include "audio_format.h"
#include "tag.h" #include "Tag.hxx"
#include "conf.h" #include "conf.h"
#endif #endif
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <glib.h> #include <glib.h>
#include <assert.h> #include <assert.h>
#include <string.h>
#undef G_LOG_DOMAIN #undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "output" #define G_LOG_DOMAIN "output"
......
...@@ -37,6 +37,8 @@ ...@@ -37,6 +37,8 @@
#include "output/SolarisOutputPlugin.hxx" #include "output/SolarisOutputPlugin.hxx"
#include "output/WinmmOutputPlugin.hxx" #include "output/WinmmOutputPlugin.hxx"
#include <string.h>
const struct audio_output_plugin *const audio_output_plugins[] = { const struct audio_output_plugin *const audio_output_plugins[] = {
#ifdef HAVE_SHOUT #ifdef HAVE_SHOUT
&shout_output_plugin, &shout_output_plugin,
......
...@@ -75,7 +75,7 @@ ao_plugin_delay(struct audio_output *ao) ...@@ -75,7 +75,7 @@ ao_plugin_delay(struct audio_output *ao)
} }
void 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) if (ao->plugin->send_tag != NULL)
ao->plugin->send_tag(ao, tag); ao->plugin->send_tag(ao, tag);
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
struct config_param; struct config_param;
struct audio_format; struct audio_format;
struct tag; struct Tag;
/** /**
* A plugin which controls an audio output device. * A plugin which controls an audio output device.
...@@ -111,7 +111,7 @@ struct audio_output_plugin { ...@@ -111,7 +111,7 @@ struct audio_output_plugin {
* Display metadata for the next chunk. Optional method, * Display metadata for the next chunk. Optional method,
* because not all devices can display metadata. * 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. * Play a chunk of audio data.
...@@ -192,7 +192,7 @@ unsigned ...@@ -192,7 +192,7 @@ unsigned
ao_plugin_delay(struct audio_output *ao); ao_plugin_delay(struct audio_output *ao);
void 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 size_t
ao_plugin_play(struct audio_output *ao, const void *chunk, size_t size, ao_plugin_play(struct audio_output *ao, const void *chunk, size_t size,
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <errno.h> #include <errno.h>
#undef G_LOG_DOMAIN #undef G_LOG_DOMAIN
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include "CrossFade.hxx" #include "CrossFade.hxx"
#include "PlayerControl.hxx" #include "PlayerControl.hxx"
#include "OutputAll.hxx" #include "OutputAll.hxx"
#include "tag.h" #include "Tag.hxx"
#include "Idle.hxx" #include "Idle.hxx"
#include "GlobalEvents.hxx" #include "GlobalEvents.hxx"
...@@ -38,6 +38,8 @@ ...@@ -38,6 +38,8 @@
#include <glib.h> #include <glib.h>
#include <string.h>
#undef G_LOG_DOMAIN #undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "player_thread" #define G_LOG_DOMAIN "player_thread"
...@@ -108,7 +110,7 @@ struct player { ...@@ -108,7 +110,7 @@ struct player {
* postponed, and sent to the output thread when the new song * postponed, and sent to the output thread when the new song
* really begins. * really begins.
*/ */
struct tag *cross_fade_tag; Tag *cross_fade_tag;
/** /**
* The current audio format for the audio outputs. * The current audio format for the audio outputs.
...@@ -656,18 +658,17 @@ static void player_process_command(struct player *player) ...@@ -656,18 +658,17 @@ static void player_process_command(struct player *player)
} }
static void static void
update_song_tag(Song *song, const struct tag *new_tag) update_song_tag(Song *song, const Tag &new_tag)
{ {
if (song->IsFile()) if (song->IsFile())
/* don't update tags of local files, only remote /* don't update tags of local files, only remote
streams may change tags dynamically */ streams may change tags dynamically */
return; return;
struct tag *old_tag = song->tag; Tag *old_tag = song->tag;
song->tag = tag_dup(new_tag); song->tag = new Tag(new_tag);
if (old_tag != NULL) delete old_tag;
tag_free(old_tag);
/* the main thread will update the playlist version when he /* the main thread will update the playlist version when he
receives this event */ receives this event */
...@@ -694,7 +695,7 @@ play_chunk(struct player_control *pc, ...@@ -694,7 +695,7 @@ play_chunk(struct player_control *pc,
assert(chunk->CheckFormat(*format)); assert(chunk->CheckFormat(*format));
if (chunk->tag != NULL) if (chunk->tag != NULL)
update_song_tag(song, chunk->tag); update_song_tag(song, *chunk->tag);
if (chunk->length == 0) { if (chunk->length == 0) {
music_buffer_return(player_buffer, chunk); music_buffer_return(player_buffer, chunk);
...@@ -760,7 +761,7 @@ play_next_chunk(struct player *player) ...@@ -760,7 +761,7 @@ play_next_chunk(struct player *player)
is being faded in) yet; postpone it until is being faded in) yet; postpone it until
the current song is faded out */ the current song is faded out */
player->cross_fade_tag = player->cross_fade_tag =
tag_merge_replace(player->cross_fade_tag, Tag::MergeReplace(player->cross_fade_tag,
other_chunk->tag); other_chunk->tag);
other_chunk->tag = NULL; other_chunk->tag = NULL;
...@@ -815,7 +816,7 @@ play_next_chunk(struct player *player) ...@@ -815,7 +816,7 @@ play_next_chunk(struct player *player)
/* insert the postponed tag if cross-fading is finished */ /* insert the postponed tag if cross-fading is finished */
if (player->xfade != XFADE_ENABLED && player->cross_fade_tag != NULL) { 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);
player->cross_fade_tag = NULL; player->cross_fade_tag = NULL;
} }
...@@ -1080,8 +1081,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc) ...@@ -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_clear(player.pipe, player_buffer);
music_pipe_free(player.pipe); music_pipe_free(player.pipe);
if (player.cross_fade_tag != NULL) delete player.cross_fade_tag;
tag_free(player.cross_fade_tag);
if (player.song != NULL) if (player.song != NULL)
player.song->Free(); player.song->Free();
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
struct config_param; struct config_param;
struct input_stream; struct input_stream;
struct tag; struct Tag;
struct Song; struct Song;
/** /**
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include "DatabasePlugin.hxx" #include "DatabasePlugin.hxx"
#include "DatabaseGlue.hxx" #include "DatabaseGlue.hxx"
#include "ls.hxx" #include "ls.hxx"
#include "tag.h" #include "Tag.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "util/UriUtil.hxx" #include "util/UriUtil.hxx"
#include "Song.hxx" #include "Song.hxx"
...@@ -39,10 +39,10 @@ merge_song_metadata(Song *dest, const Song *base, ...@@ -39,10 +39,10 @@ merge_song_metadata(Song *dest, const Song *base,
{ {
dest->tag = base->tag != NULL dest->tag = base->tag != NULL
? (add->tag != NULL ? (add->tag != NULL
? tag_merge(base->tag, add->tag) ? Tag::Merge(*base->tag, *add->tag)
: tag_dup(base->tag)) : new Tag(*base->tag))
: (add->tag != NULL : (add->tag != NULL
? tag_dup(add->tag) ? new Tag(*add->tag)
: NULL); : NULL);
dest->mtime = base->mtime; dest->mtime = base->mtime;
......
...@@ -20,11 +20,12 @@ ...@@ -20,11 +20,12 @@
#include "config.h" #include "config.h"
#include "Song.hxx" #include "Song.hxx"
#include "Directory.hxx" #include "Directory.hxx"
#include "tag.h" #include "Tag.hxx"
#include <glib.h> #include <glib.h>
#include <assert.h> #include <assert.h>
#include <string.h>
Directory detached_root; Directory detached_root;
...@@ -94,7 +95,7 @@ Song::DupDetached() const ...@@ -94,7 +95,7 @@ Song::DupDetached() const
} else } else
song = song_alloc(uri, nullptr); song = song_alloc(uri, nullptr);
song->tag = tag_dup(tag); song->tag = tag != nullptr ? new Tag(*tag) : nullptr;
song->mtime = mtime; song->mtime = mtime;
song->start_ms = start_ms; song->start_ms = start_ms;
song->end_ms = end_ms; song->end_ms = end_ms;
...@@ -105,8 +106,7 @@ Song::DupDetached() const ...@@ -105,8 +106,7 @@ Song::DupDetached() const
void void
Song::Free() Song::Free()
{ {
if (tag != nullptr) delete tag;
tag_free(tag);
g_free(this); g_free(this);
} }
......
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
#define SONG_FILE "file: " #define SONG_FILE "file: "
#define SONG_TIME "Time: " #define SONG_TIME "Time: "
struct Tag;
/** /**
* A dummy #directory instance that is used for "detached" song * A dummy #directory instance that is used for "detached" song
* copies. * copies.
...@@ -46,7 +48,7 @@ struct Song { ...@@ -46,7 +48,7 @@ struct Song {
*/ */
struct list_head siblings; struct list_head siblings;
struct tag *tag; Tag *tag;
Directory *parent; Directory *parent;
time_t mtime; time_t mtime;
......
...@@ -20,11 +20,12 @@ ...@@ -20,11 +20,12 @@
#include "config.h" #include "config.h"
#include "SongFilter.hxx" #include "SongFilter.hxx"
#include "Song.hxx" #include "Song.hxx"
#include "tag.h" #include "Tag.hxx"
#include <glib.h> #include <glib.h>
#include <assert.h> #include <assert.h>
#include <string.h>
#include <stdlib.h> #include <stdlib.h>
#define LOCATE_TAG_FILE_KEY "file" #define LOCATE_TAG_FILE_KEY "file"
...@@ -74,14 +75,14 @@ SongFilter::Item::StringMatch(const char *s) const ...@@ -74,14 +75,14 @@ SongFilter::Item::StringMatch(const char *s) const
} }
bool 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) && return (tag == LOCATE_TAG_ANY_TYPE || (unsigned)item.type == tag) &&
StringMatch(item.value); StringMatch(item.value);
} }
bool bool
SongFilter::Item::Match(const struct tag &_tag) const SongFilter::Item::Match(const Tag &_tag) const
{ {
bool visited_types[TAG_NUM_OF_ITEM_TYPES]; bool visited_types[TAG_NUM_OF_ITEM_TYPES];
std::fill(visited_types, visited_types + TAG_NUM_OF_ITEM_TYPES, false); std::fill(visited_types, visited_types + TAG_NUM_OF_ITEM_TYPES, false);
......
...@@ -29,8 +29,8 @@ ...@@ -29,8 +29,8 @@
#define LOCATE_TAG_FILE_TYPE TAG_NUM_OF_ITEM_TYPES+10 #define LOCATE_TAG_FILE_TYPE TAG_NUM_OF_ITEM_TYPES+10
#define LOCATE_TAG_ANY_TYPE TAG_NUM_OF_ITEM_TYPES+20 #define LOCATE_TAG_ANY_TYPE TAG_NUM_OF_ITEM_TYPES+20
struct tag; struct Tag;
struct tag_item; struct TagItem;
struct Song; struct Song;
class SongFilter { class SongFilter {
...@@ -65,10 +65,10 @@ class SongFilter { ...@@ -65,10 +65,10 @@ class SongFilter {
bool StringMatch(const char *s) const; bool StringMatch(const char *s) const;
gcc_pure gcc_pure
bool Match(const tag_item &tag_item) const; bool Match(const TagItem &tag_item) const;
gcc_pure gcc_pure
bool Match(const struct tag &tag) const; bool Match(const Tag &tag) const;
gcc_pure gcc_pure
bool Match(const Song &song) const; bool Match(const Song &song) const;
...@@ -91,7 +91,7 @@ public: ...@@ -91,7 +91,7 @@ public:
bool Parse(unsigned argc, char *argv[], bool fold_case=false); bool Parse(unsigned argc, char *argv[], bool fold_case=false);
gcc_pure gcc_pure
bool Match(const tag &tag) const; bool Match(const Tag &tag) const;
gcc_pure gcc_pure
bool Match(const Song &song) const; bool Match(const Song &song) const;
......
...@@ -69,6 +69,6 @@ song_print_info(Client *client, Song *song) ...@@ -69,6 +69,6 @@ song_print_info(Client *client, Song *song)
if (song->mtime > 0) if (song->mtime > 0)
time_print(client, "Last-Modified", song->mtime); time_print(client, "Last-Modified", song->mtime);
if (song->tag) if (song->tag != nullptr)
tag_print(client, song->tag); tag_print(client, *song->tag);
} }
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include "TagSave.hxx" #include "TagSave.hxx"
#include "Directory.hxx" #include "Directory.hxx"
#include "TextFile.hxx" #include "TextFile.hxx"
#include "tag.h" #include "Tag.hxx"
#include "util/StringUtil.hxx" #include "util/StringUtil.hxx"
#include <glib.h> #include <glib.h>
...@@ -52,8 +52,8 @@ song_save(FILE *fp, const Song *song) ...@@ -52,8 +52,8 @@ song_save(FILE *fp, const Song *song)
else if (song->start_ms > 0) else if (song->start_ms > 0)
fprintf(fp, "Range: %u-\n", song->start_ms); fprintf(fp, "Range: %u-\n", song->start_ms);
if (song->tag != NULL) if (song->tag != nullptr)
tag_save(fp, song->tag); tag_save(fp, *song->tag);
fprintf(fp, SONG_MTIME ": %li\n", (long)song->mtime); fprintf(fp, SONG_MTIME ": %li\n", (long)song->mtime);
fprintf(fp, SONG_END "\n"); fprintf(fp, SONG_END "\n");
...@@ -75,7 +75,7 @@ song_load(TextFile &file, Directory *parent, const char *uri, ...@@ -75,7 +75,7 @@ song_load(TextFile &file, Directory *parent, const char *uri,
colon = strchr(line, ':'); colon = strchr(line, ':');
if (colon == NULL || colon == line) { if (colon == NULL || colon == line) {
if (song->tag != NULL) if (song->tag != NULL)
tag_end_add(song->tag); song->tag->EndAdd();
song->Free(); song->Free();
g_set_error(error_r, song_save_quark(), 0, g_set_error(error_r, song_save_quark(), 0,
...@@ -88,22 +88,22 @@ song_load(TextFile &file, Directory *parent, const char *uri, ...@@ -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 ((type = tag_name_parse(line)) != TAG_NUM_OF_ITEM_TYPES) {
if (!song->tag) { if (!song->tag) {
song->tag = tag_new(); song->tag = new Tag();
tag_begin_add(song->tag); song->tag->BeginAdd();
} }
tag_add_item(song->tag, type, value); song->tag->AddItem(type, value);
} else if (strcmp(line, "Time") == 0) { } else if (strcmp(line, "Time") == 0) {
if (!song->tag) { if (!song->tag) {
song->tag = tag_new(); song->tag = new Tag();
tag_begin_add(song->tag); song->tag->BeginAdd();
} }
song->tag->time = atoi(value); song->tag->time = atoi(value);
} else if (strcmp(line, "Playlist") == 0) { } else if (strcmp(line, "Playlist") == 0) {
if (!song->tag) { if (!song->tag) {
song->tag = tag_new(); song->tag = new Tag();
tag_begin_add(song->tag); song->tag->BeginAdd();
} }
song->tag->has_playlist = strcmp(value, "yes") == 0; song->tag->has_playlist = strcmp(value, "yes") == 0;
...@@ -117,7 +117,7 @@ song_load(TextFile &file, Directory *parent, const char *uri, ...@@ -117,7 +117,7 @@ song_load(TextFile &file, Directory *parent, const char *uri,
song->end_ms = strtoul(endptr + 1, NULL, 10); song->end_ms = strtoul(endptr + 1, NULL, 10);
} else { } else {
if (song->tag != NULL) if (song->tag != NULL)
tag_end_add(song->tag); song->tag->EndAdd();
song->Free(); song->Free();
g_set_error(error_r, song_save_quark(), 0, g_set_error(error_r, song_save_quark(), 0,
...@@ -127,7 +127,7 @@ song_load(TextFile &file, Directory *parent, const char *uri, ...@@ -127,7 +127,7 @@ song_load(TextFile &file, Directory *parent, const char *uri,
} }
if (song->tag != NULL) if (song->tag != NULL)
tag_end_add(song->tag); song->tag->EndAdd();
return song; return song;
} }
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include "SongSort.hxx" #include "SongSort.hxx"
#include "Song.hxx" #include "Song.hxx"
#include "util/list.h" #include "util/list.h"
#include "tag.h" #include "Tag.hxx"
extern "C" { extern "C" {
#include "util/list_sort.h" #include "util/list_sort.h"
...@@ -33,10 +33,10 @@ extern "C" { ...@@ -33,10 +33,10 @@ extern "C" {
#include <stdlib.h> #include <stdlib.h>
static const char * 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 return tag != NULL
? tag_get_value(tag, type) ? tag->GetValue(type)
: NULL; : NULL;
} }
...@@ -57,7 +57,7 @@ compare_utf8_string(const char *a, const char *b) ...@@ -57,7 +57,7 @@ compare_utf8_string(const char *a, const char *b)
* NULL. * NULL.
*/ */
static int 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) enum tag_type type)
{ {
return compare_utf8_string(tag_get_value_checked(a, type), return compare_utf8_string(tag_get_value_checked(a, type),
...@@ -84,7 +84,7 @@ compare_number_string(const char *a, const char *b) ...@@ -84,7 +84,7 @@ compare_number_string(const char *a, const char *b)
} }
static int 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), return compare_number_string(tag_get_value_checked(a, type),
tag_get_value_checked(b, type)); tag_get_value_checked(b, type));
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#include "Mapper.hxx" #include "Mapper.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "fs/FileSystem.hxx" #include "fs/FileSystem.hxx"
#include "tag.h" #include "Tag.hxx"
#include "input_stream.h" #include "input_stream.h"
#include "DecoderPlugin.hxx" #include "DecoderPlugin.hxx"
#include "DecoderList.hxx" #include "DecoderList.hxx"
...@@ -100,10 +100,8 @@ Song::UpdateFile() ...@@ -100,10 +100,8 @@ Song::UpdateFile()
if (path_fs.IsNull()) if (path_fs.IsNull())
return false; return false;
if (tag != NULL) { delete tag;
tag_free(tag); tag = nullptr;
tag = NULL;
}
if (!StatFile(path_fs, st) || !S_ISREG(st.st_mode)) { if (!StatFile(path_fs, st) || !S_ISREG(st.st_mode)) {
return false; return false;
...@@ -116,12 +114,12 @@ Song::UpdateFile() ...@@ -116,12 +114,12 @@ Song::UpdateFile()
do { do {
/* load file tag */ /* load file tag */
tag = tag_new(); tag = new Tag();
if (decoder_plugin_scan_file(plugin, path_fs.c_str(), if (decoder_plugin_scan_file(plugin, path_fs.c_str(),
&full_tag_handler, tag)) &full_tag_handler, tag))
break; break;
tag_free(tag); delete tag;
tag = nullptr; tag = nullptr;
/* fall back to stream tag */ /* fall back to stream tag */
...@@ -136,13 +134,13 @@ Song::UpdateFile() ...@@ -136,13 +134,13 @@ Song::UpdateFile()
/* now try the stream_tag() method */ /* now try the stream_tag() method */
if (is != NULL) { if (is != NULL) {
tag = tag_new(); tag = new Tag();
if (decoder_plugin_scan_stream(plugin, is, if (decoder_plugin_scan_stream(plugin, is,
&full_tag_handler, &full_tag_handler,
tag)) tag))
break; break;
tag_free(tag); delete tag;
tag = nullptr; tag = nullptr;
input_stream_lock_seek(is, 0, SEEK_SET, NULL); input_stream_lock_seek(is, 0, SEEK_SET, NULL);
...@@ -155,7 +153,7 @@ Song::UpdateFile() ...@@ -155,7 +153,7 @@ Song::UpdateFile()
if (is != NULL) if (is != NULL)
input_stream_close(is); 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); tag_scan_fallback(path_fs.c_str(), &full_tag_handler, tag);
return tag != nullptr; return tag != nullptr;
...@@ -179,13 +177,12 @@ Song::UpdateFileInArchive() ...@@ -179,13 +177,12 @@ Song::UpdateFileInArchive()
if (plugin == NULL) if (plugin == NULL)
return false; return false;
if (tag != nullptr) delete tag;
tag_free(tag);
//accept every file that has music suffix //accept every file that has music suffix
//because we don't support tag reading through //because we don't support tag reading through
//input streams //input streams
tag = tag_new(); tag = new Tag();
return true; return true;
} }
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
*/ */
#include "config.h" #include "config.h"
#include "tag.h" #include "Tag.hxx"
#include "TagInternal.hxx" #include "TagInternal.hxx"
#include "TagPool.hxx" #include "TagPool.hxx"
#include "conf.h" #include "conf.h"
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
/** /**
* Maximum number of items managed in the bulk list; if it is * Maximum number of items managed in the bulk list; if it is
...@@ -40,7 +41,7 @@ static struct { ...@@ -40,7 +41,7 @@ static struct {
#ifndef NDEBUG #ifndef NDEBUG
bool busy; bool busy;
#endif #endif
struct tag_item *items[BULK_MAX]; TagItem *items[BULK_MAX];
} bulk; } bulk;
bool ignore_tag_items[TAG_NUM_OF_ITEM_TYPES]; bool ignore_tag_items[TAG_NUM_OF_ITEM_TYPES];
...@@ -75,9 +76,10 @@ tag_name_parse_i(const char *name) ...@@ -75,9 +76,10 @@ tag_name_parse_i(const char *name)
return TAG_NUM_OF_ITEM_TYPES; 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) void tag_lib_init(void)
...@@ -130,127 +132,101 @@ void tag_lib_init(void) ...@@ -130,127 +132,101 @@ void tag_lib_init(void)
g_free(temp); g_free(temp);
} }
struct tag *tag_new(void) void
Tag::DeleteItem(unsigned idx)
{ {
struct tag *ret = g_new(struct tag, 1); assert(idx < num_items);
ret->items = nullptr; --num_items;
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--;
tag_pool_lock.lock(); tag_pool_lock.lock();
tag_pool_put_item(tag->items[idx]); tag_pool_put_item(items[idx]);
tag_pool_lock.unlock(); tag_pool_lock.unlock();
if (tag->num_items - idx > 0) { if (num_items - idx > 0) {
memmove(tag->items + idx, tag->items + idx + 1, memmove(items + idx, items + idx + 1,
(tag->num_items - idx) * sizeof(tag->items[0])); (num_items - idx) * sizeof(items[0]));
} }
if (tag->num_items > 0) { if (num_items > 0) {
tag->items = (struct tag_item **) items = (TagItem **)
g_realloc(tag->items, items_size(tag)); g_realloc(items, items_size(*this));
} else { } else {
g_free(tag->items); g_free(items);
tag->items = nullptr; 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++) { for (unsigned i = 0; i < num_items; i++) {
if (tag->items[i]->type == type) { if (items[i]->type == type) {
tag_delete_item(tag, i); DeleteItem(i);
/* decrement since when just deleted this node */ /* decrement since when just deleted this node */
i--; i--;
} }
} }
} }
void tag_free(struct tag *tag) Tag::~Tag()
{ {
int i;
assert(tag != nullptr);
tag_pool_lock.lock(); tag_pool_lock.lock();
for (i = tag->num_items; --i >= 0; ) for (int i = num_items; --i >= 0; )
tag_pool_put_item(tag->items[i]); tag_pool_put_item(items[i]);
tag_pool_lock.unlock(); tag_pool_lock.unlock();
if (tag->items == bulk.items) { if (items == bulk.items) {
#ifndef NDEBUG #ifndef NDEBUG
assert(bulk.busy); assert(bulk.busy);
bulk.busy = false; bulk.busy = false;
#endif #endif
} else } else
g_free(tag->items); g_free(items);
g_free(tag);
} }
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(); tag_pool_lock.lock();
for (unsigned i = 0; i < tag->num_items; i++) for (unsigned i = 0; i < num_items; i++)
ret->items[i] = tag_pool_dup_item(tag->items[i]); items[i] = tag_pool_dup_item(other.items[i]);
tag_pool_lock.unlock(); tag_pool_lock.unlock();
}
return ret;
} }
struct tag * Tag *
tag_merge(const struct tag *base, const struct tag *add) Tag::Merge(const Tag &base, const Tag &add)
{ {
struct tag *ret;
unsigned n; unsigned n;
assert(base != nullptr);
assert(add != nullptr);
/* allocate new tag object */ /* allocate new tag object */
ret = tag_new(); Tag *ret = new Tag();
ret->time = add->time > 0 ? add->time : base->time; ret->time = add.time > 0 ? add.time : base.time;
ret->num_items = base->num_items + add->num_items; ret->num_items = base.num_items + add.num_items;
ret->items = ret->num_items > 0 ret->items = ret->num_items > 0
? (struct tag_item **)g_malloc(items_size(ret)) ? (TagItem **)g_malloc(items_size(*ret))
: nullptr; : nullptr;
tag_pool_lock.lock(); tag_pool_lock.lock();
/* copy all items from "add" */ /* copy all items from "add" */
for (unsigned i = 0; i < add->num_items; ++i) for (unsigned i = 0; i < add.num_items; ++i)
ret->items[i] = tag_pool_dup_item(add->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" */ /* copy additional items from "base" */
for (unsigned i = 0; i < base->num_items; ++i) for (unsigned i = 0; i < base.num_items; ++i)
if (!tag_has_type(add, base->items[i]->type)) if (!add.HasType(base.items[i]->type))
ret->items[n++] = tag_pool_dup_item(base->items[i]); ret->items[n++] = tag_pool_dup_item(base.items[i]);
tag_pool_lock.unlock(); tag_pool_lock.unlock();
...@@ -261,15 +237,15 @@ tag_merge(const struct tag *base, const struct tag *add) ...@@ -261,15 +237,15 @@ tag_merge(const struct tag *base, const struct tag *add)
assert(n > 0); assert(n > 0);
ret->num_items = n; ret->num_items = n;
ret->items = (struct tag_item **) ret->items = (TagItem **)
g_realloc(ret->items, items_size(ret)); g_realloc(ret->items, items_size(*ret));
} }
return ret; return ret;
} }
struct tag * Tag *
tag_merge_replace(struct tag *base, struct tag *add) Tag::MergeReplace(Tag *base, Tag *add)
{ {
if (add == nullptr) if (add == nullptr)
return base; return base;
...@@ -277,48 +253,44 @@ tag_merge_replace(struct tag *base, struct tag *add) ...@@ -277,48 +253,44 @@ tag_merge_replace(struct tag *base, struct tag *add)
if (base == nullptr) if (base == nullptr)
return add; return add;
struct tag *tag = tag_merge(base, add); Tag *tag = Merge(*base, *add);
tag_free(base); delete base;
tag_free(add); delete add;
return tag; return tag;
} }
const char * 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); assert(type < TAG_NUM_OF_ITEM_TYPES);
for (unsigned i = 0; i < tag->num_items; i++) for (unsigned i = 0; i < num_items; i++)
if (tag->items[i]->type == type) if (items[i]->type == type)
return tag->items[i]->value; return items[i]->value;
return nullptr; 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) if (time != other.time)
return true;
else if (!tag1 || !tag2)
return false;
if (tag1->time != tag2->time)
return false; return false;
if (tag1->num_items != tag2->num_items) if (num_items != other.num_items)
return false; return false;
for (unsigned i = 0; i < tag1->num_items; i++) { for (unsigned i = 0; i < num_items; i++) {
if (tag1->items[i]->type != tag2->items[i]->type) if (items[i]->type != other.items[i]->type)
return false; return false;
if (strcmp(tag1->items[i]->value, tag2->items[i]->value)) { if (strcmp(items[i]->value, other.items[i]->value)) {
return false; return false;
} }
} }
...@@ -368,32 +340,33 @@ fix_utf8(const char *str, size_t length) ...@@ -368,32 +340,33 @@ fix_utf8(const char *str, size_t length)
return patch_utf8(str, length, end); return patch_utf8(str, length, end);
} }
void tag_begin_add(struct tag *tag) void
Tag::BeginAdd()
{ {
assert(!bulk.busy); assert(!bulk.busy);
assert(tag != nullptr); assert(items == nullptr);
assert(tag->items == nullptr); assert(num_items == 0);
assert(tag->num_items == 0);
#ifndef NDEBUG #ifndef NDEBUG
bulk.busy = true; bulk.busy = true;
#endif #endif
tag->items = bulk.items; items = bulk.items;
} }
void tag_end_add(struct tag *tag) void
Tag::EndAdd()
{ {
if (tag->items == bulk.items) { if (items == bulk.items) {
assert(tag->num_items <= BULK_MAX); assert(num_items <= BULK_MAX);
if (tag->num_items > 0) { if (num_items > 0) {
/* copy the tag items from the bulk list over /* copy the tag items from the bulk list over
to a new list (which fits exactly) */ to a new list (which fits exactly) */
tag->items = (struct tag_item **) items = (TagItem **)
g_malloc(items_size(tag)); g_malloc(items_size(*this));
memcpy(tag->items, bulk.items, items_size(tag)); memcpy(items, bulk.items, items_size(*this));
} else } else
tag->items = nullptr; items = nullptr;
} }
#ifndef NDEBUG #ifndef NDEBUG
...@@ -459,11 +432,10 @@ fix_tag_value(const char *p, size_t length) ...@@ -459,11 +432,10 @@ fix_tag_value(const char *p, size_t length)
return cleared; return cleared;
} }
static void void
tag_add_item_internal(struct tag *tag, enum tag_type type, Tag::AddItemInternal(tag_type type, const char *value, size_t len)
const char *value, size_t len)
{ {
unsigned int i = tag->num_items; unsigned int i = num_items;
char *p; char *p;
p = fix_tag_value(value, len); p = fix_tag_value(value, len);
...@@ -472,37 +444,42 @@ tag_add_item_internal(struct tag *tag, enum tag_type type, ...@@ -472,37 +444,42 @@ tag_add_item_internal(struct tag *tag, enum tag_type type,
len = strlen(value); len = strlen(value);
} }
tag->num_items++; num_items++;
if (tag->items != bulk.items) if (items != bulk.items)
/* bulk mode disabled */ /* bulk mode disabled */
tag->items = (struct tag_item **) items = (TagItem **)
g_realloc(tag->items, items_size(tag)); g_realloc(items, items_size(*this));
else if (tag->num_items >= BULK_MAX) { else if (num_items >= BULK_MAX) {
/* bulk list already full - switch back to non-bulk */ /* bulk list already full - switch back to non-bulk */
assert(bulk.busy); assert(bulk.busy);
tag->items = (struct tag_item **)g_malloc(items_size(tag)); items = (TagItem **)g_malloc(items_size(*this));
memcpy(tag->items, bulk.items, memcpy(items, bulk.items,
items_size(tag) - sizeof(struct tag_item *)); items_size(*this) - sizeof(TagItem *));
} }
tag_pool_lock.lock(); 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(); tag_pool_lock.unlock();
g_free(p); g_free(p);
} }
void tag_add_item_n(struct tag *tag, enum tag_type type, void
const char *value, size_t len) Tag::AddItem(tag_type type, const char *value, size_t len)
{ {
if (ignore_tag_items[type]) if (ignore_tag_items[type])
{
return; return;
}
if (!value || !len) if (value == nullptr || len == 0)
return; return;
tag_add_item_internal(tag, type, value, len); AddItemInternal(type, value, len);
}
void
Tag::AddItem(tag_type type, const char *value)
{
AddItem(type, value, strlen(value));
} }
...@@ -17,23 +17,22 @@ ...@@ -17,23 +17,22 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef MPD_TAG_H #ifndef MPD_TAG_HXX
#define MPD_TAG_H #define MPD_TAG_HXX
#include "TagType.h" #include "TagType.h"
#include "gcc.h" #include "gcc.h"
#include <stdint.h> #include <algorithm>
#include <stddef.h> #include <stddef.h>
#include <stdbool.h>
#include <string.h>
/** /**
* One tag value. It is a mapping of #tag_type to am arbitrary string * 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 * value. Each tag can have multiple items of one tag type (although
* few clients support that). * few clients support that).
*/ */
struct tag_item { struct TagItem {
/** the type of this item */ /** the type of this item */
enum tag_type type; enum tag_type type;
...@@ -47,7 +46,7 @@ struct tag_item { ...@@ -47,7 +46,7 @@ struct tag_item {
* The meta information about a song file. It is a MPD specific * The meta information about a song file. It is a MPD specific
* subset of tags (e.g. from ID3, vorbis comments, ...). * subset of tags (e.g. from ID3, vorbis comments, ...).
*/ */
struct tag { struct Tag {
/** /**
* The duration of the song (in seconds). A value of zero * The duration of the song (in seconds). A value of zero
* means that the length is unknown. If the duration is * means that the length is unknown. If the duration is
...@@ -63,153 +62,157 @@ struct tag { ...@@ -63,153 +62,157 @@ struct tag {
bool has_playlist; bool has_playlist;
/** an array of tag items */ /** an array of tag items */
struct tag_item **items; TagItem **items;
/** the total number of tag items in the #items array */ /** the total number of tag items in the #items array */
unsigned num_items; unsigned num_items;
};
#ifdef __cplusplus
extern "C" {
#endif
/** /**
* Parse the string, and convert it into a #tag_type. Returns * Create an empty tag.
* #TAG_NUM_OF_ITEM_TYPES if the string could not be recognized.
*/ */
enum tag_type Tag():time(-1), has_playlist(false),
tag_name_parse(const char *name); items(nullptr), num_items(0) {}
/** Tag(const Tag &other);
* 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);
/** Tag(Tag &&other)
* Creates an empty #tag. :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.
*/ */
struct tag *tag_new(void); ~Tag();
/** Tag &operator=(const Tag &other) = delete;
* Initializes the tag library.
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.
*/ */
void tag_lib_init(void); bool IsEmpty() const {
return num_items == 0;
}
/** /**
* Clear all tag items with the specified type. * Returns true if the tag contains any information.
*/ */
void tag_clear_items_by_type(struct tag *tag, enum tag_type type); bool IsDefined() const {
return !IsEmpty() || time >= 0;
}
/** void DeleteItem(unsigned i);
* Frees a #tag object and all its items.
/**
* Clear all tag items with the specified type.
*/ */
void tag_free(struct tag *tag); void ClearItemsByType(tag_type type);
/** /**
* Gives an optional hint to the tag library that we will now add * Gives an optional hint to the tag library that we will now
* several tag items; this is used by the library to optimize memory * add several tag items; this is used by the library to
* allocation. Only one tag may be in this state, and this tag must * optimize memory allocation. Only one tag may be in this
* not have any items yet. You must call tag_end_add() when you are * state, and this tag must not have any items yet. You must
* done. * call tag_end_add() when you are done.
*/ */
void tag_begin_add(struct tag *tag); void BeginAdd();
/** /**
* Finishes the operation started with tag_begin_add(). * Finishes the operation started with tag_begin_add().
*/ */
void tag_end_add(struct tag *tag); void EndAdd();
/** /**
* Appends a new tag item. * Appends a new tag item.
* *
* @param tag the #tag object
* @param type the type of the new tag item * @param type the type of the new tag item
* @param value the value of the tag item (not null-terminated) * @param value the value of the tag item (not null-terminated)
* @param len the length of #value * @param len the length of #value
*/ */
void tag_add_item_n(struct tag *tag, enum tag_type type, void AddItem(tag_type type, const char *value, size_t len);
const char *value, size_t len);
/** /**
* Appends a new tag item. * Appends a new tag item.
* *
* @param tag the #tag object * @param tag the #tag object
* @param type the type of the new tag item * @param type the type of the new tag item
* @param value the value of the tag item (null-terminated) * @param value the value of the tag item (null-terminated)
*/ */
static inline void void AddItem(tag_type type, const char *value);
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 * Merges the data from two tags. If both tags share data for the
* same tag_type, only data from "add" is used. * same tag_type, only data from "add" is used.
* *
* @return a newly allocated tag, which must be freed with tag_free() * @return a newly allocated tag
*/ */
struct tag * gcc_malloc
tag_merge(const struct tag *base, const struct tag *add); static Tag *Merge(const Tag &base, const Tag &add);
/** /**
* Merges the data from two tags. Any of the two may be NULL. Both * Merges the data from two tags. Any of the two may be NULL. Both
* are freed by this function. * are freed by this function.
* *
* @return a newly allocated tag, which must be freed with tag_free() * @return a newly allocated tag
*/
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 gcc_malloc
tag_is_defined(const struct tag *tag) static Tag *MergeReplace(Tag *base, Tag *add);
{
return !tag_is_empty(tag) || tag->time >= 0;
}
/** /**
* Returns the first value of the specified tag type, or NULL if none * Returns the first value of the specified tag type, or NULL if none
* is present in this tag object. * is present in this tag object.
*/ */
const char * gcc_pure
tag_get_value(const struct tag *tag, enum tag_type type); const char *GetValue(tag_type type) const;
/** /**
* Checks whether the tag contains one or more items with * Checks whether the tag contains one or more items with
* the specified type. * the specified type.
*/ */
bool tag_has_type(const struct tag *tag, enum tag_type type); bool HasType(tag_type type) const;
/** /**
* Compares two tags, including the duration and all tag items. The * Compares two tags, including the duration and all tag items. The
* order of the tag items matters. * order of the tag items matters.
*/ */
bool tag_equal(const struct tag *tag1, const struct tag *tag2); gcc_pure
bool Equals(const Tag &other) const;
#ifdef __cplusplus private:
} void AddItemInternal(tag_type type, const char *value, size_t len);
#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);
/**
* Initializes the tag library.
*/
void
tag_lib_init();
#endif #endif
...@@ -19,14 +19,14 @@ ...@@ -19,14 +19,14 @@
#include "config.h" #include "config.h"
#include "TagHandler.hxx" #include "TagHandler.hxx"
#include "tag.h" #include "Tag.hxx"
#include <glib.h> #include <glib.h>
static void static void
add_tag_duration(unsigned seconds, void *ctx) add_tag_duration(unsigned seconds, void *ctx)
{ {
struct tag *tag = (struct tag *)ctx; Tag *tag = (Tag *)ctx;
tag->time = seconds; tag->time = seconds;
} }
...@@ -34,9 +34,9 @@ add_tag_duration(unsigned seconds, void *ctx) ...@@ -34,9 +34,9 @@ add_tag_duration(unsigned seconds, void *ctx)
static void static void
add_tag_tag(enum tag_type type, const char *value, void *ctx) 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 = { const struct tag_handler add_tag_handler = {
...@@ -48,7 +48,7 @@ const struct tag_handler add_tag_handler = { ...@@ -48,7 +48,7 @@ const struct tag_handler add_tag_handler = {
static void static void
full_tag_pair(const char *name, G_GNUC_UNUSED const char *value, void *ctx) 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) if (g_ascii_strcasecmp(name, "cuesheet") == 0)
tag->has_playlist = true; tag->has_playlist = true;
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include "TagId3.hxx" #include "TagId3.hxx"
#include "TagHandler.hxx" #include "TagHandler.hxx"
#include "TagTable.hxx" #include "TagTable.hxx"
#include "tag.h" #include "Tag.hxx"
extern "C" { extern "C" {
#include "riff.h" #include "riff.h"
...@@ -385,14 +385,15 @@ scan_id3_tag(struct id3_tag *tag, ...@@ -385,14 +385,15 @@ scan_id3_tag(struct id3_tag *tag,
tag_id3_import_ufid(tag, handler, handler_ctx); 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); scan_id3_tag(tag, &add_tag_handler, ret);
if (tag_is_empty(ret)) { if (ret->IsEmpty()) {
tag_free(ret); delete ret;
ret = nullptr; ret = nullptr;
} }
......
...@@ -25,7 +25,8 @@ ...@@ -25,7 +25,8 @@
#include "gerror.h" #include "gerror.h"
struct tag_handler; struct tag_handler;
struct tag; struct Tag;
struct id3_tag;
#ifdef HAVE_ID3TAG #ifdef HAVE_ID3TAG
...@@ -33,8 +34,8 @@ bool ...@@ -33,8 +34,8 @@ bool
tag_id3_scan(const char *path_fs, tag_id3_scan(const char *path_fs,
const struct tag_handler *handler, void *handler_ctx); const struct tag_handler *handler, void *handler_ctx);
struct id3_tag; Tag *
struct tag *tag_id3_import(struct id3_tag *); tag_id3_import(struct id3_tag *);
/** /**
* Loads the ID3 tags from the file into a libid3tag object. The * Loads the ID3 tags from the file into a libid3tag object. The
......
...@@ -19,11 +19,12 @@ ...@@ -19,11 +19,12 @@
#include "config.h" #include "config.h"
#include "TagPool.hxx" #include "TagPool.hxx"
#include "tag.h" #include "Tag.hxx"
#include <glib.h> #include <glib.h>
#include <assert.h> #include <assert.h>
#include <string.h>
Mutex tag_pool_lock; Mutex tag_pool_lock;
...@@ -32,7 +33,7 @@ Mutex tag_pool_lock; ...@@ -32,7 +33,7 @@ Mutex tag_pool_lock;
struct slot { struct slot {
struct slot *next; struct slot *next;
unsigned char ref; unsigned char ref;
struct tag_item item; TagItem item;
} mpd_packed; } mpd_packed;
static struct slot *slots[NUM_SLOTS]; static struct slot *slots[NUM_SLOTS];
...@@ -64,7 +65,7 @@ calc_hash(enum tag_type type, const char *p) ...@@ -64,7 +65,7 @@ calc_hash(enum tag_type type, const char *p)
} }
static inline struct slot * 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)); return (struct slot*)(((char*)item) - offsetof(struct slot, item));
} }
...@@ -85,7 +86,7 @@ static struct slot *slot_alloc(struct slot *next, ...@@ -85,7 +86,7 @@ static struct slot *slot_alloc(struct slot *next,
return slot; return slot;
} }
struct tag_item * TagItem *
tag_pool_get_item(enum tag_type type, const char *value, size_t length) tag_pool_get_item(enum tag_type type, const char *value, size_t length)
{ {
struct slot **slot_p, *slot; struct slot **slot_p, *slot;
...@@ -107,7 +108,8 @@ tag_pool_get_item(enum tag_type type, const char *value, size_t length) ...@@ -107,7 +108,8 @@ tag_pool_get_item(enum tag_type type, const char *value, size_t length)
return &slot->item; 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); struct slot *slot = tag_item_to_slot(item);
...@@ -130,7 +132,8 @@ struct tag_item *tag_pool_dup_item(struct tag_item *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; struct slot **slot_p, *slot;
......
...@@ -25,13 +25,15 @@ ...@@ -25,13 +25,15 @@
extern Mutex tag_pool_lock; 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); 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 #endif
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include "config.h" #include "config.h"
#include "TagPrint.hxx" #include "TagPrint.hxx"
#include "tag.h" #include "Tag.hxx"
#include "TagInternal.hxx" #include "TagInternal.hxx"
#include "Song.hxx" #include "Song.hxx"
#include "Client.hxx" #include "Client.hxx"
...@@ -35,14 +35,14 @@ void tag_print_types(Client *client) ...@@ -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) if (tag.time >= 0)
client_printf(client, SONG_TIME "%i\n", tag->time); 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", client_printf(client, "%s: %s\n",
tag_item_names[tag->items[i]->type], tag_item_names[tag.items[i]->type],
tag->items[i]->value); tag.items[i]->value);
} }
} }
...@@ -20,11 +20,12 @@ ...@@ -20,11 +20,12 @@
#ifndef MPD_TAG_PRINT_HXX #ifndef MPD_TAG_PRINT_HXX
#define MPD_TAG_PRINT_HXX #define MPD_TAG_PRINT_HXX
struct tag; struct Tag;
class Client; class Client;
void tag_print_types(Client *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 #endif
...@@ -19,20 +19,21 @@ ...@@ -19,20 +19,21 @@
#include "config.h" #include "config.h"
#include "TagSave.hxx" #include "TagSave.hxx"
#include "tag.h" #include "Tag.hxx"
#include "TagInternal.hxx" #include "TagInternal.hxx"
#include "Song.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) if (tag.time >= 0)
fprintf(file, SONG_TIME "%i\n", tag->time); fprintf(file, SONG_TIME "%i\n", tag.time);
if (tag->has_playlist) if (tag.has_playlist)
fprintf(file, "Playlist: yes\n"); 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", fprintf(file, "%s: %s\n",
tag_item_names[tag->items[i]->type], tag_item_names[tag.items[i]->type],
tag->items[i]->value); tag.items[i]->value);
} }
...@@ -22,8 +22,9 @@ ...@@ -22,8 +22,9 @@
#include <stdio.h> #include <stdio.h>
struct tag; struct Tag;
void tag_save(FILE *file, const struct tag *tag); void
tag_save(FILE *file, const Tag &tag);
#endif #endif
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include "Mapper.hxx" #include "Mapper.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "TagHandler.hxx" #include "TagHandler.hxx"
#include "tag.h" #include "Tag.hxx"
#include <glib.h> #include <glib.h>
...@@ -95,7 +95,7 @@ update_container_file(Directory *directory, ...@@ -95,7 +95,7 @@ update_container_file(Directory *directory,
const Path child_path_fs = const Path child_path_fs =
map_directory_child_fs(contdir, vtrack); map_directory_child_fs(contdir, vtrack);
song->tag = tag_new(); song->tag = new Tag();
decoder_plugin_scan_file(plugin, child_path_fs.c_str(), decoder_plugin_scan_file(plugin, child_path_fs.c_str(),
&add_tag_handler, song->tag); &add_tag_handler, song->tag);
......
...@@ -21,15 +21,16 @@ ...@@ -21,15 +21,16 @@
#include "CueParser.hxx" #include "CueParser.hxx"
#include "util/StringUtil.hxx" #include "util/StringUtil.hxx"
#include "Song.hxx" #include "Song.hxx"
#include "tag.h" #include "Tag.hxx"
#include <glib.h> #include <glib.h>
#include <assert.h> #include <assert.h>
#include <string.h>
#include <stdlib.h> #include <stdlib.h>
CueParser::CueParser() CueParser::CueParser()
:state(HEADER), tag(tag_new()), :state(HEADER), tag(new Tag()),
filename(nullptr), filename(nullptr),
current(nullptr), current(nullptr),
previous(nullptr), previous(nullptr),
...@@ -38,7 +39,7 @@ CueParser::CueParser() ...@@ -38,7 +39,7 @@ CueParser::CueParser()
CueParser::~CueParser() CueParser::~CueParser()
{ {
tag_free(tag); delete tag;
g_free(filename); g_free(filename);
if (current != nullptr) if (current != nullptr)
...@@ -109,16 +110,16 @@ cue_next_value(char **pp) ...@@ -109,16 +110,16 @@ cue_next_value(char **pp)
} }
static void 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); const char *value = cue_next_value(&p);
if (value != nullptr) if (value != nullptr)
tag_add_item(tag, type, value); tag.AddItem(type, value);
} }
static void static void
cue_parse_rem(char *p, struct tag *tag) cue_parse_rem(char *p, Tag &tag)
{ {
const char *type = cue_next_token(&p); const char *type = cue_next_token(&p);
if (type == nullptr) if (type == nullptr)
...@@ -129,7 +130,7 @@ cue_parse_rem(char *p, struct tag *tag) ...@@ -129,7 +130,7 @@ cue_parse_rem(char *p, struct tag *tag)
cue_add_tag(tag, type2, p); cue_add_tag(tag, type2, p);
} }
struct tag * Tag *
CueParser::GetCurrentTag() CueParser::GetCurrentTag()
{ {
if (state == HEADER) if (state == HEADER)
...@@ -188,9 +189,9 @@ CueParser::Feed2(char *p) ...@@ -188,9 +189,9 @@ CueParser::Feed2(char *p)
return; return;
if (strcmp(command, "REM") == 0) { if (strcmp(command, "REM") == 0) {
struct tag *current_tag = GetCurrentTag(); Tag *current_tag = GetCurrentTag();
if (current_tag != nullptr) if (current_tag != nullptr)
cue_parse_rem(p, current_tag); cue_parse_rem(p, *current_tag);
} else if (strcmp(command, "PERFORMER") == 0) { } else if (strcmp(command, "PERFORMER") == 0) {
/* MPD knows a "performer" tag, but it is not a good /* MPD knows a "performer" tag, but it is not a good
match for this CUE tag; from the Hydrogenaudio match for this CUE tag; from the Hydrogenaudio
...@@ -202,14 +203,14 @@ CueParser::Feed2(char *p) ...@@ -202,14 +203,14 @@ CueParser::Feed2(char *p)
? TAG_ARTIST ? TAG_ARTIST
: TAG_ALBUM_ARTIST; : TAG_ALBUM_ARTIST;
struct tag *current_tag = GetCurrentTag(); Tag *current_tag = GetCurrentTag();
if (current_tag != nullptr) if (current_tag != nullptr)
cue_add_tag(current_tag, type, p); cue_add_tag(*current_tag, type, p);
} else if (strcmp(command, "TITLE") == 0) { } else if (strcmp(command, "TITLE") == 0) {
if (state == HEADER) if (state == HEADER)
cue_add_tag(tag, TAG_ALBUM, p); cue_add_tag(*tag, TAG_ALBUM, p);
else if (state == TRACK) 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) { } else if (strcmp(command, "FILE") == 0) {
Commit(); Commit();
...@@ -252,8 +253,8 @@ CueParser::Feed2(char *p) ...@@ -252,8 +253,8 @@ CueParser::Feed2(char *p)
state = TRACK; state = TRACK;
current = Song::NewRemote(filename); current = Song::NewRemote(filename);
assert(current->tag == nullptr); assert(current->tag == nullptr);
current->tag = tag_dup(tag); current->tag = new Tag(*tag);
tag_add_item(current->tag, TAG_TRACK, nr); current->tag->AddItem(TAG_TRACK, nr);
last_updated = false; last_updated = false;
} else if (state == IGNORE_TRACK) { } else if (state == IGNORE_TRACK) {
return; return;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "gcc.h" #include "gcc.h"
struct Song; struct Song;
struct Tag;
class CueParser { class CueParser {
enum { enum {
...@@ -53,7 +54,7 @@ class CueParser { ...@@ -53,7 +54,7 @@ class CueParser {
IGNORE_TRACK, IGNORE_TRACK,
} state; } state;
struct tag *tag; Tag *tag;
char *filename; char *filename;
...@@ -115,7 +116,7 @@ public: ...@@ -115,7 +116,7 @@ public:
private: private:
gcc_pure gcc_pure
struct tag *GetCurrentTag(); Tag *GetCurrentTag();
/** /**
* Commit the current song. It will be moved to "previous", * Commit the current song. It will be moved to "previous",
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include "Song.hxx" #include "Song.hxx"
#include "gcc.h" #include "gcc.h"
#include "conf.h" #include "conf.h"
#include "tag.h" #include "Tag.hxx"
extern "C" { extern "C" {
#include "db_error.h" #include "db_error.h"
...@@ -256,7 +256,7 @@ Visit(struct mpd_connection *connection, ...@@ -256,7 +256,7 @@ Visit(struct mpd_connection *connection,
} }
static void 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) const struct mpd_song *song, enum mpd_tag_type s_tag)
{ {
...@@ -265,7 +265,7 @@ Copy(struct tag *tag, enum tag_type d_tag, ...@@ -265,7 +265,7 @@ Copy(struct tag *tag, enum tag_type d_tag,
if (value == NULL) if (value == NULL)
break; break;
tag_add_item(tag, d_tag, value); tag.AddItem(d_tag, value);
} }
} }
...@@ -278,13 +278,13 @@ Convert(const struct mpd_song *song) ...@@ -278,13 +278,13 @@ Convert(const struct mpd_song *song)
s->start_ms = mpd_song_get_start(song) * 1000; s->start_ms = mpd_song_get_start(song) * 1000;
s->end_ms = mpd_song_get_end(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->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) for (const auto *i = &tag_table[0]; i->d != TAG_NUM_OF_ITEM_TYPES; ++i)
Copy(tag, i->d, song, i->s); Copy(*tag, i->d, song, i->s);
tag_end_add(tag); tag->EndAdd();
s->tag = tag; s->tag = tag;
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "TagId3.hxx" #include "TagId3.hxx"
#include <unistd.h> #include <unistd.h>
#include <string.h>
#include <stdio.h> /* for SEEK_SET, SEEK_CUR */ #include <stdio.h> /* for SEEK_SET, SEEK_CUR */
#ifdef HAVE_ID3TAG #ifdef HAVE_ID3TAG
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <glib.h> #include <glib.h>
#include <assert.h> #include <assert.h>
#include <string.h>
#include <unistd.h> #include <unistd.h>
#undef G_LOG_DOMAIN #undef G_LOG_DOMAIN
......
...@@ -43,8 +43,7 @@ flac_data::flac_data(struct decoder *_decoder, ...@@ -43,8 +43,7 @@ flac_data::flac_data(struct decoder *_decoder,
flac_data::~flac_data() flac_data::~flac_data()
{ {
if (tag != nullptr) delete tag;
tag_free(tag);
} }
static enum sample_format static enum sample_format
......
...@@ -81,7 +81,7 @@ struct flac_data : public FlacInput { ...@@ -81,7 +81,7 @@ struct flac_data : public FlacInput {
struct decoder *decoder; struct decoder *decoder;
struct input_stream *input_stream; struct input_stream *input_stream;
struct tag *tag; Tag *tag;
flac_data(struct decoder *decoder, struct input_stream *input_stream); flac_data(struct decoder *decoder, struct input_stream *input_stream);
~flac_data(); ~flac_data();
......
...@@ -172,11 +172,11 @@ flac_decoder_loop(struct flac_data *data, FLAC__StreamDecoder *flac_dec, ...@@ -172,11 +172,11 @@ flac_decoder_loop(struct flac_data *data, FLAC__StreamDecoder *flac_dec,
data->first_frame = t_start; data->first_frame = t_start;
while (true) { 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, cmd = decoder_tag(data->decoder, data->input_stream,
data->tag); data->tag);
tag_free(data->tag); delete data->tag;
data->tag = tag_new(); data->tag = new Tag();
} else } else
cmd = decoder_get_command(decoder); cmd = decoder_get_command(decoder);
...@@ -260,7 +260,7 @@ flac_decode_internal(struct decoder * decoder, ...@@ -260,7 +260,7 @@ flac_decode_internal(struct decoder * decoder,
return; return;
struct flac_data data(decoder, input_stream); struct flac_data data(decoder, input_stream);
data.tag = tag_new(); data.tag = new Tag();
FLAC__StreamDecoderInitStatus status = FLAC__StreamDecoderInitStatus status =
stream_init(flac_dec, &data, is_ogg); stream_init(flac_dec, &data, is_ogg);
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include "config.h" #include "config.h"
#include "FlacMetadata.hxx" #include "FlacMetadata.hxx"
#include "XiphTags.hxx" #include "XiphTags.hxx"
#include "tag.h" #include "Tag.hxx"
#include "TagHandler.hxx" #include "TagHandler.hxx"
#include "TagTable.hxx" #include "TagTable.hxx"
#include "replay_gain_info.h" #include "replay_gain_info.h"
...@@ -228,7 +228,7 @@ flac_scan_metadata(const FLAC__StreamMetadata *block, ...@@ -228,7 +228,7 @@ flac_scan_metadata(const FLAC__StreamMetadata *block,
} }
void void
flac_vorbis_comments_to_tag(struct tag *tag, flac_vorbis_comments_to_tag(Tag *tag,
const FLAC__StreamMetadata_VorbisComment *comment) const FLAC__StreamMetadata_VorbisComment *comment)
{ {
flac_scan_comments(comment, &add_tag_handler, tag); flac_scan_comments(comment, &add_tag_handler, tag);
......
...@@ -109,7 +109,7 @@ public: ...@@ -109,7 +109,7 @@ public:
}; };
struct tag_handler; struct tag_handler;
struct tag; struct Tag;
struct replay_gain_info; struct replay_gain_info;
static inline unsigned static inline unsigned
...@@ -130,7 +130,7 @@ flac_parse_mixramp(char **mixramp_start, char **mixramp_end, ...@@ -130,7 +130,7 @@ flac_parse_mixramp(char **mixramp_start, char **mixramp_end,
const FLAC__StreamMetadata *block); const FLAC__StreamMetadata *block);
void void
flac_vorbis_comments_to_tag(struct tag *tag, flac_vorbis_comments_to_tag(Tag *tag,
const FLAC__StreamMetadata_VorbisComment *comment); const FLAC__StreamMetadata_VorbisComment *comment);
void void
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <glib.h> #include <glib.h>
#include <mad.h> #include <mad.h>
...@@ -143,8 +144,8 @@ struct MadDecoder { ...@@ -143,8 +144,8 @@ struct MadDecoder {
bool Seek(long offset); bool Seek(long offset);
bool FillBuffer(); bool FillBuffer();
void ParseId3(size_t tagsize, struct tag **mpd_tag); void ParseId3(size_t tagsize, Tag **mpd_tag);
enum mp3_action DecodeNextFrameHeader(struct tag **tag); enum mp3_action DecodeNextFrameHeader(Tag **tag);
enum mp3_action DecodeNextFrame(); enum mp3_action DecodeNextFrame();
gcc_pure gcc_pure
...@@ -158,7 +159,7 @@ struct MadDecoder { ...@@ -158,7 +159,7 @@ struct MadDecoder {
*/ */
void FileSizeToSongLength(); void FileSizeToSongLength();
bool DecodeFirstFrame(struct tag **tag); bool DecodeFirstFrame(Tag **tag);
gcc_pure gcc_pure
long TimeToFrame(double t) const; long TimeToFrame(double t) const;
...@@ -334,7 +335,7 @@ parse_id3_mixramp(char **mixramp_start, char **mixramp_end, ...@@ -334,7 +335,7 @@ parse_id3_mixramp(char **mixramp_start, char **mixramp_end,
#endif #endif
inline void inline void
MadDecoder::ParseId3(size_t tagsize, struct tag **mpd_tag) MadDecoder::ParseId3(size_t tagsize, Tag **mpd_tag)
{ {
#ifdef HAVE_ID3TAG #ifdef HAVE_ID3TAG
struct id3_tag *id3_tag = nullptr; struct id3_tag *id3_tag = nullptr;
...@@ -379,10 +380,9 @@ MadDecoder::ParseId3(size_t tagsize, struct tag **mpd_tag) ...@@ -379,10 +380,9 @@ MadDecoder::ParseId3(size_t tagsize, struct tag **mpd_tag)
} }
if (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 (tmp_tag != nullptr) {
if (*mpd_tag != nullptr) delete *mpd_tag;
tag_free(*mpd_tag);
*mpd_tag = tmp_tag; *mpd_tag = tmp_tag;
} }
} }
...@@ -453,7 +453,7 @@ id3_tag_query(const void *p0, size_t length) ...@@ -453,7 +453,7 @@ id3_tag_query(const void *p0, size_t length)
#endif /* !HAVE_ID3TAG */ #endif /* !HAVE_ID3TAG */
enum mp3_action enum mp3_action
MadDecoder::DecodeNextFrameHeader(struct tag **tag) MadDecoder::DecodeNextFrameHeader(Tag **tag)
{ {
if ((stream.buffer == nullptr || stream.error == MAD_ERROR_BUFLEN) && if ((stream.buffer == nullptr || stream.error == MAD_ERROR_BUFLEN) &&
!FillBuffer()) !FillBuffer())
...@@ -807,7 +807,7 @@ MadDecoder::FileSizeToSongLength() ...@@ -807,7 +807,7 @@ MadDecoder::FileSizeToSongLength()
} }
inline bool inline bool
MadDecoder::DecodeFirstFrame(struct tag **tag) MadDecoder::DecodeFirstFrame(Tag **tag)
{ {
struct xing xing; struct xing xing;
struct lame lame; struct lame lame;
...@@ -1079,13 +1079,13 @@ MadDecoder::Read() ...@@ -1079,13 +1079,13 @@ MadDecoder::Read()
bool skip = false; bool skip = false;
do { do {
struct tag *tag = nullptr; Tag *tag = nullptr;
ret = DecodeNextFrameHeader(&tag); ret = DecodeNextFrameHeader(&tag);
if (tag != nullptr) { if (tag != nullptr) {
decoder_tag(decoder, input_stream, tag); decoder_tag(decoder, input_stream, tag);
tag_free(tag); delete tag;
} }
} while (ret == DECODE_CONT); } while (ret == DECODE_CONT);
if (ret == DECODE_BREAK) if (ret == DECODE_BREAK)
...@@ -1113,10 +1113,9 @@ mp3_decode(struct decoder *decoder, struct input_stream *input_stream) ...@@ -1113,10 +1113,9 @@ mp3_decode(struct decoder *decoder, struct input_stream *input_stream)
{ {
MadDecoder data(decoder, input_stream); MadDecoder data(decoder, input_stream);
struct tag *tag = nullptr; Tag *tag = nullptr;
if (!data.DecodeFirstFrame(&tag)) { if (!data.DecodeFirstFrame(&tag)) {
if (tag != nullptr) delete tag;
tag_free(tag);
if (decoder_get_command(decoder) == DECODE_COMMAND_NONE) if (decoder_get_command(decoder) == DECODE_COMMAND_NONE)
g_warning g_warning
...@@ -1134,8 +1133,7 @@ mp3_decode(struct decoder *decoder, struct input_stream *input_stream) ...@@ -1134,8 +1133,7 @@ mp3_decode(struct decoder *decoder, struct input_stream *input_stream)
g_warning("%s", error->message); g_warning("%s", error->message);
g_error_free(error); g_error_free(error);
if (tag != nullptr) delete tag;
tag_free(tag);
return; return;
} }
...@@ -1145,7 +1143,7 @@ mp3_decode(struct decoder *decoder, struct input_stream *input_stream) ...@@ -1145,7 +1143,7 @@ mp3_decode(struct decoder *decoder, struct input_stream *input_stream)
if (tag != nullptr) { if (tag != nullptr) {
decoder_tag(decoder, input_stream, tag); decoder_tag(decoder, input_stream, tag);
tag_free(tag); delete tag;
} }
while (data.Read()) {} while (data.Read()) {}
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
#include "config.h" #include "config.h"
#include "OggCodec.hxx" #include "OggCodec.hxx"
#include <string.h>
enum ogg_codec enum ogg_codec
ogg_codec_detect(struct decoder *decoder, struct input_stream *is) ogg_codec_detect(struct decoder *decoder, struct input_stream *is)
{ {
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <glib.h> #include <glib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#undef G_LOG_DOMAIN #undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "opus" #define G_LOG_DOMAIN "opus"
...@@ -221,16 +222,16 @@ MPDOpusDecoder::HandleBOS(const ogg_packet &packet) ...@@ -221,16 +222,16 @@ MPDOpusDecoder::HandleBOS(const ogg_packet &packet)
inline enum decoder_command inline enum decoder_command
MPDOpusDecoder::HandleTags(const ogg_packet &packet) MPDOpusDecoder::HandleTags(const ogg_packet &packet)
{ {
struct tag *tag = tag_new(); Tag tag;
enum decoder_command cmd; enum decoder_command cmd;
if (ScanOpusTags(packet.packet, packet.bytes, &add_tag_handler, tag) && if (ScanOpusTags(packet.packet, packet.bytes,
!tag_is_empty(tag)) &add_tag_handler, &tag) &&
cmd = decoder_tag(decoder, input_stream, tag); !tag.IsEmpty())
cmd = decoder_tag(decoder, input_stream, &tag);
else else
cmd = decoder_get_command(decoder); cmd = decoder_get_command(decoder);
tag_free(tag);
return cmd; return cmd;
} }
......
...@@ -27,6 +27,7 @@ extern "C" { ...@@ -27,6 +27,7 @@ extern "C" {
#include <glib.h> #include <glib.h>
#include <unistd.h> #include <unistd.h>
#include <string.h>
#include <stdio.h> /* for SEEK_SET */ #include <stdio.h> /* for SEEK_SET */
#undef G_LOG_DOMAIN #undef G_LOG_DOMAIN
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include "config.h" #include "config.h"
#include "VorbisComments.hxx" #include "VorbisComments.hxx"
#include "XiphTags.hxx" #include "XiphTags.hxx"
#include "tag.h" #include "Tag.hxx"
#include "TagTable.hxx" #include "TagTable.hxx"
#include "TagHandler.hxx" #include "TagHandler.hxx"
#include "replay_gain_info.h" #include "replay_gain_info.h"
...@@ -135,14 +135,14 @@ vorbis_comments_scan(char **comments, ...@@ -135,14 +135,14 @@ vorbis_comments_scan(char **comments,
} }
struct tag * Tag *
vorbis_comments_to_tag(char **comments) vorbis_comments_to_tag(char **comments)
{ {
struct tag *tag = tag_new(); Tag *tag = new Tag();
vorbis_comments_scan(comments, &add_tag_handler, tag); vorbis_comments_scan(comments, &add_tag_handler, tag);
if (tag_is_empty(tag)) { if (tag->IsEmpty()) {
tag_free(tag); delete tag;
tag = NULL; tag = NULL;
} }
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
struct replay_gain_info; struct replay_gain_info;
struct tag_handler; struct tag_handler;
struct Tag;
bool bool
vorbis_comments_to_replay_gain(struct replay_gain_info *rgi, char **comments); vorbis_comments_to_replay_gain(struct replay_gain_info *rgi, char **comments);
...@@ -32,7 +33,7 @@ void ...@@ -32,7 +33,7 @@ void
vorbis_comments_scan(char **comments, vorbis_comments_scan(char **comments,
const struct tag_handler *handler, void *handler_ctx); const struct tag_handler *handler, void *handler_ctx);
struct tag * Tag *
vorbis_comments_to_tag(char **comments); vorbis_comments_to_tag(char **comments);
#endif #endif
...@@ -154,12 +154,12 @@ static void ...@@ -154,12 +154,12 @@ static void
vorbis_send_comments(struct decoder *decoder, struct input_stream *is, vorbis_send_comments(struct decoder *decoder, struct input_stream *is,
char **comments) char **comments)
{ {
struct tag *tag = vorbis_comments_to_tag(comments); Tag *tag = vorbis_comments_to_tag(comments);
if (!tag) if (!tag)
return; return;
decoder_tag(decoder, is, tag); decoder_tag(decoder, is, tag);
tag_free(tag); delete tag;
} }
#ifndef HAVE_TREMOR #ifndef HAVE_TREMOR
......
...@@ -26,6 +26,7 @@ extern "C" { ...@@ -26,6 +26,7 @@ extern "C" {
#include <errno.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <glib.h> #include <glib.h>
#include <sidplay/sidplay2.h> #include <sidplay/sidplay2.h>
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include "VorbisEncoderPlugin.hxx" #include "VorbisEncoderPlugin.hxx"
#include "OggStream.hxx" #include "OggStream.hxx"
#include "EncoderAPI.hxx" #include "EncoderAPI.hxx"
#include "tag.h" #include "Tag.hxx"
#include "audio_format.h" #include "audio_format.h"
#include "mpd_error.h" #include "mpd_error.h"
...@@ -278,18 +278,18 @@ vorbis_encoder_pre_tag(Encoder *_encoder, G_GNUC_UNUSED GError **error) ...@@ -278,18 +278,18 @@ vorbis_encoder_pre_tag(Encoder *_encoder, G_GNUC_UNUSED GError **error)
} }
static void 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++) { for (unsigned i = 0; i < tag->num_items; i++) {
struct tag_item *item = tag->items[i]; const TagItem &item = *tag->items[i];
char *name = g_ascii_strup(tag_item_names[item->type], -1); char *name = g_ascii_strup(tag_item_names[item.type], -1);
vorbis_comment_add_tag(vc, name, item->value); vorbis_comment_add_tag(vc, name, item.value);
g_free(name); g_free(name);
} }
} }
static bool static bool
vorbis_encoder_tag(Encoder *_encoder, const struct tag *tag, vorbis_encoder_tag(Encoder *_encoder, const Tag *tag,
G_GNUC_UNUSED GError **error) G_GNUC_UNUSED GError **error)
{ {
struct vorbis_encoder *encoder = (struct vorbis_encoder *)_encoder; struct vorbis_encoder *encoder = (struct vorbis_encoder *)_encoder;
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include "InputStream.hxx" #include "InputStream.hxx"
#include "InputPlugin.hxx" #include "InputPlugin.hxx"
#include "conf.h" #include "conf.h"
#include "tag.h" #include "Tag.hxx"
#include "IcyMetaDataParser.hxx" #include "IcyMetaDataParser.hxx"
#include "event/MultiSocketMonitor.hxx" #include "event/MultiSocketMonitor.hxx"
#include "event/Loop.hxx" #include "event/Loop.hxx"
...@@ -160,7 +160,7 @@ struct input_curl { ...@@ -160,7 +160,7 @@ struct input_curl {
/** the tag object ready to be requested via /** the tag object ready to be requested via
input_stream_tag() */ input_stream_tag() */
struct tag *tag; Tag *tag;
GError *postponed_error; GError *postponed_error;
...@@ -696,8 +696,8 @@ curl_total_buffer_size(const struct input_curl *c) ...@@ -696,8 +696,8 @@ curl_total_buffer_size(const struct input_curl *c)
input_curl::~input_curl() input_curl::~input_curl()
{ {
if (tag != NULL) delete tag;
tag_free(tag);
g_free(meta_name); g_free(meta_name);
input_curl_easy_free_indirect(this); input_curl_easy_free_indirect(this);
...@@ -720,11 +720,11 @@ input_curl_check(struct input_stream *is, GError **error_r) ...@@ -720,11 +720,11 @@ input_curl_check(struct input_stream *is, GError **error_r)
return success; return success;
} }
static struct tag * static Tag *
input_curl_tag(struct input_stream *is) input_curl_tag(struct input_stream *is)
{ {
struct input_curl *c = (struct input_curl *)is; struct input_curl *c = (struct input_curl *)is;
struct tag *tag = c->tag; Tag *tag = c->tag;
c->tag = NULL; c->tag = NULL;
return tag; return tag;
...@@ -798,16 +798,15 @@ read_from_buffer(IcyMetaDataParser &icy, std::list<CurlInputBuffer> &buffers, ...@@ -798,16 +798,15 @@ read_from_buffer(IcyMetaDataParser &icy, std::list<CurlInputBuffer> &buffers,
static void static void
copy_icy_tag(struct input_curl *c) copy_icy_tag(struct input_curl *c)
{ {
struct tag *tag = c->icy.ReadTag(); Tag *tag = c->icy.ReadTag();
if (tag == NULL) if (tag == NULL)
return; return;
if (c->tag != NULL) delete c->tag;
tag_free(c->tag);
if (c->meta_name != NULL && !tag_has_type(tag, TAG_NAME)) if (c->meta_name != NULL && !tag->HasType(TAG_NAME))
tag_add_item(tag, TAG_NAME, c->meta_name); tag->AddItem(TAG_NAME, c->meta_name);
c->tag = tag; c->tag = tag;
} }
...@@ -931,11 +930,10 @@ input_curl_headerfunction(void *ptr, size_t size, size_t nmemb, void *stream) ...@@ -931,11 +930,10 @@ input_curl_headerfunction(void *ptr, size_t size, size_t nmemb, void *stream)
g_free(c->meta_name); g_free(c->meta_name);
c->meta_name = g_strndup(value, end - value); c->meta_name = g_strndup(value, end - value);
if (c->tag != NULL) delete c->tag;
tag_free(c->tag);
c->tag = tag_new(); c->tag = new Tag();
tag_add_item(c->tag, TAG_NAME, c->meta_name); c->tag->AddItem(TAG_NAME, c->meta_name);
} else if (g_ascii_strcasecmp(name, "icy-metaint") == 0) { } else if (g_ascii_strcasecmp(name, "icy-metaint") == 0) {
char buffer[64]; char buffer[64];
size_t icy_metaint; size_t icy_metaint;
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include "InputInternal.hxx" #include "InputInternal.hxx"
#include "InputStream.hxx" #include "InputStream.hxx"
#include "InputPlugin.hxx" #include "InputPlugin.hxx"
#include "tag.h" #include "Tag.hxx"
extern "C" { extern "C" {
#include <despotify.h> #include <despotify.h>
...@@ -42,7 +42,7 @@ struct DespotifyInputStream { ...@@ -42,7 +42,7 @@ struct DespotifyInputStream {
struct despotify_session *session; struct despotify_session *session;
struct ds_track *track; struct ds_track *track;
struct tag *tag; Tag *tag;
struct ds_pcm_data pcm; struct ds_pcm_data pcm;
size_t len_available; size_t len_available;
bool eof; bool eof;
...@@ -64,8 +64,7 @@ struct DespotifyInputStream { ...@@ -64,8 +64,7 @@ struct DespotifyInputStream {
} }
~DespotifyInputStream() { ~DespotifyInputStream() {
if (tag != NULL) delete tag;
tag_free(tag);
despotify_free_track(track); despotify_free_track(track);
} }
...@@ -216,11 +215,11 @@ input_despotify_seek(G_GNUC_UNUSED struct input_stream *is, ...@@ -216,11 +215,11 @@ input_despotify_seek(G_GNUC_UNUSED struct input_stream *is,
return false; return false;
} }
static struct tag * static Tag *
input_despotify_tag(struct input_stream *is) input_despotify_tag(struct input_stream *is)
{ {
DespotifyInputStream *ctx = (DespotifyInputStream *)is; DespotifyInputStream *ctx = (DespotifyInputStream *)is;
struct tag *tag = ctx->tag; Tag *tag = ctx->tag;
ctx->tag = NULL; ctx->tag = NULL;
......
...@@ -22,11 +22,12 @@ ...@@ -22,11 +22,12 @@
#include "InputInternal.hxx" #include "InputInternal.hxx"
#include "InputStream.hxx" #include "InputStream.hxx"
#include "InputPlugin.hxx" #include "InputPlugin.hxx"
#include "tag.h" #include "Tag.hxx"
#include <glib.h> #include <glib.h>
#include <assert.h> #include <assert.h>
#include <string.h>
#include <stdio.h> #include <stdio.h>
#undef G_LOG_DOMAIN #undef G_LOG_DOMAIN
...@@ -127,7 +128,7 @@ input_rewind_update(struct input_stream *is) ...@@ -127,7 +128,7 @@ input_rewind_update(struct input_stream *is)
r->CopyAttributes(); r->CopyAttributes();
} }
static struct tag * static Tag *
input_rewind_tag(struct input_stream *is) input_rewind_tag(struct input_stream *is)
{ {
RewindInputStream *r = (RewindInputStream *)is; RewindInputStream *r = (RewindInputStream *)is;
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <sys/types.h> #include <sys/types.h>
struct Tag;
struct input_stream; struct input_stream;
#ifdef __cplusplus #ifdef __cplusplus
...@@ -174,12 +175,12 @@ input_stream_lock_eof(struct input_stream *is); ...@@ -174,12 +175,12 @@ input_stream_lock_eof(struct input_stream *is);
* *
* The caller must lock the mutex. * 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 * if the tag has not changed since the last call
*/ */
gcc_nonnull(1) gcc_nonnull(1)
gcc_malloc gcc_malloc
struct tag * Tag *
input_stream_tag(struct input_stream *is); input_stream_tag(struct input_stream *is);
/** /**
...@@ -188,7 +189,7 @@ input_stream_tag(struct input_stream *is); ...@@ -188,7 +189,7 @@ input_stream_tag(struct input_stream *is);
*/ */
gcc_nonnull(1) gcc_nonnull(1)
gcc_malloc gcc_malloc
struct tag * Tag *
input_stream_lock_tag(struct input_stream *is); input_stream_lock_tag(struct input_stream *is);
/** /**
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <glib.h> #include <glib.h>
#include <assert.h> #include <assert.h>
#include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <fcntl.h> #include <fcntl.h>
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
#include <ao/ao.h> #include <ao/ao.h>
#include <glib.h> #include <glib.h>
#include <string.h>
#undef G_LOG_DOMAIN #undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "ao" #define G_LOG_DOMAIN "ao"
......
...@@ -38,6 +38,7 @@ class ServerSocket; ...@@ -38,6 +38,7 @@ class ServerSocket;
class HttpdClient; class HttpdClient;
class Page; class Page;
struct Encoder; struct Encoder;
struct Tag;
struct HttpdOutput final : private ServerSocket { struct HttpdOutput final : private ServerSocket {
struct audio_output base; struct audio_output base;
...@@ -195,7 +196,7 @@ struct HttpdOutput final : private ServerSocket { ...@@ -195,7 +196,7 @@ struct HttpdOutput final : private ServerSocket {
bool EncodeAndPlay(const void *chunk, size_t size, GError **error_r); bool EncodeAndPlay(const void *chunk, size_t size, GError **error_r);
void SendTag(const struct tag *tag); void SendTag(const Tag *tag);
private: private:
virtual void OnAccept(int fd, const sockaddr &address, virtual void OnAccept(int fd, const sockaddr &address,
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <string.h>
#include <errno.h> #include <errno.h>
#ifdef HAVE_LIBWRAP #ifdef HAVE_LIBWRAP
...@@ -484,7 +485,7 @@ httpd_output_pause(struct audio_output *ao) ...@@ -484,7 +485,7 @@ httpd_output_pause(struct audio_output *ao)
} }
inline void inline void
HttpdOutput::SendTag(const struct tag *tag) HttpdOutput::SendTag(const Tag *tag)
{ {
assert(tag != NULL); assert(tag != NULL);
...@@ -523,7 +524,7 @@ HttpdOutput::SendTag(const struct tag *tag) ...@@ -523,7 +524,7 @@ HttpdOutput::SendTag(const struct tag *tag)
TAG_NUM_OF_ITEM_TYPES TAG_NUM_OF_ITEM_TYPES
}; };
metadata = icy_server_metadata_page(tag, &types[0]); metadata = icy_server_metadata_page(*tag, &types[0]);
if (metadata != NULL) { if (metadata != NULL) {
const ScopeLock protect(mutex); const ScopeLock protect(mutex);
for (auto &client : clients) for (auto &client : clients)
...@@ -533,7 +534,7 @@ HttpdOutput::SendTag(const struct tag *tag) ...@@ -533,7 +534,7 @@ HttpdOutput::SendTag(const struct tag *tag)
} }
static void 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); HttpdOutput *httpd = Cast(ao);
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <jack/ringbuffer.h> #include <jack/ringbuffer.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <stdio.h> #include <stdio.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
......
...@@ -329,7 +329,7 @@ roar_tag_convert(enum tag_type type, bool *is_uuid) ...@@ -329,7 +329,7 @@ roar_tag_convert(enum tag_type type, bool *is_uuid)
} }
static void 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; RoarOutput *self = (RoarOutput *)ao;
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <stdio.h> #include <stdio.h>
#undef G_LOG_DOMAIN #undef G_LOG_DOMAIN
...@@ -482,7 +483,7 @@ my_shout_pause(struct audio_output *ao) ...@@ -482,7 +483,7 @@ my_shout_pause(struct audio_output *ao)
} }
static void 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 artist[size];
char title[size]; char title[size];
...@@ -508,7 +509,7 @@ shout_tag_to_metadata(const struct tag *tag, char *dest, size_t 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, static void my_shout_set_tag(struct audio_output *ao,
const struct tag *tag) const Tag *tag)
{ {
ShoutOutput *sd = (ShoutOutput *)ao; ShoutOutput *sd = (ShoutOutput *)ao;
GError *error = nullptr; GError *error = nullptr;
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include "MemoryPlaylistProvider.hxx" #include "MemoryPlaylistProvider.hxx"
#include "input_stream.h" #include "input_stream.h"
#include "Song.hxx" #include "Song.hxx"
#include "tag.h" #include "Tag.hxx"
#include <glib.h> #include <glib.h>
...@@ -169,8 +169,8 @@ asx_text(G_GNUC_UNUSED GMarkupParseContext *context, ...@@ -169,8 +169,8 @@ asx_text(G_GNUC_UNUSED GMarkupParseContext *context,
case AsxParser::ENTRY: case AsxParser::ENTRY:
if (parser->tag != TAG_NUM_OF_ITEM_TYPES) { if (parser->tag != TAG_NUM_OF_ITEM_TYPES) {
if (parser->song->tag == NULL) if (parser->song->tag == NULL)
parser->song->tag = tag_new(); parser->song->tag = new Tag();
tag_add_item_n(parser->song->tag, parser->tag, parser->song->tag->AddItem(parser->tag,
text, text_len); text, text_len);
} }
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include "config.h" #include "config.h"
#include "CuePlaylistPlugin.hxx" #include "CuePlaylistPlugin.hxx"
#include "PlaylistPlugin.hxx" #include "PlaylistPlugin.hxx"
#include "tag.h" #include "Tag.hxx"
#include "Song.hxx" #include "Song.hxx"
#include "input_stream.h" #include "input_stream.h"
#include "cue/CueParser.hxx" #include "cue/CueParser.hxx"
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include "DespotifyPlaylistPlugin.hxx" #include "DespotifyPlaylistPlugin.hxx"
#include "DespotifyUtils.hxx" #include "DespotifyUtils.hxx"
#include "MemoryPlaylistProvider.hxx" #include "MemoryPlaylistProvider.hxx"
#include "tag.h" #include "Tag.hxx"
#include "Song.hxx" #include "Song.hxx"
extern "C" { extern "C" {
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include "config.h" #include "config.h"
#include "EmbeddedCuePlaylistPlugin.hxx" #include "EmbeddedCuePlaylistPlugin.hxx"
#include "PlaylistPlugin.hxx" #include "PlaylistPlugin.hxx"
#include "tag.h" #include "Tag.hxx"
#include "TagHandler.hxx" #include "TagHandler.hxx"
#include "TagId3.hxx" #include "TagId3.hxx"
#include "ApeTag.hxx" #include "ApeTag.hxx"
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include "ExtM3uPlaylistPlugin.hxx" #include "ExtM3uPlaylistPlugin.hxx"
#include "PlaylistPlugin.hxx" #include "PlaylistPlugin.hxx"
#include "Song.hxx" #include "Song.hxx"
#include "tag.h" #include "Tag.hxx"
#include "util/StringUtil.hxx" #include "util/StringUtil.hxx"
#include "TextInputStream.hxx" #include "TextInputStream.hxx"
...@@ -70,13 +70,13 @@ extm3u_close(struct playlist_provider *_playlist) ...@@ -70,13 +70,13 @@ extm3u_close(struct playlist_provider *_playlist)
* *
* @param line the rest of the input line after the colon * @param line the rest of the input line after the colon
*/ */
static struct tag * static Tag *
extm3u_parse_tag(const char *line) extm3u_parse_tag(const char *line)
{ {
long duration; long duration;
char *endptr; char *endptr;
const char *name; const char *name;
struct tag *tag; Tag *tag;
duration = strtol(line, &endptr, 10); duration = strtol(line, &endptr, 10);
if (endptr[0] != ',') if (endptr[0] != ',')
...@@ -93,14 +93,14 @@ extm3u_parse_tag(const char *line) ...@@ -93,14 +93,14 @@ extm3u_parse_tag(const char *line)
object */ object */
return NULL; return NULL;
tag = tag_new(); tag = new Tag();
tag->time = duration; tag->time = duration;
/* unfortunately, there is no real specification for the /* unfortunately, there is no real specification for the
EXTM3U format, so we must assume that the string after the EXTM3U format, so we must assume that the string after the
comma is opaque, and is just the song name*/ comma is opaque, and is just the song name*/
if (*name != 0) if (*name != 0)
tag_add_item(tag, TAG_NAME, name); tag->AddItem(TAG_NAME, name);
return tag; return tag;
} }
...@@ -109,23 +109,21 @@ static Song * ...@@ -109,23 +109,21 @@ static Song *
extm3u_read(struct playlist_provider *_playlist) extm3u_read(struct playlist_provider *_playlist)
{ {
ExtM3uPlaylist *playlist = (ExtM3uPlaylist *)_playlist; ExtM3uPlaylist *playlist = (ExtM3uPlaylist *)_playlist;
struct tag *tag = NULL; Tag *tag = NULL;
std::string line; std::string line;
const char *line_s; const char *line_s;
Song *song; Song *song;
do { do {
if (!playlist->tis->ReadLine(line)) { if (!playlist->tis->ReadLine(line)) {
if (tag != NULL) delete tag;
tag_free(tag);
return NULL; return NULL;
} }
line_s = line.c_str(); line_s = line.c_str();
if (g_str_has_prefix(line_s, "#EXTINF:")) { if (g_str_has_prefix(line_s, "#EXTINF:")) {
if (tag != NULL) delete tag;
tag_free(tag);
tag = extm3u_parse_tag(line_s + 8); tag = extm3u_parse_tag(line_s + 8);
continue; continue;
} }
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include "MemoryPlaylistProvider.hxx" #include "MemoryPlaylistProvider.hxx"
#include "input_stream.h" #include "input_stream.h"
#include "Song.hxx" #include "Song.hxx"
#include "tag.h" #include "Tag.hxx"
#include <glib.h> #include <glib.h>
...@@ -71,8 +71,8 @@ pls_parser(GKeyFile *keyfile, std::forward_list<SongPointer> &songs) ...@@ -71,8 +71,8 @@ pls_parser(GKeyFile *keyfile, std::forward_list<SongPointer> &songs)
g_free(key); g_free(key);
if(error == NULL && value){ if(error == NULL && value){
if (song->tag == NULL) if (song->tag == NULL)
song->tag = tag_new(); song->tag = new Tag();
tag_add_item(song->tag,TAG_TITLE, value); song->tag->AddItem(TAG_TITLE, value);
} }
/* Ignore errors? Most likely value not present */ /* Ignore errors? Most likely value not present */
if(error) g_error_free(error); if(error) g_error_free(error);
...@@ -85,7 +85,7 @@ pls_parser(GKeyFile *keyfile, std::forward_list<SongPointer> &songs) ...@@ -85,7 +85,7 @@ pls_parser(GKeyFile *keyfile, std::forward_list<SongPointer> &songs)
g_free(key); g_free(key);
if(error == NULL && length > 0){ if(error == NULL && length > 0){
if (song->tag == NULL) if (song->tag == NULL)
song->tag = tag_new(); song->tag = new Tag();
song->tag->time = length; song->tag->time = length;
} }
/* Ignore errors? Most likely value not present */ /* Ignore errors? Most likely value not present */
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include "MemoryPlaylistProvider.hxx" #include "MemoryPlaylistProvider.hxx"
#include "input_stream.h" #include "input_stream.h"
#include "Song.hxx" #include "Song.hxx"
#include "tag.h" #include "Tag.hxx"
#include <glib.h> #include <glib.h>
...@@ -166,8 +166,8 @@ rss_text(G_GNUC_UNUSED GMarkupParseContext *context, ...@@ -166,8 +166,8 @@ rss_text(G_GNUC_UNUSED GMarkupParseContext *context,
case RssParser::ITEM: case RssParser::ITEM:
if (parser->tag != TAG_NUM_OF_ITEM_TYPES) { if (parser->tag != TAG_NUM_OF_ITEM_TYPES) {
if (parser->song->tag == NULL) if (parser->song->tag == NULL)
parser->song->tag = tag_new(); parser->song->tag = new Tag();
tag_add_item_n(parser->song->tag, parser->tag, parser->song->tag->AddItem(parser->tag,
text, text_len); text, text_len);
} }
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include "conf.h" #include "conf.h"
#include "input_stream.h" #include "input_stream.h"
#include "Song.hxx" #include "Song.hxx"
#include "tag.h" #include "Tag.hxx"
#include <glib.h> #include <glib.h>
#include <yajl/yajl_parse.h> #include <yajl/yajl_parse.h>
...@@ -204,16 +204,16 @@ static int handle_end_map(void *ctx) ...@@ -204,16 +204,16 @@ static int handle_end_map(void *ctx)
data->got_url = 0; data->got_url = 0;
Song *s; Song *s;
struct tag *t;
char *u; char *u;
u = g_strconcat(data->stream_url, "?client_id=", soundcloud_config.apikey, NULL); u = g_strconcat(data->stream_url, "?client_id=", soundcloud_config.apikey, NULL);
s = Song::NewRemote(u); s = Song::NewRemote(u);
g_free(u); g_free(u);
t = tag_new();
Tag *t = new Tag();
t->time = data->duration / 1000; t->time = data->duration / 1000;
if (data->title != NULL) if (data->title != NULL)
tag_add_item(t, TAG_NAME, data->title); t->AddItem(TAG_NAME, data->title);
s->tag = t; s->tag = t;
data->songs.emplace_front(s); data->songs.emplace_front(s);
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include "XspfPlaylistPlugin.hxx" #include "XspfPlaylistPlugin.hxx"
#include "MemoryPlaylistProvider.hxx" #include "MemoryPlaylistProvider.hxx"
#include "input_stream.h" #include "input_stream.h"
#include "tag.h" #include "Tag.hxx"
#include <glib.h> #include <glib.h>
...@@ -177,9 +177,8 @@ xspf_text(G_GNUC_UNUSED GMarkupParseContext *context, ...@@ -177,9 +177,8 @@ xspf_text(G_GNUC_UNUSED GMarkupParseContext *context,
if (parser->song != NULL && if (parser->song != NULL &&
parser->tag != TAG_NUM_OF_ITEM_TYPES) { parser->tag != TAG_NUM_OF_ITEM_TYPES) {
if (parser->song->tag == NULL) if (parser->song->tag == NULL)
parser->song->tag = tag_new(); parser->song->tag = new Tag();
tag_add_item_n(parser->song->tag, parser->tag, parser->song->tag->AddItem(parser->tag, text, text_len);
text, text_len);
} }
break; break;
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include "Song.hxx" #include "Song.hxx"
#include "PlaylistVector.hxx" #include "PlaylistVector.hxx"
#include "conf.h" #include "conf.h"
#include "tag.h" #include "Tag.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include <iostream> #include <iostream>
......
...@@ -106,7 +106,7 @@ decoder_data(G_GNUC_UNUSED struct decoder *decoder, ...@@ -106,7 +106,7 @@ decoder_data(G_GNUC_UNUSED struct decoder *decoder,
enum decoder_command enum decoder_command
decoder_tag(G_GNUC_UNUSED struct decoder *decoder, decoder_tag(G_GNUC_UNUSED struct decoder *decoder,
G_GNUC_UNUSED struct input_stream *is, G_GNUC_UNUSED struct input_stream *is,
G_GNUC_UNUSED const struct tag *tag) G_GNUC_UNUSED const Tag *tag)
{ {
return DECODE_COMMAND_NONE; return DECODE_COMMAND_NONE;
} }
...@@ -232,7 +232,7 @@ int main(int argc, char **argv) ...@@ -232,7 +232,7 @@ int main(int argc, char **argv)
(song->start_ms / 1000) % 60); (song->start_ms / 1000) % 60);
if (song->tag != NULL) if (song->tag != NULL)
tag_save(stdout, song->tag); tag_save(stdout, *song->tag);
song->Free(); song->Free();
} }
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include "TagRva2.hxx" #include "TagRva2.hxx"
#include "replay_gain_info.h" #include "replay_gain_info.h"
#include "conf.h" #include "conf.h"
#include "tag.h" #include "Tag.hxx"
#include <id3tag.h> #include <id3tag.h>
...@@ -41,23 +41,13 @@ config_get_string(gcc_unused enum ConfigOption option, ...@@ -41,23 +41,13 @@ config_get_string(gcc_unused enum ConfigOption option,
return default_value; return default_value;
} }
struct tag *
tag_new(void)
{
return NULL;
}
void void
tag_add_item_n(gcc_unused struct tag *tag, gcc_unused enum tag_type type, Tag::AddItem(gcc_unused enum tag_type type,
gcc_unused const char *value, gcc_unused size_t len) gcc_unused const char *value)
{ {
} }
void Tag::~Tag() {}
tag_free(struct tag *tag)
{
g_free(tag);
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
......
...@@ -92,7 +92,7 @@ decoder_data(G_GNUC_UNUSED struct decoder *decoder, ...@@ -92,7 +92,7 @@ decoder_data(G_GNUC_UNUSED struct decoder *decoder,
enum decoder_command enum decoder_command
decoder_tag(G_GNUC_UNUSED struct decoder *decoder, decoder_tag(G_GNUC_UNUSED struct decoder *decoder,
G_GNUC_UNUSED struct input_stream *is, G_GNUC_UNUSED struct input_stream *is,
G_GNUC_UNUSED const struct tag *tag) G_GNUC_UNUSED const Tag *tag)
{ {
return DECODE_COMMAND_NONE; return DECODE_COMMAND_NONE;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment