diff options
Diffstat (limited to 'src/tag')
-rw-r--r-- | src/tag/Aiff.cxx | 2 | ||||
-rw-r--r-- | src/tag/ApeLoader.cxx | 8 | ||||
-rw-r--r-- | src/tag/ApeTag.hxx | 2 | ||||
-rw-r--r-- | src/tag/Riff.cxx | 1 | ||||
-rw-r--r-- | src/tag/Tag.cxx | 105 | ||||
-rw-r--r-- | src/tag/Tag.hxx | 29 | ||||
-rw-r--r-- | src/tag/TagBuilder.cxx | 150 | ||||
-rw-r--r-- | src/tag/TagBuilder.hxx | 40 | ||||
-rw-r--r-- | src/tag/TagConfig.cxx | 7 | ||||
-rw-r--r-- | src/tag/TagConfig.hxx | 2 | ||||
-rw-r--r-- | src/tag/TagId3.cxx | 156 | ||||
-rw-r--r-- | src/tag/TagId3.hxx | 10 | ||||
-rw-r--r-- | src/tag/TagPool.cxx | 71 | ||||
-rw-r--r-- | src/tag/TagRva2.cxx | 4 | ||||
-rw-r--r-- | src/tag/TagRva2.hxx | 2 | ||||
-rw-r--r-- | src/tag/TagString.cxx | 15 | ||||
-rw-r--r-- | src/tag/TagTable.cxx | 10 | ||||
-rw-r--r-- | src/tag/TagTable.hxx | 9 |
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 |