configure.ac: Move OpenAL to Audio Output Plugins (nonstreaming), add header.
[mpd-mk.git] / src / tag_id3.c
blob008eff87775dfff091953590b84dc12d1a0ceed7
1 /*
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.
20 #include "config.h"
21 #include "tag_id3.h"
22 #include "tag.h"
23 #include "riff.h"
24 #include "aiff.h"
25 #include "conf.h"
27 #include <glib.h>
28 #include <id3tag.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <string.h>
35 #undef G_LOG_DOMAIN
36 #define G_LOG_DOMAIN "id3"
38 # ifndef ID3_FRAME_COMPOSER
39 # define ID3_FRAME_COMPOSER "TCOM"
40 # endif
41 # ifndef ID3_FRAME_DISC
42 # define ID3_FRAME_DISC "TPOS"
43 # endif
45 #ifndef ID3_FRAME_ARTIST_SORT
46 #define ID3_FRAME_ARTIST_SORT "TSOP"
47 #endif
49 #ifndef ID3_FRAME_ALBUM_ARTIST_SORT
50 #define ID3_FRAME_ALBUM_ARTIST_SORT "TSO2" /* this one is unofficial, introduced by Itunes */
51 #endif
53 #ifndef ID3_FRAME_ALBUM_ARTIST
54 #define ID3_FRAME_ALBUM_ARTIST "TPE2"
55 #endif
57 static inline bool
58 tag_is_id3v1(struct id3_tag *tag)
60 return (id3_tag_options(tag, 0, 0) & ID3_TAG_OPTION_ID3V1) != 0;
63 static id3_utf8_t *
64 tag_id3_getstring(const struct id3_frame *frame, unsigned i)
66 union id3_field *field;
67 const id3_ucs4_t *ucs4;
69 field = id3_frame_field(frame, i);
70 if (field == NULL)
71 return NULL;
73 ucs4 = id3_field_getstring(field);
74 if (ucs4 == NULL)
75 return NULL;
77 return id3_ucs4_utf8duplicate(ucs4);
80 /* This will try to convert a string to utf-8,
82 static id3_utf8_t *
83 import_id3_string(bool is_id3v1, const id3_ucs4_t *ucs4)
85 id3_utf8_t *utf8, *utf8_stripped;
86 id3_latin1_t *isostr;
87 const char *encoding;
89 /* use encoding field here? */
90 if (is_id3v1 &&
91 (encoding = config_get_string(CONF_ID3V1_ENCODING, NULL)) != NULL) {
92 isostr = id3_ucs4_latin1duplicate(ucs4);
93 if (G_UNLIKELY(!isostr)) {
94 return NULL;
97 utf8 = (id3_utf8_t *)
98 g_convert_with_fallback((const char*)isostr, -1,
99 "utf-8", encoding,
100 NULL, NULL, NULL, NULL);
101 if (utf8 == NULL) {
102 g_debug("Unable to convert %s string to UTF-8: '%s'",
103 encoding, isostr);
104 g_free(isostr);
105 return NULL;
107 g_free(isostr);
108 } else {
109 utf8 = id3_ucs4_utf8duplicate(ucs4);
110 if (G_UNLIKELY(!utf8)) {
111 return NULL;
115 utf8_stripped = (id3_utf8_t *)g_strdup(g_strstrip((gchar *)utf8));
116 g_free(utf8);
118 return utf8_stripped;
122 * Import a "Text information frame" (ID3v2.4.0 section 4.2). It
123 * contains 2 fields:
125 * - encoding
126 * - string list
128 static void
129 tag_id3_import_text(struct tag *dest, struct id3_tag *tag, const char *id,
130 enum tag_type type)
132 struct id3_frame const *frame;
133 id3_ucs4_t const *ucs4;
134 id3_utf8_t *utf8;
135 union id3_field const *field;
136 unsigned int nstrings, i;
138 frame = id3_tag_findframe(tag, id, 0);
139 if (frame == NULL || frame->nfields != 2)
140 return;
142 /* check the encoding field */
144 field = id3_frame_field(frame, 0);
145 if (field == NULL || field->type != ID3_FIELD_TYPE_TEXTENCODING)
146 return;
148 /* process the value(s) */
150 field = id3_frame_field(frame, 1);
151 if (field == NULL || field->type != ID3_FIELD_TYPE_STRINGLIST)
152 return;
154 /* Get the number of strings available */
155 nstrings = id3_field_getnstrings(field);
156 for (i = 0; i < nstrings; i++) {
157 ucs4 = id3_field_getstrings(field, i);
158 if (ucs4 == NULL)
159 continue;
161 if (type == TAG_GENRE)
162 ucs4 = id3_genre_name(ucs4);
164 utf8 = import_id3_string(tag_is_id3v1(tag), ucs4);
165 if (utf8 == NULL)
166 continue;
168 tag_add_item(dest, type, (char *)utf8);
169 g_free(utf8);
174 * Import a "Comment frame" (ID3v2.4.0 section 4.10). It
175 * contains 4 fields:
177 * - encoding
178 * - language
179 * - string
180 * - full string (we use this one)
182 static void
183 tag_id3_import_comment(struct tag *dest, struct id3_tag *tag, const char *id,
184 enum tag_type type)
186 struct id3_frame const *frame;
187 id3_ucs4_t const *ucs4;
188 id3_utf8_t *utf8;
189 union id3_field const *field;
191 frame = id3_tag_findframe(tag, id, 0);
192 if (frame == NULL || frame->nfields != 4)
193 return;
195 /* for now I only read the 4th field, with the fullstring */
196 field = id3_frame_field(frame, 3);
197 if (field == NULL)
198 return;
200 ucs4 = id3_field_getfullstring(field);
201 if (ucs4 == NULL)
202 return;
204 utf8 = import_id3_string(tag_is_id3v1(tag), ucs4);
205 if (utf8 == NULL)
206 return;
208 tag_add_item(dest, type, (char *)utf8);
209 g_free(utf8);
213 * Parse a TXXX name, and convert it to a tag_type enum value.
214 * Returns TAG_NUM_OF_ITEM_TYPES if the TXXX name is not understood.
216 static enum tag_type
217 tag_id3_parse_txxx_name(const char *name)
219 static const struct {
220 enum tag_type type;
221 const char *name;
222 } musicbrainz_txxx[] = {
223 { TAG_ALBUM_ARTIST_SORT, "ALBUMARTISTSORT" },
224 { TAG_MUSICBRAINZ_ARTISTID, "MusicBrainz Artist Id" },
225 { TAG_MUSICBRAINZ_ALBUMID, "MusicBrainz Album Id" },
226 { TAG_MUSICBRAINZ_ALBUMARTISTID,
227 "MusicBrainz Album Artist Id" },
228 { TAG_MUSICBRAINZ_TRACKID, "MusicBrainz Track Id" },
231 for (unsigned i = 0; i < G_N_ELEMENTS(musicbrainz_txxx); ++i)
232 if (strcmp(name, musicbrainz_txxx[i].name) == 0)
233 return musicbrainz_txxx[i].type;
235 return TAG_NUM_OF_ITEM_TYPES;
239 * Import all known MusicBrainz tags from TXXX frames.
241 static void
242 tag_id3_import_musicbrainz(struct tag *mpd_tag, struct id3_tag *id3_tag)
244 for (unsigned i = 0;; ++i) {
245 const struct id3_frame *frame;
246 id3_utf8_t *name, *value;
247 enum tag_type type;
249 frame = id3_tag_findframe(id3_tag, "TXXX", i);
250 if (frame == NULL)
251 break;
253 name = tag_id3_getstring(frame, 1);
254 if (name == NULL)
255 continue;
257 type = tag_id3_parse_txxx_name((const char*)name);
258 free(name);
260 if (type == TAG_NUM_OF_ITEM_TYPES)
261 continue;
263 value = tag_id3_getstring(frame, 2);
264 if (value == NULL)
265 continue;
267 tag_add_item(mpd_tag, type, (const char*)value);
268 free(value);
273 * Imports the MusicBrainz TrackId from the UFID tag.
275 static void
276 tag_id3_import_ufid(struct tag *mpd_tag, struct id3_tag *id3_tag)
278 for (unsigned i = 0;; ++i) {
279 const struct id3_frame *frame;
280 union id3_field *field;
281 const id3_latin1_t *name;
282 const id3_byte_t *value;
283 id3_length_t length;
285 frame = id3_tag_findframe(id3_tag, "UFID", i);
286 if (frame == NULL)
287 break;
289 field = id3_frame_field(frame, 0);
290 if (field == NULL)
291 continue;
293 name = id3_field_getlatin1(field);
294 if (name == NULL ||
295 strcmp((const char *)name, "http://musicbrainz.org") != 0)
296 continue;
298 field = id3_frame_field(frame, 1);
299 if (field == NULL)
300 continue;
302 value = id3_field_getbinarydata(field, &length);
303 if (value == NULL || length == 0)
304 continue;
306 tag_add_item_n(mpd_tag, TAG_MUSICBRAINZ_TRACKID,
307 (const char*)value, length);
311 struct tag *tag_id3_import(struct id3_tag * tag)
313 struct tag *ret = tag_new();
315 tag_id3_import_text(ret, tag, ID3_FRAME_ARTIST, TAG_ARTIST);
316 tag_id3_import_text(ret, tag, ID3_FRAME_ALBUM_ARTIST,
317 TAG_ALBUM_ARTIST);
318 tag_id3_import_text(ret, tag, ID3_FRAME_ARTIST_SORT,
319 TAG_ARTIST_SORT);
320 tag_id3_import_text(ret, tag, ID3_FRAME_ALBUM_ARTIST_SORT,
321 TAG_ALBUM_ARTIST_SORT);
322 tag_id3_import_text(ret, tag, ID3_FRAME_TITLE, TAG_TITLE);
323 tag_id3_import_text(ret, tag, ID3_FRAME_ALBUM, TAG_ALBUM);
324 tag_id3_import_text(ret, tag, ID3_FRAME_TRACK, TAG_TRACK);
325 tag_id3_import_text(ret, tag, ID3_FRAME_YEAR, TAG_DATE);
326 tag_id3_import_text(ret, tag, ID3_FRAME_GENRE, TAG_GENRE);
327 tag_id3_import_text(ret, tag, ID3_FRAME_COMPOSER, TAG_COMPOSER);
328 tag_id3_import_text(ret, tag, "TPE3", TAG_PERFORMER);
329 tag_id3_import_text(ret, tag, "TPE4", TAG_PERFORMER);
330 tag_id3_import_comment(ret, tag, ID3_FRAME_COMMENT, TAG_COMMENT);
331 tag_id3_import_text(ret, tag, ID3_FRAME_DISC, TAG_DISC);
333 tag_id3_import_musicbrainz(ret, tag);
334 tag_id3_import_ufid(ret, tag);
336 if (tag_is_empty(ret)) {
337 tag_free(ret);
338 ret = NULL;
341 return ret;
344 static int
345 fill_buffer(void *buf, size_t size, FILE *stream, long offset, int whence)
347 if (fseek(stream, offset, whence) != 0) return 0;
348 return fread(buf, 1, size, stream);
351 static int
352 get_id3v2_footer_size(FILE *stream, long offset, int whence)
354 id3_byte_t buf[ID3_TAG_QUERYSIZE];
355 int bufsize;
357 bufsize = fill_buffer(buf, ID3_TAG_QUERYSIZE, stream, offset, whence);
358 if (bufsize <= 0) return 0;
359 return id3_tag_query(buf, bufsize);
362 static struct id3_tag *
363 tag_id3_read(FILE *stream, long offset, int whence)
365 struct id3_tag *tag;
366 id3_byte_t query_buffer[ID3_TAG_QUERYSIZE];
367 id3_byte_t *tag_buffer;
368 int tag_size;
369 int query_buffer_size;
370 int tag_buffer_size;
372 /* It's ok if we get less than we asked for */
373 query_buffer_size = fill_buffer(query_buffer, ID3_TAG_QUERYSIZE,
374 stream, offset, whence);
375 if (query_buffer_size <= 0) return NULL;
377 /* Look for a tag header */
378 tag_size = id3_tag_query(query_buffer, query_buffer_size);
379 if (tag_size <= 0) return NULL;
381 /* Found a tag. Allocate a buffer and read it in. */
382 tag_buffer = g_malloc(tag_size);
383 if (!tag_buffer) return NULL;
385 tag_buffer_size = fill_buffer(tag_buffer, tag_size, stream, offset, whence);
386 if (tag_buffer_size < tag_size) {
387 g_free(tag_buffer);
388 return NULL;
391 tag = id3_tag_parse(tag_buffer, tag_buffer_size);
393 g_free(tag_buffer);
395 return tag;
398 static struct id3_tag *
399 tag_id3_find_from_beginning(FILE *stream)
401 struct id3_tag *tag;
402 struct id3_tag *seektag;
403 struct id3_frame *frame;
404 int seek;
406 tag = tag_id3_read(stream, 0, SEEK_SET);
407 if (!tag) {
408 return NULL;
409 } else if (tag_is_id3v1(tag)) {
410 /* id3v1 tags don't belong here */
411 id3_tag_delete(tag);
412 return NULL;
415 /* We have an id3v2 tag, so let's look for SEEK frames */
416 while ((frame = id3_tag_findframe(tag, "SEEK", 0))) {
417 /* Found a SEEK frame, get it's value */
418 seek = id3_field_getint(id3_frame_field(frame, 0));
419 if (seek < 0)
420 break;
422 /* Get the tag specified by the SEEK frame */
423 seektag = tag_id3_read(stream, seek, SEEK_CUR);
424 if (!seektag || tag_is_id3v1(seektag))
425 break;
427 /* Replace the old tag with the new one */
428 id3_tag_delete(tag);
429 tag = seektag;
432 return tag;
435 static struct id3_tag *
436 tag_id3_find_from_end(FILE *stream)
438 struct id3_tag *tag;
439 struct id3_tag *v1tag;
440 int tagsize;
442 /* Get an id3v1 tag from the end of file for later use */
443 v1tag = tag_id3_read(stream, -128, SEEK_END);
445 /* Get the id3v2 tag size from the footer (located before v1tag) */
446 tagsize = get_id3v2_footer_size(stream, (v1tag ? -128 : 0) - 10, SEEK_END);
447 if (tagsize >= 0)
448 return v1tag;
450 /* Get the tag which the footer belongs to */
451 tag = tag_id3_read(stream, tagsize, SEEK_CUR);
452 if (!tag)
453 return v1tag;
455 /* We have an id3v2 tag, so ditch v1tag */
456 id3_tag_delete(v1tag);
458 return tag;
461 static struct id3_tag *
462 tag_id3_riff_aiff_load(FILE *file)
464 size_t size;
465 void *buffer;
466 size_t ret;
467 struct id3_tag *tag;
469 size = riff_seek_id3(file);
470 if (size == 0)
471 size = aiff_seek_id3(file);
472 if (size == 0)
473 return NULL;
475 if (size > 4 * 1024 * 1024)
476 /* too large, don't allocate so much memory */
477 return NULL;
479 buffer = g_malloc(size);
480 ret = fread(buffer, size, 1, file);
481 if (ret != 1) {
482 g_warning("Failed to read RIFF chunk");
483 g_free(buffer);
484 return NULL;
487 tag = id3_tag_parse(buffer, size);
488 g_free(buffer);
489 return tag;
492 struct tag *tag_id3_load(const char *file)
494 struct tag *ret;
495 struct id3_tag *tag;
496 FILE *stream;
498 stream = fopen(file, "r");
499 if (!stream) {
500 g_debug("tag_id3_load: Failed to open file: '%s', %s",
501 file, strerror(errno));
502 return NULL;
505 tag = tag_id3_find_from_beginning(stream);
506 if (tag == NULL)
507 tag = tag_id3_riff_aiff_load(stream);
508 if (!tag)
509 tag = tag_id3_find_from_end(stream);
511 fclose(stream);
513 if (!tag)
514 return NULL;
515 ret = tag_id3_import(tag);
516 id3_tag_delete(tag);
517 return ret;