tag: convert to C++

This commit is contained in:
Max Kellermann 2013-07-30 20:11:57 +02:00
parent 6a9ab8bc0e
commit 06f898cc12
105 changed files with 711 additions and 723 deletions

View File

@ -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 = \
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 \

View File

@ -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"

View File

@ -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"

View File

@ -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>

View File

@ -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"

View File

@ -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;
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,
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:

View File

@ -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"

View File

@ -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>

View File

@ -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)
* (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)
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)
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,
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,
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,
/* 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,
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;
} }

View File

@ -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,
*/ */
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.

View File

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

View File

@ -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()
/* 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);
} }
/** /**

View File

@ -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 {
* 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 {
*/ */
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),

View File

@ -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;
/** /**

View File

@ -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,
{ {
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;

View File

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

View File

@ -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);
* *
* @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.

View File

@ -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

View File

@ -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 {
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)
* @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);

View File

@ -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()
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)
} }
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)
} }
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)
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)
/* 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);

View File

@ -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:
*/ */
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;
} }

View File

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

View File

@ -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,
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

View File

@ -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:

View File

@ -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)
: 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);

View File

@ -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"

View File

@ -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

View File

@ -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 {
* 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.

View File

@ -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

View File

@ -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"

View File

@ -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,

View File

@ -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);

View File

@ -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 {
* 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
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,

View File

@ -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

View File

@ -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 @@
#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 {
* 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)
} }
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,
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)
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)
/* 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)
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();

View File

@ -27,7 +27,7 @@
struct config_param; struct config_param;
struct input_stream; struct input_stream;
struct tag; struct Tag;
struct Song; struct Song;
/** /**

View File

@ -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,
{ {
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;

View File

@ -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
} 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
void void
Song::Free() Song::Free()
{ {
if (tag != nullptr) delete tag;
tag_free(tag);
g_free(this); g_free(this);
} }

View File

@ -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 {
*/ */
struct list_head siblings; struct list_head siblings;
struct tag *tag; Tag *tag;
Directory *parent; Directory *parent;
time_t mtime; time_t mtime;

View File

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

View File

@ -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 {
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:
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;

View File

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

View File

@ -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)
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,
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,
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,
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,
} }
if (song->tag != NULL) if (song->tag != NULL)
tag_end_add(song->tag); song->tag->EndAdd();
return song; return song;
} }

View File

@ -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" {
#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)
* 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)
} }
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));

View File

