2 * Copyright (C) 2003-2010 The Music Player Daemon Project
3 * http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "tag_internal.h"
33 * Maximum number of items managed in the bulk list; if it is
34 * exceeded, we switch back to "normal" reallocation.
42 struct tag_item
*items
[BULK_MAX
];
45 const char *tag_item_names
[TAG_NUM_OF_ITEM_TYPES
] = {
46 [TAG_ARTIST
] = "Artist",
47 [TAG_ARTIST_SORT
] = "ArtistSort",
48 [TAG_ALBUM
] = "Album",
49 [TAG_ALBUM_ARTIST
] = "AlbumArtist",
50 [TAG_ALBUM_ARTIST_SORT
] = "AlbumArtistSort",
51 [TAG_TITLE
] = "Title",
52 [TAG_TRACK
] = "Track",
54 [TAG_GENRE
] = "Genre",
56 [TAG_COMPOSER
] = "Composer",
57 [TAG_PERFORMER
] = "Performer",
58 [TAG_COMMENT
] = "Comment",
61 /* MusicBrainz tags from http://musicbrainz.org/doc/MusicBrainzTag */
62 [TAG_MUSICBRAINZ_ARTISTID
] = "MUSICBRAINZ_ARTISTID",
63 [TAG_MUSICBRAINZ_ALBUMID
] = "MUSICBRAINZ_ALBUMID",
64 [TAG_MUSICBRAINZ_ALBUMARTISTID
] = "MUSICBRAINZ_ALBUMARTISTID",
65 [TAG_MUSICBRAINZ_TRACKID
] = "MUSICBRAINZ_TRACKID",
68 bool ignore_tag_items
[TAG_NUM_OF_ITEM_TYPES
];
71 tag_name_parse(const char *name
)
75 for (unsigned i
= 0; i
< TAG_NUM_OF_ITEM_TYPES
; ++i
) {
76 assert(tag_item_names
[i
] != NULL
);
78 if (strcmp(name
, tag_item_names
[i
]) == 0)
79 return (enum tag_type
)i
;
82 return TAG_NUM_OF_ITEM_TYPES
;
86 tag_name_parse_i(const char *name
)
90 for (unsigned i
= 0; i
< TAG_NUM_OF_ITEM_TYPES
; ++i
) {
91 assert(tag_item_names
[i
] != NULL
);
93 if (g_ascii_strcasecmp(name
, tag_item_names
[i
]) == 0)
94 return (enum tag_type
)i
;
97 return TAG_NUM_OF_ITEM_TYPES
;
100 static size_t items_size(const struct tag
*tag
)
102 return tag
->num_items
* sizeof(struct tag_item
*);
105 void tag_lib_init(void)
114 /* parse the "metadata_to_use" config parameter below */
116 /* ignore comments by default */
117 ignore_tag_items
[TAG_COMMENT
] = true;
119 value
= config_get_string(CONF_METADATA_TO_USE
, NULL
);
123 memset(ignore_tag_items
, true, TAG_NUM_OF_ITEM_TYPES
);
125 if (0 == g_ascii_strcasecmp(value
, "none"))
128 temp
= c
= s
= g_strdup(value
);
130 if (*s
== ',' || *s
== '\0') {
139 type
= tag_name_parse_i(c
);
140 if (type
== TAG_NUM_OF_ITEM_TYPES
)
141 g_error("error parsing metadata item \"%s\"",
144 ignore_tag_items
[type
] = false;
155 struct tag
*tag_new(void)
157 struct tag
*ret
= g_new(struct tag
, 1);
164 static void tag_delete_item(struct tag
*tag
, unsigned idx
)
166 assert(idx
< tag
->num_items
);
169 g_mutex_lock(tag_pool_lock
);
170 tag_pool_put_item(tag
->items
[idx
]);
171 g_mutex_unlock(tag_pool_lock
);
173 if (tag
->num_items
- idx
> 0) {
174 memmove(tag
->items
+ idx
, tag
->items
+ idx
+ 1,
175 (tag
->num_items
- idx
) * sizeof(tag
->items
[0]));
178 if (tag
->num_items
> 0) {
179 tag
->items
= g_realloc(tag
->items
, items_size(tag
));
186 void tag_clear_items_by_type(struct tag
*tag
, enum tag_type type
)
188 for (unsigned i
= 0; i
< tag
->num_items
; i
++) {
189 if (tag
->items
[i
]->type
== type
) {
190 tag_delete_item(tag
, i
);
191 /* decrement since when just deleted this node */
197 void tag_free(struct tag
*tag
)
203 g_mutex_lock(tag_pool_lock
);
204 for (i
= tag
->num_items
; --i
>= 0; )
205 tag_pool_put_item(tag
->items
[i
]);
206 g_mutex_unlock(tag_pool_lock
);
208 if (tag
->items
== bulk
.items
) {
219 struct tag
*tag_dup(const struct tag
*tag
)
227 ret
->time
= tag
->time
;
228 ret
->num_items
= tag
->num_items
;
229 ret
->items
= ret
->num_items
> 0 ? g_malloc(items_size(tag
)) : NULL
;
231 g_mutex_lock(tag_pool_lock
);
232 for (unsigned i
= 0; i
< tag
->num_items
; i
++)
233 ret
->items
[i
] = tag_pool_dup_item(tag
->items
[i
]);
234 g_mutex_unlock(tag_pool_lock
);
240 tag_merge(const struct tag
*base
, const struct tag
*add
)
245 assert(base
!= NULL
);
248 /* allocate new tag object */
251 ret
->time
= add
->time
> 0 ? add
->time
: base
->time
;
252 ret
->num_items
= base
->num_items
+ add
->num_items
;
253 ret
->items
= ret
->num_items
> 0 ? g_malloc(items_size(ret
)) : NULL
;
255 g_mutex_lock(tag_pool_lock
);
257 /* copy all items from "add" */
259 for (unsigned i
= 0; i
< add
->num_items
; ++i
)
260 ret
->items
[i
] = tag_pool_dup_item(add
->items
[i
]);
264 /* copy additional items from "base" */
266 for (unsigned i
= 0; i
< base
->num_items
; ++i
)
267 if (!tag_has_type(add
, base
->items
[i
]->type
))
268 ret
->items
[n
++] = tag_pool_dup_item(base
->items
[i
]);
270 g_mutex_unlock(tag_pool_lock
);
272 assert(n
<= ret
->num_items
);
274 if (n
< ret
->num_items
) {
275 /* some tags were not copied - shrink ret->items */
279 ret
->items
= g_realloc(ret
->items
, items_size(ret
));
286 tag_merge_replace(struct tag
*base
, struct tag
*add
)
294 struct tag
*tag
= tag_merge(base
, add
);
302 tag_get_value(const struct tag
*tag
, enum tag_type type
)
305 assert(type
< TAG_NUM_OF_ITEM_TYPES
);
307 for (unsigned i
= 0; i
< tag
->num_items
; i
++)
308 if (tag
->items
[i
]->type
== type
)
309 return tag
->items
[i
]->value
;
314 bool tag_has_type(const struct tag
*tag
, enum tag_type type
)
316 return tag_get_value(tag
, type
) != NULL
;
319 bool tag_equal(const struct tag
*tag1
, const struct tag
*tag2
)
321 if (tag1
== NULL
&& tag2
== NULL
)
323 else if (!tag1
|| !tag2
)
326 if (tag1
->time
!= tag2
->time
)
329 if (tag1
->num_items
!= tag2
->num_items
)
332 for (unsigned i
= 0; i
< tag1
->num_items
; i
++) {
333 if (tag1
->items
[i
]->type
!= tag2
->items
[i
]->type
)
335 if (strcmp(tag1
->items
[i
]->value
, tag2
->items
[i
]->value
)) {
344 * Replace invalid sequences with the question mark.
347 patch_utf8(const char *src
, size_t length
, const gchar
*end
)
349 /* duplicate the string, and replace invalid bytes in that
351 char *dest
= g_strdup(src
);
354 dest
[end
- src
] = '?';
355 } while (!g_utf8_validate(end
+ 1, (src
+ length
) - (end
+ 1), &end
));
361 fix_utf8(const char *str
, size_t length
)
369 /* check if the string is already valid UTF-8 */
370 if (g_utf8_validate(str
, length
, &end
))
373 /* no, it's not - try to import it from ISO-Latin-1 */
374 temp
= g_convert(str
, length
, "utf-8", "iso-8859-1",
375 NULL
, &written
, NULL
);
380 /* no, still broken - there's no medication, just patch
382 return patch_utf8(str
, length
, end
);
385 void tag_begin_add(struct tag
*tag
)
389 assert(tag
->items
== NULL
);
390 assert(tag
->num_items
== 0);
395 tag
->items
= bulk
.items
;
398 void tag_end_add(struct tag
*tag
)
400 if (tag
->items
== bulk
.items
) {
401 assert(tag
->num_items
<= BULK_MAX
);
403 if (tag
->num_items
> 0) {
404 /* copy the tag items from the bulk list over
405 to a new list (which fits exactly) */
406 tag
->items
= g_malloc(items_size(tag
));
407 memcpy(tag
->items
, bulk
.items
, items_size(tag
));
418 char_is_non_printable(unsigned char ch
)
424 find_non_printable(const char *p
, size_t length
)
426 for (size_t i
= 0; i
< length
; ++i
)
427 if (char_is_non_printable(p
[i
]))
434 * Clears all non-printable characters, convert them to space.
435 * Returns NULL if nothing needs to be cleared.
438 clear_non_printable(const char *p
, size_t length
)
440 const char *first
= find_non_printable(p
, length
);
446 dest
= g_strndup(p
, length
);
448 for (size_t i
= first
- p
; i
< length
; ++i
)
449 if (char_is_non_printable(dest
[i
]))
456 fix_tag_value(const char *p
, size_t length
)
458 char *utf8
, *cleared
;
460 utf8
= fix_utf8(p
, length
);
466 cleared
= clear_non_printable(p
, length
);
476 tag_add_item_internal(struct tag
*tag
, enum tag_type type
,
477 const char *value
, size_t len
)
479 unsigned int i
= tag
->num_items
;
482 p
= fix_tag_value(value
, len
);
490 if (tag
->items
!= bulk
.items
)
491 /* bulk mode disabled */
492 tag
->items
= g_realloc(tag
->items
, items_size(tag
));
493 else if (tag
->num_items
>= BULK_MAX
) {
494 /* bulk list already full - switch back to non-bulk */
497 tag
->items
= g_malloc(items_size(tag
));
498 memcpy(tag
->items
, bulk
.items
,
499 items_size(tag
) - sizeof(struct tag_item
*));
502 g_mutex_lock(tag_pool_lock
);
503 tag
->items
[i
] = tag_pool_get_item(type
, value
, len
);
504 g_mutex_unlock(tag_pool_lock
);
509 void tag_add_item_n(struct tag
*tag
, enum tag_type type
,
510 const char *value
, size_t len
)
512 if (ignore_tag_items
[type
])
519 tag_add_item_internal(tag
, type
, value
, len
);