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.
36 #define G_LOG_DOMAIN "id3"
38 # ifndef ID3_FRAME_COMPOSER
39 # define ID3_FRAME_COMPOSER "TCOM"
41 # ifndef ID3_FRAME_DISC
42 # define ID3_FRAME_DISC "TPOS"
45 #ifndef ID3_FRAME_ARTIST_SORT
46 #define ID3_FRAME_ARTIST_SORT "TSOP"
49 #ifndef ID3_FRAME_ALBUM_ARTIST_SORT
50 #define ID3_FRAME_ALBUM_ARTIST_SORT "TSO2" /* this one is unofficial, introduced by Itunes */
53 #ifndef ID3_FRAME_ALBUM_ARTIST
54 #define ID3_FRAME_ALBUM_ARTIST "TPE2"
58 tag_is_id3v1(struct id3_tag
*tag
)
60 return (id3_tag_options(tag
, 0, 0) & ID3_TAG_OPTION_ID3V1
) != 0;
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
);
73 ucs4
= id3_field_getstring(field
);
77 return id3_ucs4_utf8duplicate(ucs4
);
80 /* This will try to convert a string to utf-8,
83 import_id3_string(bool is_id3v1
, const id3_ucs4_t
*ucs4
)
85 id3_utf8_t
*utf8
, *utf8_stripped
;
89 /* use encoding field here? */
91 (encoding
= config_get_string(CONF_ID3V1_ENCODING
, NULL
)) != NULL
) {
92 isostr
= id3_ucs4_latin1duplicate(ucs4
);
93 if (G_UNLIKELY(!isostr
)) {
98 g_convert_with_fallback((const char*)isostr
, -1,
100 NULL
, NULL
, NULL
, NULL
);
102 g_debug("Unable to convert %s string to UTF-8: '%s'",
109 utf8
= id3_ucs4_utf8duplicate(ucs4
);
110 if (G_UNLIKELY(!utf8
)) {
115 utf8_stripped
= (id3_utf8_t
*)g_strdup(g_strstrip((gchar
*)utf8
));
118 return utf8_stripped
;
122 * Import a "Text information frame" (ID3v2.4.0 section 4.2). It
129 tag_id3_import_text(struct tag
*dest
, struct id3_tag
*tag
, const char *id
,
132 struct id3_frame
const *frame
;
133 id3_ucs4_t
const *ucs4
;
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)
142 /* check the encoding field */
144 field
= id3_frame_field(frame
, 0);
145 if (field
== NULL
|| field
->type
!= ID3_FIELD_TYPE_TEXTENCODING
)
148 /* process the value(s) */
150 field
= id3_frame_field(frame
, 1);
151 if (field
== NULL
|| field
->type
!= ID3_FIELD_TYPE_STRINGLIST
)
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
);
161 if (type
== TAG_GENRE
)
162 ucs4
= id3_genre_name(ucs4
);
164 utf8
= import_id3_string(tag_is_id3v1(tag
), ucs4
);
168 tag_add_item(dest
, type
, (char *)utf8
);
174 * Import a "Comment frame" (ID3v2.4.0 section 4.10). It
180 * - full string (we use this one)
183 tag_id3_import_comment(struct tag
*dest
, struct id3_tag
*tag
, const char *id
,
186 struct id3_frame
const *frame
;
187 id3_ucs4_t
const *ucs4
;
189 union id3_field
const *field
;
191 frame
= id3_tag_findframe(tag
, id
, 0);
192 if (frame
== NULL
|| frame
->nfields
!= 4)
195 /* for now I only read the 4th field, with the fullstring */
196 field
= id3_frame_field(frame
, 3);
200 ucs4
= id3_field_getfullstring(field
);
204 utf8
= import_id3_string(tag_is_id3v1(tag
), ucs4
);
208 tag_add_item(dest
, type
, (char *)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.
217 tag_id3_parse_txxx_name(const char *name
)
219 static const struct {
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.
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
;
249 frame
= id3_tag_findframe(id3_tag
, "TXXX", i
);
253 name
= tag_id3_getstring(frame
, 1);
257 type
= tag_id3_parse_txxx_name((const char*)name
);
260 if (type
== TAG_NUM_OF_ITEM_TYPES
)
263 value
= tag_id3_getstring(frame
, 2);
267 tag_add_item(mpd_tag
, type
, (const char*)value
);
273 * Imports the MusicBrainz TrackId from the UFID tag.
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
;
285 frame
= id3_tag_findframe(id3_tag
, "UFID", i
);
289 field
= id3_frame_field(frame
, 0);
293 name
= id3_field_getlatin1(field
);
295 strcmp((const char *)name
, "http://musicbrainz.org") != 0)
298 field
= id3_frame_field(frame
, 1);
302 value
= id3_field_getbinarydata(field
, &length
);
303 if (value
== NULL
|| length
== 0)
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
,
318 tag_id3_import_text(ret
, tag
, ID3_FRAME_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
)) {
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
);
352 get_id3v2_footer_size(FILE *stream
, long offset
, int whence
)
354 id3_byte_t buf
[ID3_TAG_QUERYSIZE
];
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
)
366 id3_byte_t query_buffer
[ID3_TAG_QUERYSIZE
];
367 id3_byte_t
*tag_buffer
;
369 int query_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
) {
391 tag
= id3_tag_parse(tag_buffer
, tag_buffer_size
);
398 static struct id3_tag
*
399 tag_id3_find_from_beginning(FILE *stream
)
402 struct id3_tag
*seektag
;
403 struct id3_frame
*frame
;
406 tag
= tag_id3_read(stream
, 0, SEEK_SET
);
409 } else if (tag_is_id3v1(tag
)) {
410 /* id3v1 tags don't belong here */
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));
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
))
427 /* Replace the old tag with the new one */
435 static struct id3_tag
*
436 tag_id3_find_from_end(FILE *stream
)
439 struct id3_tag
*v1tag
;
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
);
450 /* Get the tag which the footer belongs to */
451 tag
= tag_id3_read(stream
, tagsize
, SEEK_CUR
);
455 /* We have an id3v2 tag, so ditch v1tag */
456 id3_tag_delete(v1tag
);
461 static struct id3_tag
*
462 tag_id3_riff_aiff_load(FILE *file
)
469 size
= riff_seek_id3(file
);
471 size
= aiff_seek_id3(file
);
475 if (size
> 4 * 1024 * 1024)
476 /* too large, don't allocate so much memory */
479 buffer
= g_malloc(size
);
480 ret
= fread(buffer
, size
, 1, file
);
482 g_warning("Failed to read RIFF chunk");
487 tag
= id3_tag_parse(buffer
, size
);
492 struct tag
*tag_id3_load(const char *file
)
498 stream
= fopen(file
, "r");
500 g_debug("tag_id3_load: Failed to open file: '%s', %s",
501 file
, strerror(errno
));
505 tag
= tag_id3_find_from_beginning(stream
);
507 tag
= tag_id3_riff_aiff_load(stream
);
509 tag
= tag_id3_find_from_end(stream
);
515 ret
= tag_id3_import(tag
);