@ -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()
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()
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()
/* 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()
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()
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;
} }

View File

@ -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 @@
#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 {
#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)
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)
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) tag_pool_lock.lock();
return nullptr; for (unsigned i = 0; i < num_items; i++)
items[i] = tag_pool_dup_item(other.items[i]);
ret = tag_new(); tag_pool_lock.unlock();
ret->time = tag->time; }
ret->has_playlist = tag->has_playlist;
ret->num_items = tag->num_items;
ret->items = ret->num_items > 0
? (struct tag_item **)g_malloc(items_size(tag))
: nullptr;
tag_pool_lock.lock();
for (unsigned i = 0; i < tag->num_items; i++)
ret->items[i] = tag_pool_dup_item(tag->items[i]);
tag_pool_lock.unlock();
return ret;
} }
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)
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)
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; return false;
if (tag1->time != tag2->time) if (num_items != other.num_items)
return false; return false;
if (tag1->num_items != tag2->num_items) for (unsigned i = 0; i < num_items; i++) {
return false; if (items[i]->type != other.items[i]->type)
for (unsigned i = 0; i < tag1->num_items; i++) {
if (tag1->items[i]->type != tag2->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)
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)
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,
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;
}
if (!value || !len)
return; return;
tag_add_item_internal(tag, type, value, len); if (value == nullptr || len == 0)
return;
AddItemInternal(type, value, len);
}
void
Tag::AddItem(tag_type type, const char *value)
{
AddItem(type, value, strlen(value));
} }

218
src/Tag.hxx Normal file
View File

@ -0,0 +1,218 @@
/*
* Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_TAG_HXX
#define MPD_TAG_HXX
#include "TagType.h"
#include "gcc.h"
#include <algorithm>
#include <stddef.h>
/**
* One tag value. It is a mapping of #tag_type to am arbitrary string
* value. Each tag can have multiple items of one tag type (although
* few clients support that).
*/
struct TagItem {
/** the type of this item */
enum tag_type type;
/**
* the value of this tag; this is a variable length string
*/
char value[sizeof(long)];
} gcc_packed;
/**
* The meta information about a song file. It is a MPD specific
* subset of tags (e.g. from ID3, vorbis comments, ...).
*/
struct Tag {
/**
* The duration of the song (in seconds). A value of zero
* means that the length is unknown. If the duration is
* really between zero and one second, you should round up to
* 1.
*/
int time;
/**
* Does this file have an embedded playlist (e.g. embedded CUE
* sheet)?
*/
bool has_playlist;
/** an array of tag items */
TagItem **items;
/** the total number of tag items in the #items array */
unsigned num_items;
/**
* Create an empty tag.
*/
Tag():time(-1), has_playlist(false),
items(nullptr), num_items(0) {}
Tag(const Tag &other);
Tag(Tag &&other)
:time(other.time), has_playlist(other.has_playlist),
items(other.items), num_items(other.num_items) {
other.items = nullptr;
other.num_items = 0;
}
/**
* Free the tag object and all its items.
*/
~Tag();
Tag &operator=(const Tag &other) = delete;
Tag &operator=(Tag &&other) {
time = other.time;
has_playlist = other.has_playlist;
std::swap(items, other.items);
std::swap(num_items, other.num_items);
return *this;
}
/**
* Returns true if the tag contains no items. This ignores the "time"
* attribute.
*/
bool IsEmpty() const {
return num_items == 0;
}
/**
* Returns true if the tag contains any information.
*/
bool IsDefined() const {
return !IsEmpty() || time >= 0;
}
void DeleteItem(unsigned i);
/**
* Clear all tag items with the specified type.
*/
void ClearItemsByType(tag_type type);
/**
* Gives an optional hint to the tag library that we will now
* add several tag items; this is used by the library to
* optimize memory allocation. Only one tag may be in this
* state, and this tag must not have any items yet. You must
* call tag_end_add() when you are done.
*/
void BeginAdd();
/**
* Finishes the operation started with tag_begin_add().
*/
void EndAdd();
/**
* Appends a new tag item.
*
* @param type the type of the new tag item
* @param value the value of the tag item (not null-terminated)
* @param len the length of #value
*/
void AddItem(tag_type type, const char *value, size_t len);
/**
* Appends a new tag item.
*
* @param tag the #tag object
* @param type the type of the new tag item
* @param value the value of the tag item (null-terminated)
*/
void AddItem(tag_type type, const char *value);
/**
* Merges the data from two tags. If both tags share data for the
* same tag_type, only data from "add" is used.
*
* @return a newly allocated tag
*/
gcc_malloc
static Tag *Merge(const Tag &base, const Tag &add);
/**
* Merges the data from two tags. Any of the two may be NULL. Both
* are freed by this function.
*
* @return a newly allocated tag
*/
gcc_malloc
static Tag *MergeReplace(Tag *base, Tag *add);
/**
* Returns the first value of the specified tag type, or NULL if none
* is present in this tag object.
*/
gcc_pure
const char *GetValue(tag_type type) const;
/**
* Checks whether the tag contains one or more items with
* the specified type.
*/
bool HasType(tag_type type) const;
/**
* Compares two tags, including the duration and all tag items. The
* order of the tag items matters.
*/
gcc_pure
bool Equals(const Tag &other) const;
private:
void AddItemInternal(tag_type type, const char *value, size_t len);
};
/**
* Parse the string, and convert it into a #tag_type. Returns
* #TAG_NUM_OF_ITEM_TYPES if the string could not be recognized.
*/
enum tag_type
tag_name_parse(const char *name);
/**
* Parse the string, and convert it into a #tag_type. Returns
* #TAG_NUM_OF_ITEM_TYPES if the string could not be recognized.
*
* Case does not matter.
*/
enum tag_type
tag_name_parse_i(const char *name);
/**
* Initializes the tag library.
*/
void
tag_lib_init();
#endif

View File

@ -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)
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 = {
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;

View File

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

View File

@ -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
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

View File

@ -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;
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)
} }
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,
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)
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)
} }
} }
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;

View File

@ -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

View File

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

View File

@ -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

View File

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

View File

@ -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

View File

@ -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,
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);

View File

@ -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()
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)
} }
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)
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)
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)
? 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)
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;

View File

@ -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 {
IGNORE_TRACK, IGNORE_TRACK,
} state; } state;
struct tag *tag; Tag *tag;
char *filename; char *filename;
@ -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",

View File

@ -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,
} }
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,
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)
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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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,
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);

View File

@ -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,
} }
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);

View File

@ -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,
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

View File

@ -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 {
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 {
*/ */
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,
#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)
} }
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)
#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()
} }
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()
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)
{ {
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)
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)
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()) {}

View File

@ -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)
{ {

View File

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

View File

@ -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

View File

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

View File

@ -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
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

View File

@ -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

View File

@ -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>

View File

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

View File

@ -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 {
/** 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)
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)
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,
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)
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;

View File

@ -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 {
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 {
} }
~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,
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;

View File

@ -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)
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;

View File

@ -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);
* *
* 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);
*/ */
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);
/** /**

View File

@ -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>

View File

@ -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"

View File

@ -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 {
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,

View File

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

View File

@ -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>

View File

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

View File

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

View File

@ -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,9 +169,9 @@ 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);
} }
break; break;

View File

@ -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"

View File

@ -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" {

View File

@ -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"

View File

@ -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)
* *
* @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)
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 *
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;
} }

View File

@ -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)
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)
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 */

View File

@ -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,9 +166,9 @@ 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);
} }
break; break;

