1 /* plugin_common - Routines common to several plugins
2 * Copyright (C) 2002 Daisuke Shimamura
4 * Almost from id3_tag.c - 2001/02/16
5 * EasyTAG - Tag editor for MP3 and OGG files
6 * Copyright (C) 2001-2002 Jerome Couderc <j.couderc@ifrance.com>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 #ifdef FLAC__HAS_ID3LIB
33 #include "FLAC/assert.h"
35 #include "id3v1.h" /* for genre stuff */
36 #include "locale_hack.h"
38 #define ID3V2_MAX_STRING_LEN 4096
39 #define NUMBER_TRACK_FORMATED 1
42 /* local__strip() based on glib's g_strchomp() and g_strchug():
43 * GLIB - Library of useful routines for C programming
44 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
47 static void local__strip(char *string)
54 for(s = string; *s && isspace(*s); s++)
57 memmove(string, s, strlen((char*)s) + 1);
62 for(s = string + strlen (string) - 1; s >= string && isspace(*s); s--)
68 * As the ID3Tag_Link function of id3lib-3.8.0pre2 returns the ID3v1 tags
69 * when a file has both ID3v1 and ID3v2 tags, we first try to explicitely
70 * get the ID3v2 tags with ID3Tag_LinkWithFlags and, if we cannot get them,
71 * fall back to the ID3v1 tags.
72 * (Written by Holger Schemel).
74 static size_t local__ID3Tag_Link_wrapper(ID3Tag *id3tag, const char *filename)
78 # if ( (ID3LIB_MAJOR >= 3) && (ID3LIB_MINOR >= 8) )
79 /* First, try to get the ID3v2 tags */
80 offset = ID3Tag_LinkWithFlags(id3tag, filename, ID3TT_ID3V2);
82 /* No ID3v2 tags available => try to get the ID3v1 tags */
83 offset = ID3Tag_LinkWithFlags(id3tag, filename, ID3TT_ID3V1);
86 /* Function 'ID3Tag_LinkWithFlags' is not defined up to id3lib-.3.7.13 */
87 offset = ID3Tag_Link(id3tag, filename);
94 * As the ID3Field_GetASCII function differs with the version of id3lib, we must redefine it.
96 /* [JEC] old id3lib versions may have used index_t for itemNum but size_t is what it wants now and seems safe enough. */
97 static size_t local__ID3Field_GetASCII_wrapper(const ID3Field *field, char *buffer, size_t maxChars, size_t itemNum)
100 /* Defined by id3lib: ID3LIB_MAJOR_VERSION, ID3LIB_MINOR_VERSION, ID3LIB_PATCH_VERSION
101 * Defined by autoconf: ID3LIB_MAJOR, ID3LIB_MINOR, ID3LIB_PATCH
103 * <= 3.7.12 : first item num is 1 for ID3Field_GetASCII
104 * = 3.7.13 : first item num is 0 for ID3Field_GetASCII
105 * >= 3.8.0 : doesn't need item num for ID3Field_GetASCII
107 # if (ID3LIB_MAJOR >= 3)
109 # if (ID3LIB_MINOR <= 7)
110 /* (3.0.0 to 3.7.x) */
111 # if (ID3LIB_PATCH >= 13)
113 return ID3Field_GetASCII(field, buffer, maxChars, itemNum);
115 return ID3Field_GetASCII(field, buffer, maxChars, itemNum+1);
119 /*return ID3Field_GetASCII(field, buffer, maxChars); */
120 return ID3Field_GetASCIIItem(field, buffer, maxChars, itemNum);
123 /* Not tested (< 3.x.x) */
124 return ID3Field_GetASCII(field, buffer, maxChars, itemNum+1);
130 * Returns the name of a genre code if found
131 * Three states for genre code :
132 * - defined (0 to GENRE_MAX)
133 * - undefined/unknown (GENRE_MAX+1 to ID3_INVALID_GENRE-1)
134 * - invalid (>ID3_INVALID_GENRE)
136 static const char *local__genre_to_string(unsigned genre_code)
138 if(genre_code >= FLAC_PLUGIN__ID3V1_TAG_INVALID_GENRE)
141 const char *s = FLAC_plugin__id3v1_tag_get_genre_as_string((unsigned)genre_code);
151 * Read id3v1.x / id3v2 tag and load data into the File_Tag structure using id3lib functions.
152 * Returns true on success, else false.
153 * If a tag entry exists (ex: title), we allocate memory, else value stays to NULL
155 static FLAC__bool local__get_tag(const char *filename, FLAC_Plugin__CanonicalTag *tag)
158 ID3Tag *id3_tag = 0; /* Tag defined by id3lib */
159 char *string, *string1;
161 FLAC__ASSERT(0 != filename);
162 FLAC__ASSERT(0 != tag);
164 if(0 == (file = fopen(filename, "r"))) {
166 fprintf(stderr, _("ERROR while opening file: '%s' (%s).\n\a"), filename, strerror(errno));
170 fclose(file); /* We close it cause id3lib opens/closes file itself */
173 /* Get data from tag */
174 if(0 != (id3_tag = ID3Tag_New())) {
179 size_t field_num = 0; /* First field */
181 /* Link the file to the tag */
182 frm_size = local__ID3Tag_Link_wrapper(id3_tag, filename);
184 string = malloc(ID3V2_MAX_STRING_LEN+1);
189 if(0 != (id3_frame = ID3Tag_FindFrameWithID(id3_tag, ID3FID_TITLE))) {
190 if(0 != (id3_field = ID3Frame_GetField(id3_frame, ID3FN_TEXT))) {
191 /* Note: if 'num_chars' is equal to 0, then the field is empty or corrupted! */
192 if((num_chars = local__ID3Field_GetASCII_wrapper(id3_field, string, ID3V2_MAX_STRING_LEN, field_num)) > 0 && string != NULL) {
193 local__strip(string);
194 tag->title = strdup(string);
203 if(0 != (id3_frame = ID3Tag_FindFrameWithID(id3_tag, ID3FID_COMPOSER))) {
204 if(0 != (id3_field = ID3Frame_GetField(id3_frame, ID3FN_TEXT))) {
205 if((num_chars = local__ID3Field_GetASCII_wrapper(id3_field, string, ID3V2_MAX_STRING_LEN, field_num)) > 0 && string != NULL) {
206 local__strip(string);
207 tag->composer = strdup(string);
216 if(0 != (id3_frame = ID3Tag_FindFrameWithID(id3_tag, ID3FID_LEADARTIST))) {
217 if(0 != (id3_field = ID3Frame_GetField(id3_frame, ID3FN_TEXT))) {
218 if((num_chars = local__ID3Field_GetASCII_wrapper(id3_field, string, ID3V2_MAX_STRING_LEN, field_num)) > 0 && string != NULL) {
219 local__strip(string);
220 tag->performer = strdup(string);
229 if(0 != (id3_frame = ID3Tag_FindFrameWithID(id3_tag, ID3FID_ALBUM))) {
230 if(0 != (id3_field = ID3Frame_GetField(id3_frame, ID3FN_TEXT))) {
231 if((num_chars = local__ID3Field_GetASCII_wrapper(id3_field, string, ID3V2_MAX_STRING_LEN, field_num)) > 0 && string != NULL) {
232 local__strip(string);
233 tag->album = strdup(string);
242 if(0 != (id3_frame = ID3Tag_FindFrameWithID(id3_tag, ID3FID_YEAR))) {
243 if(0 != (id3_field = ID3Frame_GetField(id3_frame, ID3FN_TEXT))) {
244 if((num_chars = local__ID3Field_GetASCII_wrapper(id3_field, string, ID3V2_MAX_STRING_LEN, field_num)) > 0 && string != NULL) {
247 local__strip(string);
249 /* Fix for id3lib 3.7.x: if the id3v1.x tag was filled with spaces
250 * instead of zeroes, then the year field contains garbages! */
252 while (isdigit(*tmp_str)) tmp_str++;
254 /* End of fix for id3lib 3.7.x */
256 local__strip(string);
257 tag->year_recorded = strdup(string);
258 tag->year_performed = strdup(string);
264 /*************************
265 * Track and Total Track *
266 *************************/
267 if(0 != (id3_frame = ID3Tag_FindFrameWithID(id3_tag, ID3FID_TRACKNUM))) {
268 if(0 != (id3_field = ID3Frame_GetField(id3_frame, ID3FN_TEXT))) {
269 if((num_chars = local__ID3Field_GetASCII_wrapper(id3_field, string, ID3V2_MAX_STRING_LEN, field_num)) > 0 && string != NULL) {
270 local__strip(string);
272 string1 = strchr(string, '/');
273 if (NUMBER_TRACK_FORMATED) {
275 /* Just to have numbers like this : '01', '05', '12', ... */
276 tag->tracks_in_album = malloc(64);
277 sprintf(tag->tracks_in_album, "%.2d", atoi(string1+1));
280 /* Just to have numbers like this : '01', '05', '12', ... */
281 tag->track_number = malloc(64);
282 sprintf(tag->track_number, "%.2d", atoi(string));
286 tag->tracks_in_album = strdup(string1+1);
289 tag->track_number = strdup(string);
299 if(0 != (id3_frame = ID3Tag_FindFrameWithID(id3_tag, ID3FID_CONTENTTYPE))) {
300 if(0 != (id3_field = ID3Frame_GetField(id3_frame, ID3FN_TEXT))) {
302 * We manipulate only the name of the genre
304 if((num_chars = local__ID3Field_GetASCII_wrapper(id3_field, string, ID3V2_MAX_STRING_LEN, field_num)) > 0 && string != NULL) {
307 local__strip(string);
309 if((string[0]=='(') && (tmp=strchr(string, ')')) && (strlen((tmp+1))>0)) {
310 /* Convert a genre written as '(3)Dance' into 'Dance' */
311 tag->genre = strdup(tmp+1);
314 else if((string[0]=='(') && (tmp=strchr(string, ')'))) {
315 /* Convert a genre written as '(3)' into 'Dance' */
317 tag->genre = strdup(local__genre_to_string((unsigned)atoi(string+1)));
321 /* Genre is already written as 'Dance' */
322 tag->genre = strdup(string);
332 if(0 != (id3_frame = ID3Tag_FindFrameWithID(id3_tag, ID3FID_COMMENT))) {
333 if(0 != (id3_field = ID3Frame_GetField(id3_frame, ID3FN_TEXT))) {
334 if((num_chars = local__ID3Field_GetASCII_wrapper(id3_field, string, ID3V2_MAX_STRING_LEN, field_num)) > 0 && string != NULL) {
335 local__strip(string);
336 tag->comment = strdup(string);
340 if(0 != (id3_field = ID3Frame_GetField(id3_frame, ID3FN_DESCRIPTION))) {
341 char *comment1 = calloc(MAX_STRING_LEN+1);
342 num_chars = ID3Field_GetASCII(id3_field, comment1, MAX_STRING_LEN, Item_Num);
345 if(0 != (id3_field = ID3Frame_GetField(id3_frame, ID3FN_LANGUAGE))) {
346 char *comment2 = calloc(MAX_STRING_LEN+1);
347 num_chars = ID3Field_GetASCII(id3_field, comment2, MAX_STRING_LEN, Item_Num);
354 /* Free allocated data */
355 ID3Tag_Delete(id3_tag);
360 #endif /* ifdef FLAC__HAS_ID3LIB */
362 FLAC__bool FLAC_plugin__id3v2_tag_get(const char *filename, FLAC_Plugin__CanonicalTag *tag)
364 #ifdef FLAC__HAS_ID3LIB
365 return local__get_tag(filename, tag);