aboutsummaryrefslogtreecommitdiffstats
path: root/src/tag
diff options
context:
space:
mode:
Diffstat (limited to 'src/tag')
-rw-r--r--src/tag/Aiff.cxx2
-rw-r--r--src/tag/ApeLoader.cxx8
-rw-r--r--src/tag/ApeTag.hxx2
-rw-r--r--src/tag/Riff.cxx1
-rw-r--r--src/tag/Tag.cxx105
-rw-r--r--src/tag/Tag.hxx29
-rw-r--r--src/tag/TagBuilder.cxx150
-rw-r--r--src/tag/TagBuilder.hxx40
-rw-r--r--src/tag/TagConfig.cxx7
-rw-r--r--src/tag/TagConfig.hxx2
-rw-r--r--src/tag/TagId3.cxx156
-rw-r--r--src/tag/TagId3.hxx10
-rw-r--r--src/tag/TagPool.cxx71
-rw-r--r--src/tag/TagRva2.cxx4
-rw-r--r--src/tag/TagRva2.hxx2
-rw-r--r--src/tag/TagString.cxx15
-rw-r--r--src/tag/TagTable.cxx10
-rw-r--r--src/tag/TagTable.hxx9
18 files changed, 330 insertions, 293 deletions
diff --git a/src/tag/Aiff.cxx b/src/tag/Aiff.cxx
index 73e46e49f..84c386678 100644
--- a/src/tag/Aiff.cxx
+++ b/src/tag/Aiff.cxx
@@ -26,9 +26,7 @@
#include <limits>
#include <stdint.h>
-#include <sys/types.h>
#include <sys/stat.h>
-#include <unistd.h>
#include <string.h>
static constexpr Domain aiff_domain("aiff");
diff --git a/src/tag/ApeLoader.cxx b/src/tag/ApeLoader.cxx
index 8251efe10..febe4467d 100644
--- a/src/tag/ApeLoader.cxx
+++ b/src/tag/ApeLoader.cxx
@@ -22,8 +22,6 @@
#include "system/ByteOrder.hxx"
#include "fs/FileSystem.hxx"
-#include <glib.h>
-
#include <stdint.h>
#include <assert.h>
#include <stdio.h>
@@ -61,9 +59,9 @@ ape_scan_internal(FILE *fp, ApeTagCallback callback)
remaining -= sizeof(footer);
assert(remaining > 10);
- char *buffer = (char *)g_malloc(remaining);
+ char *buffer = new char[remaining];
if (fread(buffer, 1, remaining, fp) != remaining) {
- g_free(buffer);
+ delete[] buffer;
return false;
}
@@ -98,7 +96,7 @@ ape_scan_internal(FILE *fp, ApeTagCallback callback)
remaining -= size;
}
- g_free(buffer);
+ delete[] buffer;
return true;
}
diff --git a/src/tag/ApeTag.hxx b/src/tag/ApeTag.hxx
index e35edc381..d2c0365c7 100644
--- a/src/tag/ApeTag.hxx
+++ b/src/tag/ApeTag.hxx
@@ -34,6 +34,6 @@ extern const struct tag_table ape_tags[];
*/
bool
tag_ape_scan2(Path path_fs,
- const struct tag_handler *handler, void *handler_ctx);
+ const tag_handler *handler, void *handler_ctx);
#endif
diff --git a/src/tag/Riff.cxx b/src/tag/Riff.cxx
index ac162bc24..0f8f265fc 100644
--- a/src/tag/Riff.cxx
+++ b/src/tag/Riff.cxx
@@ -26,7 +26,6 @@
#include <limits>
#include <stdint.h>
-#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
diff --git a/src/tag/Tag.cxx b/src/tag/Tag.cxx
index 6bf070429..d6b3abe55 100644
--- a/src/tag/Tag.cxx
+++ b/src/tag/Tag.cxx
@@ -22,9 +22,9 @@
#include "TagPool.hxx"
#include "TagString.hxx"
#include "TagSettings.h"
+#include "TagBuilder.hxx"
#include "util/ASCII.hxx"
-#include <glib.h>
#include <assert.h>
#include <string.h>
@@ -58,12 +58,6 @@ tag_name_parse_i(const char *name)
return TAG_NUM_OF_ITEM_TYPES;
}
-static size_t
-items_size(const Tag &tag)
-{
- return tag.num_items * sizeof(TagItem *);
-}
-
void
Tag::Clear()
{
@@ -75,28 +69,18 @@ Tag::Clear()
tag_pool_put_item(items[i]);
tag_pool_lock.unlock();
- g_free(items);
+ delete[] items;
items = nullptr;
num_items = 0;
}
-Tag::~Tag()
-{
- tag_pool_lock.lock();
- for (int i = num_items; --i >= 0; )
- tag_pool_put_item(items[i]);
- tag_pool_lock.unlock();
-
- g_free(items);
-}
-
Tag::Tag(const Tag &other)
:time(other.time), has_playlist(other.has_playlist),
items(nullptr),
num_items(other.num_items)
{
if (num_items > 0) {
- items = (TagItem **)g_malloc(items_size(other));
+ items = new TagItem *[num_items];
tag_pool_lock.lock();
for (unsigned i = 0; i < num_items; i++)
@@ -108,46 +92,9 @@ Tag::Tag(const Tag &other)
Tag *
Tag::Merge(const Tag &base, const Tag &add)
{
- unsigned n;
-
- /* allocate new tag object */
-
- 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
- ? (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]);
-
- n = add.num_items;
-
- /* copy additional items from "base" */
-
- 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();
-
- assert(n <= ret->num_items);
-
- if (n < ret->num_items) {
- /* some tags were not copied - shrink ret->items */
- assert(n > 0);
-
- ret->num_items = n;
- ret->items = (TagItem **)
- g_realloc(ret->items, items_size(*ret));
- }
-
- return ret;
+ TagBuilder builder(add);
+ builder.Complement(base);
+ return builder.CommitNew();
}
Tag *
@@ -183,43 +130,3 @@ Tag::HasType(TagType type) const
{
return GetValue(type) != nullptr;
}
-
-void
-Tag::AddItemInternal(TagType type, const char *value, size_t len)
-{
- unsigned int i = num_items;
-
- char *p = FixTagString(value, len);
- if (p != nullptr) {
- value = p;
- len = strlen(value);
- }
-
- num_items++;
-
- items = (TagItem **)g_realloc(items, items_size(*this));
-
- tag_pool_lock.lock();
- items[i] = tag_pool_get_item(type, value, len);
- tag_pool_lock.unlock();
-
- g_free(p);
-}
-
-void
-Tag::AddItem(TagType type, const char *value, size_t len)
-{
- if (ignore_tag_items[type])
- return;
-
- if (value == nullptr || len == 0)
- return;
-
- AddItemInternal(type, value, len);
-}
-
-void
-Tag::AddItem(TagType type, const char *value)
-{
- AddItem(type, value, strlen(value));
-}
diff --git a/src/tag/Tag.hxx b/src/tag/Tag.hxx
index 5846e7a9d..480115c5b 100644
--- a/src/tag/Tag.hxx
+++ b/src/tag/Tag.hxx
@@ -20,8 +20,8 @@
#ifndef MPD_TAG_HXX
#define MPD_TAG_HXX
-#include "TagType.h"
-#include "TagItem.hxx"
+#include "TagType.h" // IWYU pragma: export
+#include "TagItem.hxx" // IWYU pragma: export
#include "Compiler.h"
#include <algorithm>
@@ -71,7 +71,9 @@ struct Tag {
/**
* Free the tag object and all its items.
*/
- ~Tag();
+ ~Tag() {
+ Clear();
+ }
Tag &operator=(const Tag &other) = delete;
@@ -104,24 +106,6 @@ struct Tag {
void Clear();
/**
- * 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(TagType 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(TagType type, const char *value);
-
- /**
* Merges the data from two tags. If both tags share data for the
* same TagType, only data from "add" is used.
*
@@ -152,9 +136,6 @@ struct Tag {
*/
gcc_pure
bool HasType(TagType type) const;
-
-private:
- void AddItemInternal(TagType type, const char *value, size_t len);
};
/**
diff --git a/src/tag/TagBuilder.cxx b/src/tag/TagBuilder.cxx
index 25e5cc24b..462f5c49a 100644
--- a/src/tag/TagBuilder.cxx
+++ b/src/tag/TagBuilder.cxx
@@ -24,23 +24,90 @@
#include "TagString.hxx"
#include "Tag.hxx"
-#include <glib.h>
-
#include <assert.h>
#include <string.h>
+#include <stdlib.h>
-void
-TagBuilder::Clear()
+TagBuilder::TagBuilder(const Tag &other)
+ :time(other.time), has_playlist(other.has_playlist)
{
- time = -1;
- has_playlist = false;
+ items.reserve(other.num_items);
tag_pool_lock.lock();
+ for (unsigned i = 0, n = other.num_items; i != n; ++i)
+ items.push_back(tag_pool_dup_item(other.items[i]));
+ tag_pool_lock.unlock();
+}
+
+TagBuilder::TagBuilder(Tag &&other)
+ :time(other.time), has_playlist(other.has_playlist)
+{
+ /* move all TagItem pointers from the Tag object; we don't
+ need to contact the tag pool, because all we do is move
+ references */
+ items.reserve(other.num_items);
+ std::copy_n(other.items, other.num_items, std::back_inserter(items));
+
+ /* discard the pointers from the Tag object */
+ other.num_items = 0;
+ delete[] other.items;
+ other.items = nullptr;
+}
+
+TagBuilder &
+TagBuilder::operator=(const TagBuilder &other)
+{
+ /* copy all attributes */
+ time = other.time;
+ has_playlist = other.has_playlist;
+ items = other.items;
+
+ /* increment the tag pool refcounters */
+ tag_pool_lock.lock();
for (auto i : items)
- tag_pool_put_item(i);
+ tag_pool_dup_item(i);
tag_pool_lock.unlock();
+ return *this;
+}
+
+TagBuilder &
+TagBuilder::operator=(TagBuilder &&other)
+{
+ time = other.time;
+ has_playlist = other.has_playlist;
+ items = std::move(other.items);
+
+ return *this;
+}
+
+TagBuilder &
+TagBuilder::operator=(Tag &&other)
+{
+ time = other.time;
+ has_playlist = other.has_playlist;
+
+ /* move all TagItem pointers from the Tag object; we don't
+ need to contact the tag pool, because all we do is move
+ references */
items.clear();
+ items.reserve(other.num_items);
+ std::copy_n(other.items, other.num_items, std::back_inserter(items));
+
+ /* discard the pointers from the Tag object */
+ other.num_items = 0;
+ delete[] other.items;
+ other.items = nullptr;
+
+ return *this;
+}
+
+void
+TagBuilder::Clear()
+{
+ time = -1;
+ has_playlist = false;
+ RemoveAll();
}
void
@@ -57,7 +124,7 @@ TagBuilder::Commit(Tag &tag)
object */
const unsigned n_items = items.size();
tag.num_items = n_items;
- tag.items = g_new(TagItem *, n_items);
+ tag.items = new TagItem *[n_items];
std::copy_n(items.begin(), n_items, tag.items);
items.clear();
@@ -66,14 +133,51 @@ TagBuilder::Commit(Tag &tag)
Clear();
}
-Tag *
+Tag
TagBuilder::Commit()
{
+ Tag tag;
+ Commit(tag);
+ return tag;
+}
+
+Tag *
+TagBuilder::CommitNew()
+{
Tag *tag = new Tag();
Commit(*tag);
return tag;
}
+bool
+TagBuilder::HasType(TagType type) const
+{
+ for (auto i : items)
+ if (i->type == type)
+ return true;
+
+ return false;
+}
+
+void
+TagBuilder::Complement(const Tag &other)
+{
+ if (time <= 0)
+ time = other.time;
+
+ has_playlist |= other.has_playlist;
+
+ items.reserve(items.size() + other.num_items);
+
+ tag_pool_lock.lock();
+ for (unsigned i = 0, n = other.num_items; i != n; ++i) {
+ TagItem *item = other.items[i];
+ if (!HasType(item->type))
+ items.push_back(tag_pool_dup_item(item));
+ }
+ tag_pool_lock.unlock();
+}
+
inline void
TagBuilder::AddItemInternal(TagType type, const char *value, size_t length)
{
@@ -90,7 +194,7 @@ TagBuilder::AddItemInternal(TagType type, const char *value, size_t length)
auto i = tag_pool_get_item(type, value, length);
tag_pool_lock.unlock();
- g_free(p);
+ free(p);
items.push_back(i);
}
@@ -113,3 +217,29 @@ TagBuilder::AddItem(TagType type, const char *value)
AddItem(type, value, strlen(value));
}
+
+void
+TagBuilder::RemoveAll()
+{
+ tag_pool_lock.lock();
+ for (auto i : items)
+ tag_pool_put_item(i);
+ tag_pool_lock.unlock();
+
+ items.clear();
+}
+
+void
+TagBuilder::RemoveType(TagType type)
+{
+ const auto begin = items.begin(), end = items.end();
+
+ items.erase(std::remove_if(begin, end,
+ [type](TagItem *item) {
+ if (item->type != type)
+ return false;
+ tag_pool_put_item(item);
+ return true;
+ }),
+ end);
+}
diff --git a/src/tag/TagBuilder.hxx b/src/tag/TagBuilder.hxx
index ffc60a1b2..984261ded 100644
--- a/src/tag/TagBuilder.hxx
+++ b/src/tag/TagBuilder.hxx
@@ -63,7 +63,14 @@ public:
}
TagBuilder(const TagBuilder &other) = delete;
- TagBuilder &operator=(const TagBuilder &other) = delete;
+
+ explicit TagBuilder(const Tag &other);
+ explicit TagBuilder(Tag &&other);
+
+ TagBuilder &operator=(const TagBuilder &other);
+ TagBuilder &operator=(TagBuilder &&other);
+
+ TagBuilder &operator=(Tag &&other);
/**
* Returns true if the tag contains no items. This ignores the "time"
@@ -90,11 +97,17 @@ public:
void Commit(Tag &tag);
/**
+ * Create a new #Tag instance from data in this object. This
+ * object is empty afterwards.
+ */
+ Tag Commit();
+
+ /**
* Create a new #Tag instance from data in this object. The
* returned object is owned by the caller. This object is
* empty afterwards.
*/
- Tag *Commit();
+ Tag *CommitNew();
void SetTime(int _time) {
time = _time;
@@ -109,6 +122,19 @@ public:
}
/**
+ * Checks whether the tag contains one or more items with
+ * the specified type.
+ */
+ gcc_pure
+ bool HasType(TagType type) const;
+
+ /**
+ * Copy attributes and items from the other object that do not
+ * exist in this object.
+ */
+ void Complement(const Tag &other);
+
+ /**
* Appends a new tag item.
*
* @param type the type of the new tag item
@@ -127,6 +153,16 @@ public:
gcc_nonnull_all
void AddItem(TagType type, const char *value);
+ /**
+ * Removes all tag items.
+ */
+ void RemoveAll();
+
+ /**
+ * Removes all tag items of the specified type.
+ */
+ void RemoveType(TagType type);
+
private:
gcc_nonnull_all
void AddItemInternal(TagType type, const char *value, size_t length);
diff --git a/src/tag/TagConfig.cxx b/src/tag/TagConfig.cxx
index 96fd1847f..5c81fa603 100644
--- a/src/tag/TagConfig.cxx
+++ b/src/tag/TagConfig.cxx
@@ -24,13 +24,14 @@
#include "ConfigGlobal.hxx"
#include "ConfigOption.hxx"
#include "system/FatalError.hxx"
+#include "util/Alloc.hxx"
#include "util/ASCII.hxx"
#include <glib.h>
#include <algorithm>
-#include <string.h>
+#include <stdlib.h>
void
TagLoadConfig()
@@ -46,7 +47,7 @@ TagLoadConfig()
bool quit = false;
char *temp, *c, *s;
- temp = c = s = g_strdup(value);
+ temp = c = s = xstrdup(value);
do {
if (*s == ',' || *s == '\0') {
if (*s == '\0')
@@ -70,5 +71,5 @@ TagLoadConfig()
s++;
} while (!quit);
- g_free(temp);
+ free(temp);
}
diff --git a/src/tag/TagConfig.hxx b/src/tag/TagConfig.hxx
index 5ec6766d4..3bc86cc40 100644
--- a/src/tag/TagConfig.hxx
+++ b/src/tag/TagConfig.hxx
@@ -20,8 +20,6 @@
#ifndef MPD_TAG_CONFIG_HXX
#define MPD_TAG_CONFIG_HXX
-#include "TagType.h"
-
void
TagLoadConfig();
diff --git a/src/tag/TagId3.cxx b/src/tag/TagId3.cxx
index df70a95e5..0397c0039 100644
--- a/src/tag/TagId3.cxx
+++ b/src/tag/TagId3.cxx
@@ -21,7 +21,6 @@
#include "TagId3.hxx"
#include "TagHandler.hxx"
#include "TagTable.hxx"
-#include "Tag.hxx"
#include "TagBuilder.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
@@ -35,9 +34,10 @@
#include <glib.h>
#include <id3tag.h>
+#include <string>
+
#include <stdio.h>
#include <stdlib.h>
-#include <errno.h>
#include <string.h>
# ifndef ID3_FRAME_COMPOSER
@@ -70,14 +70,11 @@ tag_is_id3v1(struct id3_tag *tag)
static id3_utf8_t *
tag_id3_getstring(const struct id3_frame *frame, unsigned i)
{
- union id3_field *field;
- const id3_ucs4_t *ucs4;
-
- field = id3_frame_field(frame, i);
+ id3_field *field = id3_frame_field(frame, i);
if (field == nullptr)
return nullptr;
- ucs4 = id3_field_getstring(field);
+ const id3_ucs4_t *ucs4 = id3_field_getstring(field);
if (ucs4 == nullptr)
return nullptr;
@@ -89,17 +86,15 @@ tag_id3_getstring(const struct id3_frame *frame, unsigned i)
static id3_utf8_t *
import_id3_string(bool is_id3v1, const id3_ucs4_t *ucs4)
{
- id3_utf8_t *utf8, *utf8_stripped;
- id3_latin1_t *isostr;
- const char *encoding;
+ id3_utf8_t *utf8;
/* use encoding field here? */
+ const char *encoding;
if (is_id3v1 &&
(encoding = config_get_string(CONF_ID3V1_ENCODING, nullptr)) != nullptr) {
- isostr = id3_ucs4_latin1duplicate(ucs4);
- if (G_UNLIKELY(!isostr)) {
+ id3_latin1_t *isostr = id3_ucs4_latin1duplicate(ucs4);
+ if (gcc_unlikely(isostr == nullptr))
return nullptr;
- }
utf8 = (id3_utf8_t *)
g_convert_with_fallback((const char*)isostr, -1,
@@ -110,19 +105,19 @@ import_id3_string(bool is_id3v1, const id3_ucs4_t *ucs4)
FormatWarning(id3_domain,
"Unable to convert %s string to UTF-8: '%s'",
encoding, isostr);
- g_free(isostr);
+ free(isostr);
return nullptr;
}
- g_free(isostr);
+ free(isostr);
} else {
utf8 = id3_ucs4_utf8duplicate(ucs4);
- if (G_UNLIKELY(!utf8)) {
+ if (gcc_unlikely(utf8 == nullptr))
return nullptr;
- }
}
- utf8_stripped = (id3_utf8_t *)g_strdup(g_strstrip((gchar *)utf8));
- g_free(utf8);
+ id3_utf8_t *utf8_stripped = (id3_utf8_t *)
+ g_strdup(g_strstrip((gchar *)utf8));
+ free(utf8);
return utf8_stripped;
}
@@ -139,17 +134,12 @@ tag_id3_import_text_frame(struct id3_tag *tag, const struct id3_frame *frame,
TagType type,
const struct tag_handler *handler, void *handler_ctx)
{
- id3_ucs4_t const *ucs4;
- id3_utf8_t *utf8;
- union id3_field const *field;
- unsigned int nstrings, i;
-
if (frame->nfields != 2)
return;
/* check the encoding field */
- field = id3_frame_field(frame, 0);
+ const id3_field *field = id3_frame_field(frame, 0);
if (field == nullptr || field->type != ID3_FIELD_TYPE_TEXTENCODING)
return;
@@ -160,16 +150,16 @@ tag_id3_import_text_frame(struct id3_tag *tag, const struct id3_frame *frame,
return;
/* Get the number of strings available */
- nstrings = id3_field_getnstrings(field);
- for (i = 0; i < nstrings; i++) {
- ucs4 = id3_field_getstrings(field, i);
+ const unsigned nstrings = id3_field_getnstrings(field);
+ for (unsigned i = 0; i < nstrings; i++) {
+ const id3_ucs4_t *ucs4 = id3_field_getstrings(field, i);
if (ucs4 == nullptr)
continue;
if (type == TAG_GENRE)
ucs4 = id3_genre_name(ucs4);
- utf8 = import_id3_string(tag_is_id3v1(tag), ucs4);
+ id3_utf8_t *utf8 = import_id3_string(tag_is_id3v1(tag), ucs4);
if (utf8 == nullptr)
continue;
@@ -209,23 +199,19 @@ tag_id3_import_comment_frame(struct id3_tag *tag,
const struct tag_handler *handler,
void *handler_ctx)
{
- id3_ucs4_t const *ucs4;
- id3_utf8_t *utf8;
- union id3_field const *field;
-
if (frame->nfields != 4)
return;
/* for now I only read the 4th field, with the fullstring */
- field = id3_frame_field(frame, 3);
+ const id3_field *field = id3_frame_field(frame, 3);
if (field == nullptr)
return;
- ucs4 = id3_field_getfullstring(field);
+ const id3_ucs4_t *ucs4 = id3_field_getfullstring(field);
if (ucs4 == nullptr)
return;
- utf8 = import_id3_string(tag_is_id3v1(tag), ucs4);
+ id3_utf8_t *utf8 = import_id3_string(tag_is_id3v1(tag), ucs4);
if (utf8 == nullptr)
return;
@@ -277,19 +263,15 @@ tag_id3_import_musicbrainz(struct id3_tag *id3_tag,
void *handler_ctx)
{
for (unsigned i = 0;; ++i) {
- const struct id3_frame *frame;
- id3_utf8_t *name, *value;
- TagType type;
-
- frame = id3_tag_findframe(id3_tag, "TXXX", i);
+ const id3_frame *frame = id3_tag_findframe(id3_tag, "TXXX", i);
if (frame == nullptr)
break;
- name = tag_id3_getstring(frame, 1);
+ id3_utf8_t *name = tag_id3_getstring(frame, 1);
if (name == nullptr)
continue;
- value = tag_id3_getstring(frame, 2);
+ id3_utf8_t *value = tag_id3_getstring(frame, 2);
if (value == nullptr)
continue;
@@ -297,7 +279,7 @@ tag_id3_import_musicbrainz(struct id3_tag *id3_tag,
(const char *)name,
(const char *)value);
- type = tag_id3_parse_txxx_name((const char*)name);
+ TagType type = tag_id3_parse_txxx_name((const char*)name);
free(name);
if (type != TAG_NUM_OF_ITEM_TYPES)
@@ -316,21 +298,15 @@ tag_id3_import_ufid(struct id3_tag *id3_tag,
const struct tag_handler *handler, void *handler_ctx)
{
for (unsigned i = 0;; ++i) {
- const struct id3_frame *frame;
- union id3_field *field;
- const id3_latin1_t *name;
- const id3_byte_t *value;
- id3_length_t length;
-
- frame = id3_tag_findframe(id3_tag, "UFID", i);
+ const id3_frame *frame = id3_tag_findframe(id3_tag, "UFID", i);
if (frame == nullptr)
break;
- field = id3_frame_field(frame, 0);
+ id3_field *field = id3_frame_field(frame, 0);
if (field == nullptr)
continue;
- name = id3_field_getlatin1(field);
+ const id3_latin1_t *name = id3_field_getlatin1(field);
if (name == nullptr ||
strcmp((const char *)name, "http://musicbrainz.org") != 0)
continue;
@@ -339,14 +315,15 @@ tag_id3_import_ufid(struct id3_tag *id3_tag,
if (field == nullptr)
continue;
- value = id3_field_getbinarydata(field, &length);
+ id3_length_t length;
+ const id3_byte_t *value =
+ id3_field_getbinarydata(field, &length);
if (value == nullptr || length == 0)
continue;
- char *p = g_strndup((const char *)value, length);
+ std::string p((const char *)value, length);
tag_handler_invoke_tag(handler, handler_ctx,
- TAG_MUSICBRAINZ_TRACKID, p);
- g_free(p);
+ TAG_MUSICBRAINZ_TRACKID, p.c_str());
}
}
@@ -393,73 +370,57 @@ tag_id3_import(struct id3_tag *tag)
scan_id3_tag(tag, &add_tag_handler, &tag_builder);
return tag_builder.IsEmpty()
? nullptr
- : tag_builder.Commit();
+ : tag_builder.CommitNew();
}
-static int
+static size_t
fill_buffer(void *buf, size_t size, FILE *stream, long offset, int whence)
{
if (fseek(stream, offset, whence) != 0) return 0;
return fread(buf, 1, size, stream);
}
-static int
+static long
get_id3v2_footer_size(FILE *stream, long offset, int whence)
{
id3_byte_t buf[ID3_TAG_QUERYSIZE];
- int bufsize;
-
- bufsize = fill_buffer(buf, ID3_TAG_QUERYSIZE, stream, offset, whence);
- if (bufsize <= 0) return 0;
+ size_t bufsize = fill_buffer(buf, ID3_TAG_QUERYSIZE, stream, offset, whence);
+ if (bufsize == 0) return 0;
return id3_tag_query(buf, bufsize);
}
static struct id3_tag *
tag_id3_read(FILE *stream, long offset, int whence)
{
- struct id3_tag *tag;
- id3_byte_t query_buffer[ID3_TAG_QUERYSIZE];
- int tag_size;
- int query_buffer_size;
-
/* It's ok if we get less than we asked for */
- query_buffer_size = fill_buffer(query_buffer, ID3_TAG_QUERYSIZE,
- stream, offset, whence);
+ id3_byte_t query_buffer[ID3_TAG_QUERYSIZE];
+ size_t query_buffer_size = fill_buffer(query_buffer, ID3_TAG_QUERYSIZE,
+ stream, offset, whence);
if (query_buffer_size <= 0)
return nullptr;
/* Look for a tag header */
- tag_size = id3_tag_query(query_buffer, query_buffer_size);
+ long tag_size = id3_tag_query(query_buffer, query_buffer_size);
if (tag_size <= 0) return nullptr;
/* Found a tag. Allocate a buffer and read it in. */
- id3_byte_t *tag_buffer = (id3_byte_t *)g_malloc(tag_size);
- if (!tag_buffer)
- return nullptr;
-
+ id3_byte_t *tag_buffer = new id3_byte_t[tag_size];
int tag_buffer_size = fill_buffer(tag_buffer, tag_size,
stream, offset, whence);
if (tag_buffer_size < tag_size) {
- g_free(tag_buffer);
+ delete[] tag_buffer;
return nullptr;
}
- tag = id3_tag_parse(tag_buffer, tag_buffer_size);
-
- g_free(tag_buffer);
-
+ id3_tag *tag = id3_tag_parse(tag_buffer, tag_buffer_size);
+ delete[] tag_buffer;
return tag;
}
static struct id3_tag *
tag_id3_find_from_beginning(FILE *stream)
{
- struct id3_tag *tag;
- struct id3_tag *seektag;
- struct id3_frame *frame;
- int seek;
-
- tag = tag_id3_read(stream, 0, SEEK_SET);
+ id3_tag *tag = tag_id3_read(stream, 0, SEEK_SET);
if (!tag) {
return nullptr;
} else if (tag_is_id3v1(tag)) {
@@ -469,14 +430,15 @@ tag_id3_find_from_beginning(FILE *stream)
}
/* We have an id3v2 tag, so let's look for SEEK frames */
+ id3_frame *frame;
while ((frame = id3_tag_findframe(tag, "SEEK", 0))) {
/* Found a SEEK frame, get it's value */
- seek = id3_field_getint(id3_frame_field(frame, 0));
+ int seek = id3_field_getint(id3_frame_field(frame, 0));
if (seek < 0)
break;
/* Get the tag specified by the SEEK frame */
- seektag = tag_id3_read(stream, seek, SEEK_CUR);
+ id3_tag *seektag = tag_id3_read(stream, seek, SEEK_CUR);
if (!seektag || tag_is_id3v1(seektag))
break;
@@ -491,20 +453,16 @@ tag_id3_find_from_beginning(FILE *stream)
static struct id3_tag *
tag_id3_find_from_end(FILE *stream)
{
- struct id3_tag *tag;
- struct id3_tag *v1tag;
- int tagsize;
-
/* Get an id3v1 tag from the end of file for later use */
- v1tag = tag_id3_read(stream, -128, SEEK_END);
+ id3_tag *v1tag = tag_id3_read(stream, -128, SEEK_END);
/* Get the id3v2 tag size from the footer (located before v1tag) */
- tagsize = get_id3v2_footer_size(stream, (v1tag ? -128 : 0) - 10, SEEK_END);
+ int tagsize = get_id3v2_footer_size(stream, (v1tag ? -128 : 0) - 10, SEEK_END);
if (tagsize >= 0)
return v1tag;
/* Get the tag which the footer belongs to */
- tag = tag_id3_read(stream, tagsize, SEEK_CUR);
+ id3_tag *tag = tag_id3_read(stream, tagsize, SEEK_CUR);
if (!tag)
return v1tag;
@@ -527,16 +485,16 @@ tag_id3_riff_aiff_load(FILE *file)
/* too large, don't allocate so much memory */
return nullptr;
- id3_byte_t *buffer = (id3_byte_t *)g_malloc(size);
+ id3_byte_t *buffer = new id3_byte_t[size];
size_t ret = fread(buffer, size, 1, file);
if (ret != 1) {
LogWarning(id3_domain, "Failed to read RIFF chunk");
- g_free(buffer);
+ delete[] buffer;
return nullptr;
}
struct id3_tag *tag = id3_tag_parse(buffer, size);
- g_free(buffer);
+ delete[] buffer;
return tag;
}
diff --git a/src/tag/TagId3.hxx b/src/tag/TagId3.hxx
index 749166116..aa564e946 100644
--- a/src/tag/TagId3.hxx
+++ b/src/tag/TagId3.hxx
@@ -33,10 +33,10 @@ class Error;
bool
tag_id3_scan(Path path_fs,
- const struct tag_handler *handler, void *handler_ctx);
+ const tag_handler *handler, void *handler_ctx);
Tag *
-tag_id3_import(struct id3_tag *);
+tag_id3_import(id3_tag *);
/**
* Loads the ID3 tags from the file into a libid3tag object. The
@@ -53,8 +53,8 @@ tag_id3_load(Path path_fs, Error &error);
*
*/
void
-scan_id3_tag(struct id3_tag *tag,
- const struct tag_handler *handler, void *handler_ctx);
+scan_id3_tag(id3_tag *tag,
+ const tag_handler *handler, void *handler_ctx);
#else
@@ -62,7 +62,7 @@ scan_id3_tag(struct id3_tag *tag,
static inline bool
tag_id3_scan(gcc_unused Path path_fs,
- gcc_unused const struct tag_handler *handler,
+ gcc_unused const tag_handler *handler,
gcc_unused void *handler_ctx)
{
return false;
diff --git a/src/tag/TagPool.cxx b/src/tag/TagPool.cxx
index cc28ea9a6..409edb662 100644
--- a/src/tag/TagPool.cxx
+++ b/src/tag/TagPool.cxx
@@ -20,23 +20,46 @@
#include "config.h"
#include "TagPool.hxx"
#include "TagItem.hxx"
-
-#include <glib.h>
+#include "util/Cast.hxx"
+#include "util/VarSize.hxx"
#include <assert.h>
#include <string.h>
+#include <stdlib.h>
Mutex tag_pool_lock;
#define NUM_SLOTS 4096
-struct slot {
- struct slot *next;
+struct TagPoolSlot {
+ TagPoolSlot *next;
unsigned char ref;
TagItem item;
-} mpd_packed;
-static struct slot *slots[NUM_SLOTS];
+ TagPoolSlot(TagPoolSlot *_next, TagType type,
+ const char *value, size_t length)
+ :next(_next), ref(1) {
+ item.type = type;
+ memcpy(item.value, value, length);
+ item.value[length] = 0;
+ }
+
+ static TagPoolSlot *Create(TagPoolSlot *_next, TagType type,
+ const char *value, size_t length);
+} gcc_packed;
+
+TagPoolSlot *
+TagPoolSlot::Create(TagPoolSlot *_next, TagType type,
+ const char *value, size_t length)
+{
+ TagPoolSlot *dummy;
+ return NewVarSize<TagPoolSlot>(sizeof(dummy->item.value),
+ length + 1,
+ _next, type,
+ value, length);
+}
+
+static TagPoolSlot *slots[NUM_SLOTS];
static inline unsigned
calc_hash_n(TagType type, const char *p, size_t length)
@@ -64,32 +87,16 @@ calc_hash(TagType type, const char *p)
return hash ^ type;
}
-static inline struct slot *
+static inline constexpr TagPoolSlot *
tag_item_to_slot(TagItem *item)
{
- return (struct slot*)(((char*)item) - offsetof(struct slot, item));
-}
-
-static struct slot *slot_alloc(struct slot *next,
- TagType type,
- const char *value, int length)
-{
- struct slot *slot;
-
- slot = (struct slot *)
- g_malloc(sizeof(*slot) - sizeof(slot->item.value) + length + 1);
- slot->next = next;
- slot->ref = 1;
- slot->item.type = type;
- memcpy(slot->item.value, value, length);
- slot->item.value[length] = 0;
- return slot;
+ return ContainerCast(item, TagPoolSlot, item);
}
TagItem *
tag_pool_get_item(TagType type, const char *value, size_t length)
{
- struct slot **slot_p, *slot;
+ TagPoolSlot **slot_p, *slot;
slot_p = &slots[calc_hash_n(type, value, length) % NUM_SLOTS];
for (slot = *slot_p; slot != nullptr; slot = slot->next) {
@@ -103,7 +110,7 @@ tag_pool_get_item(TagType type, const char *value, size_t length)
}
}
- slot = slot_alloc(*slot_p, type, value, length);
+ slot = TagPoolSlot::Create(*slot_p, type, value, length);
*slot_p = slot;
return &slot->item;
}
@@ -111,7 +118,7 @@ tag_pool_get_item(TagType type, const char *value, size_t length)
TagItem *
tag_pool_dup_item(TagItem *item)
{
- struct slot *slot = tag_item_to_slot(item);
+ TagPoolSlot *slot = tag_item_to_slot(item);
assert(slot->ref > 0);
@@ -122,11 +129,11 @@ tag_pool_dup_item(TagItem *item)
/* the reference counter overflows above 0xff;
duplicate the item, and start with 1 */
size_t length = strlen(item->value);
- struct slot **slot_p =
+ TagPoolSlot **slot_p =
&slots[calc_hash_n(item->type, item->value,
length) % NUM_SLOTS];
- slot = slot_alloc(*slot_p, item->type,
- item->value, strlen(item->value));
+ slot = TagPoolSlot::Create(*slot_p, item->type,
+ item->value, strlen(item->value));
*slot_p = slot;
return &slot->item;
}
@@ -135,7 +142,7 @@ tag_pool_dup_item(TagItem *item)
void
tag_pool_put_item(TagItem *item)
{
- struct slot **slot_p, *slot;
+ TagPoolSlot **slot_p, *slot;
slot = tag_item_to_slot(item);
assert(slot->ref > 0);
@@ -151,5 +158,5 @@ tag_pool_put_item(TagItem *item)
}
*slot_p = slot->next;
- g_free(slot);
+ DeleteVarSize(slot);
}
diff --git a/src/tag/TagRva2.cxx b/src/tag/TagRva2.cxx
index 204001aa7..442695581 100644
--- a/src/tag/TagRva2.cxx
+++ b/src/tag/TagRva2.cxx
@@ -21,10 +21,10 @@
#include "TagRva2.hxx"
#include "ReplayGainInfo.hxx"
+#include <id3tag.h>
+
#include <stdint.h>
#include <string.h>
-#include <glib.h>
-#include <id3tag.h>
enum rva2_channel {
CHANNEL_OTHER = 0x00,
diff --git a/src/tag/TagRva2.hxx b/src/tag/TagRva2.hxx
index 98154041a..a1d67a777 100644
--- a/src/tag/TagRva2.hxx
+++ b/src/tag/TagRva2.hxx
@@ -32,6 +32,6 @@ struct ReplayGainInfo;
* @return true on success
*/
bool
-tag_rva2_parse(struct id3_tag *tag, ReplayGainInfo &replay_gain_info);
+tag_rva2_parse(id3_tag *tag, ReplayGainInfo &replay_gain_info);
#endif
diff --git a/src/tag/TagString.cxx b/src/tag/TagString.cxx
index 3e8d8c1b0..9d2bd68ec 100644
--- a/src/tag/TagString.cxx
+++ b/src/tag/TagString.cxx
@@ -19,11 +19,13 @@
#include "config.h"
#include "TagString.hxx"
+#include "util/Alloc.hxx"
#include <glib.h>
#include <assert.h>
#include <string.h>
+#include <stdlib.h>
/**
* Replace invalid sequences with the question mark.
@@ -33,7 +35,7 @@ patch_utf8(const char *src, size_t length, const gchar *end)
{
/* duplicate the string, and replace invalid bytes in that
buffer */
- char *dest = g_strdup(src);
+ char *dest = xstrdup(src);
do {
dest[end - src] = '?';
@@ -58,9 +60,12 @@ fix_utf8(const char *str, size_t length)
/* no, it's not - try to import it from ISO-Latin-1 */
temp = g_convert(str, length, "utf-8", "iso-8859-1",
nullptr, &written, nullptr);
- if (temp != nullptr)
+ if (temp != nullptr) {
/* success! */
- return temp;
+ char *p = xstrdup(temp);
+ g_free(temp);
+ return p;
+ }
/* no, still broken - there's no medication, just patch
invalid sequences */
@@ -96,7 +101,7 @@ clear_non_printable(const char *p, size_t length)
if (first == nullptr)
return nullptr;
- dest = g_strndup(p, length);
+ dest = xstrndup(p, length);
for (size_t i = first - p; i < length; ++i)
if (char_is_non_printable(dest[i]))
@@ -120,7 +125,7 @@ FixTagString(const char *p, size_t length)
if (cleared == nullptr)
cleared = utf8;
else
- g_free(utf8);
+ free(utf8);
return cleared;
}
diff --git a/src/tag/TagTable.cxx b/src/tag/TagTable.cxx
index b51bc35ba..5224404a9 100644
--- a/src/tag/TagTable.cxx
+++ b/src/tag/TagTable.cxx
@@ -51,3 +51,13 @@ tag_table_lookup_i(const struct tag_table *table, const char *name)
return TAG_NUM_OF_ITEM_TYPES;
}
+
+const char *
+tag_table_lookup(const tag_table *table, TagType type)
+{
+ for (; table->name != nullptr; ++table)
+ if (table->type == type)
+ return table->name;
+
+ return nullptr;
+}
diff --git a/src/tag/TagTable.hxx b/src/tag/TagTable.hxx
index c050f61ac..423a1e6ad 100644
--- a/src/tag/TagTable.hxx
+++ b/src/tag/TagTable.hxx
@@ -47,4 +47,13 @@ gcc_pure
TagType
tag_table_lookup_i(const tag_table *table, const char *name);
+/**
+ * Looks up a #TagType in a tag translation table and returns its
+ * string representation. Returns nullptr if the specified type was
+ * not found in the table.
+ */
+gcc_pure
+const char *
+tag_table_lookup(const tag_table *table, TagType type);
+
#endif