View File

@ -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)
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);

View File

@ -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,
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;

215
src/tag.h
View File

@ -1,215 +0,0 @@
/*
* Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_TAG_H
#define MPD_TAG_H
#include "TagType.h"
#include "gcc.h"
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
/**
* One tag value. It is a mapping of #tag_type to am arbitrary string
* value. Each tag can have multiple items of one tag type (although
* few clients support that).
*/
struct tag_item {
/** the type of this item */
enum tag_type type;
/**
* the value of this tag; this is a variable length string
*/
char value[sizeof(long)];
} gcc_packed;
/**
* The meta information about a song file. It is a MPD specific
* subset of tags (e.g. from ID3, vorbis comments, ...).
*/
struct tag {
/**
* The duration of the song (in seconds). A value of zero
* means that the length is unknown. If the duration is
* really between zero and one second, you should round up to
* 1.
*/
int time;
/**
* Does this file have an embedded playlist (e.g. embedded CUE
* sheet)?
*/
bool has_playlist;
/** an array of tag items */
struct tag_item **items;
/** the total number of tag items in the #items array */
unsigned num_items;
};
#ifdef __cplusplus
extern "C" {
#endif
/**
* Parse the string, and convert it into a #tag_type. Returns
* #TAG_NUM_OF_ITEM_TYPES if the string could not be recognized.
*/
enum tag_type
tag_name_parse(const char *name);
/**
* Parse the string, and convert it into a #tag_type. Returns
* #TAG_NUM_OF_ITEM_TYPES if the string could not be recognized.
*
* Case does not matter.
*/
enum tag_type
tag_name_parse_i(const char *name);
/**
* Creates an empty #tag.
*/
struct tag *tag_new(void);
/**
* Initializes the tag library.
*/
void tag_lib_init(void);
/**
* Clear all tag items with the specified type.
*/
void tag_clear_items_by_type(struct tag *tag, enum tag_type type);
/**
* Frees a #tag object and all its items.
*/
void tag_free(struct tag *tag);
/**
* Gives an optional hint to the tag library that we will now add
* several tag items; this is used by the library to optimize memory
* allocation. Only one tag may be in this state, and this tag must
* not have any items yet. You must call tag_end_add() when you are
* done.
*/
void tag_begin_add(struct tag *tag);
/**
* Finishes the operation started with tag_begin_add().
*/
void tag_end_add(struct tag *tag);
/**
* Appends a new tag item.
*
* @param tag the #tag object
* @param type the type of the new tag item
* @param value the value of the tag item (not null-terminated)
* @param len the length of #value
*/
void tag_add_item_n(struct tag *tag, enum tag_type type,
const char *value, size_t len);
/**
* Appends a new tag item.
*
* @param tag the #tag object
* @param type the type of the new tag item
* @param value the value of the tag item (null-terminated)
*/
static inline void
tag_add_item(struct tag *tag, enum tag_type type, const char *value)
{
tag_add_item_n(tag, type, value, strlen(value));
}
/**
* Duplicates a #tag object.
*/
struct tag *tag_dup(const struct tag *tag);
/**
* Merges the data from two tags. If both tags share data for the
* same tag_type, only data from "add" is used.
*
* @return a newly allocated tag, which must be freed with tag_free()
*/
struct tag *
tag_merge(const struct tag *base, const struct tag *add);
/**
* Merges the data from two tags. Any of the two may be NULL. Both
* are freed by this function.
*
* @return a newly allocated tag, which must be freed with tag_free()
*/
struct tag *
tag_merge_replace(struct tag *base, struct tag *add);
/**
* Returns true if the tag contains no items. This ignores the "time"
* attribute.
*/
static inline bool
tag_is_empty(const struct tag *tag)
{
return tag->num_items == 0;
}
/**
* Returns true if the tag contains any information.
*/
static inline bool
tag_is_defined(const struct tag *tag)
{
return !tag_is_empty(tag) || tag->time >= 0;
}
/**
* Returns the first value of the specified tag type, or NULL if none
* is present in this tag object.
*/
const char *
tag_get_value(const struct tag *tag, enum tag_type type);
/**
* Checks whether the tag contains one or more items with
* the specified type.
*/
bool tag_has_type(const struct tag *tag, enum tag_type type);
/**
* Compares two tags, including the duration and all tag items. The
* order of the tag items matters.
*/
bool tag_equal(const struct tag *tag1, const struct tag *tag2);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -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>

View File

@ -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)
(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();
} }

View File

@ -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,
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)
{ {

Some files were not shown because too many files have changed in this diff Show More