2 * Copyright (C) 2003-2009 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.
21 #include "tag_internal.h"
32 * Maximum number of items managed in the bulk list; if it is
33 * exceeded, we switch back to "normal" reallocation.
41 struct tag_item
*items
[BULK_MAX
];
44 const char *tag_item_names
[TAG_NUM_OF_ITEM_TYPES
] = {
46 [TAG_ARTIST_SORT
] = "ArtistSort",
49 [TAG_ALBUM_ARTIST_SORT
] = "AlbumArtistSort",
60 /* MusicBrainz tags from http://musicbrainz.org/doc/MusicBrainzTag */
61 [TAG_MUSICBRAINZ_ARTISTID
] = "MUSICBRAINZ_ARTISTID",
62 [TAG_MUSICBRAINZ_ALBUMID
] = "MUSICBRAINZ_ALBUMID",
63 [TAG_MUSICBRAINZ_ALBUMARTISTID
] = "MUSICBRAINZ_ALBUMARTISTID",
64 [TAG_MUSICBRAINZ_TRACKID
] = "MUSICBRAINZ_TRACKID",
67 bool ignore_tag_items
[TAG_NUM_OF_ITEM_TYPES
];
69 static size_t items_size(const struct tag
*tag
)
71 return tag
->num_items
* sizeof(struct tag_item
*);
74 void tag_lib_init(void)
83 /* parse the "metadata_to_use" config parameter below */
85 /* ignore comments by default */
86 ignore_tag_items
[TAG_ITEM_COMMENT
] = true;
88 value
= config_get_string(CONF_METADATA_TO_USE
, NULL
);
92 memset(ignore_tag_items
, true, TAG_NUM_OF_ITEM_TYPES
);
94 if (0 == g_ascii_strcasecmp(value
, "none"))
97 temp
= c
= s
= g_strdup(value
);
99 if (*s
== ',' || *s
== '\0') {
103 for (i
= 0; i
< TAG_NUM_OF_ITEM_TYPES
; i
++) {
104 if (g_ascii_strcasecmp(c
, tag_item_names
[i
]) == 0) {
105 ignore_tag_items
[i
] = false;
109 if (strlen(c
) && i
== TAG_NUM_OF_ITEM_TYPES
) {
110 g_error("error parsing metadata item \"%s\"",
122 struct tag
*tag_new(void)
124 struct tag
*ret
= g_new(struct tag
, 1);
131 static void tag_delete_item(struct tag
*tag
, unsigned idx
)
133 assert(idx
< tag
->num_items
);
136 g_mutex_lock(tag_pool_lock
);
137 tag_pool_put_item(tag
->items
[idx
]);
138 g_mutex_unlock(tag_pool_lock
);
140 if (tag
->num_items
- idx
> 0) {
141 memmove(tag
->items
+ idx
, tag
->items
+ idx
+ 1,
142 tag
->num_items
- idx
);
145 if (tag
->num_items
> 0) {
146 tag
->items
= g_realloc(tag
->items
, items_size(tag
));
153 void tag_clear_items_by_type(struct tag
*tag
, enum tag_type type
)
155 for (unsigned i
= 0; i
< tag
->num_items
; i
++) {
156 if (tag
->items
[i
]->type
== type
) {
157 tag_delete_item(tag
, i
);
158 /* decrement since when just deleted this node */
164 void tag_free(struct tag
*tag
)
170 g_mutex_lock(tag_pool_lock
);
171 for (i
= tag
->num_items
; --i
>= 0; )
172 tag_pool_put_item(tag
->items
[i
]);
173 g_mutex_unlock(tag_pool_lock
);
175 if (tag
->items
== bulk
.items
) {
186 struct tag
*tag_dup(const struct tag
*tag
)
194 ret
->time
= tag
->time
;
195 ret
->num_items
= tag
->num_items
;
196 ret
->items
= ret
->num_items
> 0 ? g_malloc(items_size(tag
)) : NULL
;
198 g_mutex_lock(tag_pool_lock
);
199 for (unsigned i
= 0; i
< tag
->num_items
; i
++)
200 ret
->items
[i
] = tag_pool_dup_item(tag
->items
[i
]);
201 g_mutex_unlock(tag_pool_lock
);
207 tag_merge(const struct tag
*base
, const struct tag
*add
)
212 assert(base
!= NULL
);
215 /* allocate new tag object */
218 ret
->time
= add
->time
> 0 ? add
->time
: base
->time
;
219 ret
->num_items
= base
->num_items
+ add
->num_items
;
220 ret
->items
= ret
->num_items
> 0 ? g_malloc(items_size(ret
)) : NULL
;
222 g_mutex_lock(tag_pool_lock
);
224 /* copy all items from "add" */
226 for (unsigned i
= 0; i
< add
->num_items
; ++i
)
227 ret
->items
[i
] = tag_pool_dup_item(add
->items
[i
]);
231 /* copy additional items from "base" */
233 for (unsigned i
= 0; i
< base
->num_items
; ++i
)
234 if (!tag_has_type(add
, base
->items
[i
]->type
))
235 ret
->items
[n
++] = tag_pool_dup_item(base
->items
[i
]);
237 g_mutex_unlock(tag_pool_lock
);
239 assert(n
<= ret
->num_items
);
241 if (n
< ret
->num_items
) {
242 /* some tags were not copied - shrink ret->items */
246 ret
->items
= g_realloc(ret
->items
, items_size(ret
));
253 tag_get_value(const struct tag
*tag
, enum tag_type type
)
256 assert(type
< TAG_NUM_OF_ITEM_TYPES
);
258 for (unsigned i
= 0; i
< tag
->num_items
; i
++)
259 if (tag
->items
[i
]->type
== type
)
260 return tag
->items
[i
]->value
;
265 bool tag_has_type(const struct tag
*tag
, enum tag_type type
)
267 return tag_get_value(tag
, type
) != NULL
;
270 bool tag_equal(const struct tag
*tag1
, const struct tag
*tag2
)
272 if (tag1
== NULL
&& tag2
== NULL
)
274 else if (!tag1
|| !tag2
)
277 if (tag1
->time
!= tag2
->time
)
280 if (tag1
->num_items
!= tag2
->num_items
)
283 for (unsigned i
= 0; i
< tag1
->num_items
; i
++) {
284 if (tag1
->items
[i
]->type
!= tag2
->items
[i
]->type
)
286 if (strcmp(tag1
->items
[i
]->value
, tag2
->items
[i
]->value
)) {
295 * Replace invalid sequences with the question mark.
298 patch_utf8(const char *src
, size_t length
, const gchar
*end
)
300 /* duplicate the string, and replace invalid bytes in that
302 char *dest
= g_strdup(src
);
305 dest
[end
- src
] = '?';
306 } while (!g_utf8_validate(end
+ 1, (src
+ length
) - (end
+ 1), &end
));
312 fix_utf8(const char *str
, size_t length
)
320 /* check if the string is already valid UTF-8 */
321 if (g_utf8_validate(str
, length
, &end
))
324 /* no, it's not - try to import it from ISO-Latin-1 */
325 temp
= g_convert(str
, length
, "utf-8", "iso-8859-1",
326 NULL
, &written
, NULL
);
331 /* no, still broken - there's no medication, just patch
333 return patch_utf8(str
, length
, end
);
336 void tag_begin_add(struct tag
*tag
)
340 assert(tag
->items
== NULL
);
341 assert(tag
->num_items
== 0);
346 tag
->items
= bulk
.items
;
349 void tag_end_add(struct tag
*tag
)
351 if (tag
->items
== bulk
.items
) {
352 assert(tag
->num_items
<= BULK_MAX
);
354 if (tag
->num_items
> 0) {
355 /* copy the tag items from the bulk list over
356 to a new list (which fits exactly) */
357 tag
->items
= g_malloc(items_size(tag
));
358 memcpy(tag
->items
, bulk
.items
, items_size(tag
));
369 char_is_non_printable(unsigned char ch
)
375 find_non_printable(const char *p
, size_t length
)
377 for (size_t i
= 0; i
< length
; ++i
)
378 if (char_is_non_printable(p
[i
]))
385 * Clears all non-printable characters, convert them to space.
386 * Returns NULL if nothing needs to be cleared.
389 clear_non_printable(const char *p
, size_t length
)
391 const char *first
= find_non_printable(p
, length
);
397 dest
= g_strndup(p
, length
);
399 for (size_t i
= first
- p
; i
< length
; ++i
)
400 if (char_is_non_printable(dest
[i
]))
407 fix_tag_value(const char *p
, size_t length
)
409 char *utf8
, *cleared
;
411 utf8
= fix_utf8(p
, length
);
417 cleared
= clear_non_printable(p
, length
);
427 tag_add_item_internal(struct tag
*tag
, enum tag_type type
,
428 const char *value
, size_t len
)
430 unsigned int i
= tag
->num_items
;
433 p
= fix_tag_value(value
, len
);
441 if (tag
->items
!= bulk
.items
)
442 /* bulk mode disabled */
443 tag
->items
= g_realloc(tag
->items
, items_size(tag
));
444 else if (tag
->num_items
>= BULK_MAX
) {
445 /* bulk list already full - switch back to non-bulk */
448 tag
->items
= g_malloc(items_size(tag
));
449 memcpy(tag
->items
, bulk
.items
,
450 items_size(tag
) - sizeof(struct tag_item
*));
453 g_mutex_lock(tag_pool_lock
);
454 tag
->items
[i
] = tag_pool_get_item(type
, value
, len
);
455 g_mutex_unlock(tag_pool_lock
);
460 void tag_add_item_n(struct tag
*tag
, enum tag_type type
,
461 const char *value
, size_t len
)
463 if (ignore_tag_items
[type
])
470 tag_add_item_internal(tag
, type
, value
, len
);