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

tag: convert to C++

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