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"
42 #define ID3V2_MAX_STRING_LEN 4096
43 #define NUMBER_TRACK_FORMATED 1
46 /* local__strip() based on glib's g_strchomp() and g_strchug():
47 * GLIB - Library of useful routines for C programming
48 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
51 static void local__strip(char *string)
58 for(s = string; *s && isspace(*s); s++)
61 memmove(string, s, strlen((char*)s) + 1);
66 for(s = string + strlen (string) - 1; s >= string && isspace(*s); s--)
72 * As the ID3Tag_Link function of id3lib-3.8.0pre2 returns the ID3v1 tags
73 * when a file has both ID3v1 and ID3v2 tags, we first try to explicitely
74 * get the ID3v2 tags with ID3Tag_LinkWithFlags and, if we cannot get them,
75 * fall back to the ID3v1 tags.
76 * (Written by Holger Schemel).
78 static size_t local__ID3Tag_Link_wrapper(ID3Tag *id3tag, const char *filename)
82 # if ( (ID3LIB_MAJOR >= 3) && (ID3LIB_MINOR >= 8) )
83 /* First, try to get the ID3v2 tags */
84 offset = ID3Tag_LinkWithFlags(id3tag, filename, ID3TT_ID3V2);
86 /* No ID3v2 tags available => try to get the ID3v1 tags */
87 offset = ID3Tag_LinkWithFlags(id3tag, filename, ID3TT_ID3V1);
90 /* Function 'ID3Tag_LinkWithFlags' is not defined up to id3lib-.3.7.13 */
91 offset = ID3Tag_Link(id3tag, filename);
98 * As the ID3Field_GetASCII function differs with the version of id3lib, we must redefine it.
100 /* [JEC] old id3lib versions may have used index_t for itemNum but size_t is what it wants now and seems safe enough. */
101 static size_t local__ID3Field_GetASCII_wrapper(const ID3Field *field, char *buffer, size_t maxChars, size_t itemNum)
104 /* Defined by id3lib: ID3LIB_MAJOR_VERSION, ID3LIB_MINOR_VERSION, ID3LIB_PATCH_VERSION
105 * Defined by autoconf: ID3LIB_MAJOR, ID3LIB_MINOR, ID3LIB_PATCH
107 * <= 3.7.12 : first item num is 1 for ID3Field_GetASCII
108 * = 3.7.13 : first item num is 0 for ID3Field_GetASCII
109 * >= 3.8.0 : doesn't need item num for ID3Field_GetASCII
111 # if (ID3LIB_MAJOR >= 3)
113 # if (ID3LIB_MINOR <= 7)
114 /* (3.0.0 to 3.7.x) */
115 # if (ID3LIB_PATCH >= 13)
117 return ID3Field_GetASCII(field, buffer, maxChars, itemNum);
119 return ID3Field_GetASCII(field, buffer, maxChars, itemNum+1);
123 /*return ID3Field_GetASCII(field, buffer, maxChars); */
124 return ID3Field_GetASCIIItem(field, buffer, maxChars, itemNum);
127 /* Not tested (< 3.x.x) */
128 return ID3Field_GetASCII(field, buffer, maxChars, itemNum+1);
134 * Returns the name of a genre code if found
135 * Three states for genre code :
136 * - defined (0 to GENRE_MAX)
137 * - undefined/unknown (GENRE_MAX+1 to ID3_INVALID_GENRE-1)
138 * - invalid (>ID3_INVALID_GENRE)
140 static const char *local__genre_to_string(unsigned genre_code)
142 if(genre_code >= FLAC_PLUGIN__ID3V1_TAG_INVALID_GENRE)
145 const char *s = FLAC_plugin__id3v1_tag_get_genre_as_string((unsigned)genre_code);
155 * Read id3v1.x / id3v2 tag and load data into the File_Tag structure using id3lib functions.
156 * Returns true on success, else false.
157 * If a tag entry exists (ex: title), we allocate memory, else value stays to NULL
159 static FLAC__bool local__get_tag(const char *filename, FLAC_Plugin__CanonicalTag *tag)
162 ID3Tag *id3_tag = 0; /* Tag defined by id3lib */
163 char *string, *string1;
165 FLAC__ASSERT(0 != filename);
166 FLAC__ASSERT(0 != tag);
168 if(0 == (file = fopen(filename, "r"))) {
170 fprintf(stderr, _("ERROR while opening file: '%s' (%s).\n\a"), filename, strerror(errno));
174 fclose(file); /* We close it cause id3lib opens/closes file itself */
177 /* Get data from tag */
178 if(0 != (id3_tag = ID3Tag_New())) {
183 size_t field_num = 0; /* First field */
185 /* Link the file to the tag */
186 frm_size = local__ID3Tag_Link_wrapper(id3_tag, filename);
188 string = malloc(ID3V2_MAX_STRING_LEN+1);
193 if(0 != (id3_frame = ID3Tag_FindFrameWithID(id3_tag, ID3FID_TITLE))) {
194 if(0 != (id3_field = ID3Frame_GetField(id3_frame, ID3FN_TEXT))) {
195 /* Note: if 'num_chars' is equal to 0, then the field is empty or corrupted! */
196 if((num_chars = local__ID3Field_GetASCII_wrapper(id3_field, string, ID3V2_MAX_STRING_LEN, field_num)) > 0 && string != NULL) {
197 local__strip(string);
198 tag->title = strdup(string);
207 if(0 != (id3_frame = ID3Tag_FindFrameWithID(id3_tag, ID3FID_COMPOSER))) {
208 if(0 != (id3_field = ID3Frame_GetField(id3_frame, ID3FN_TEXT))) {
209 if((num_chars = local__ID3Field_GetASCII_wrapper(id3_field, string, ID3V2_MAX_STRING_LEN, field_num)) > 0 && string != NULL) {
210 local__strip(string);
211 tag->composer = strdup(string);
220 if(0 != (id3_frame = ID3Tag_FindFrameWithID(id3_tag, ID3FID_LEADARTIST))) {
221 if(0 != (id3_field = ID3Frame_GetField(id3_frame, ID3FN_TEXT))) {
222 if((num_chars = local__ID3Field_GetASCII_wrapper(id3_field, string, ID3V2_MAX_STRING_LEN, field_num)) > 0 && string != NULL) {
223 local__strip(string);
224 tag->performer = strdup(string);
233 if(0 != (id3_frame = ID3Tag_FindFrameWithID(id3_tag, ID3FID_ALBUM))) {
234 if(0 != (id3_field = ID3Frame_GetField(id3_frame, ID3FN_TEXT))) {
235 if((num_chars = local__ID3Field_GetASCII_wrapper(id3_field, string, ID3V2_MAX_STRING_LEN, field_num)) > 0 && string != NULL) {
236 local__strip(string);
237 tag->album = strdup(string);
246 if(0 != (id3_frame = ID3Tag_FindFrameWithID(id3_tag, ID3FID_YEAR))) {
247 if(0 != (id3_field = ID3Frame_GetField(id3_frame, ID3FN_TEXT))) {
248 if((num_chars = local__ID3Field_GetASCII_wrapper(id3_field, string, ID3V2_MAX_STRING_LEN, field_num)) > 0 && string != NULL) {
251 local__strip(string);
253 /* Fix for id3lib 3.7.x: if the id3v1.x tag was filled with spaces
254 * instead of zeroes, then the year field contains garbages! */
256 while (isdigit(*tmp_str)) tmp_str++;
258 /* End of fix for id3lib 3.7.x */
260 local__strip(string);
261 tag->year_recorded = strdup(string);
262 tag->year_performed = strdup(string);
268 /*************************
269 * Track and Total Track *
270 *************************/
271 if(0 != (id3_frame = ID3Tag_FindFrameWithID(id3_tag, ID3FID_TRACKNUM))) {
272 if(0 != (id3_field = ID3Frame_GetField(id3_frame, ID3FN_TEXT))) {
273 if((num_chars = local__ID3Field_GetASCII_wrapper(id3_field, string, ID3V2_MAX_STRING_LEN, field_num)) > 0 && string != NULL) {
274 local__strip(string);
276 string1 = strchr(string, '/');
277 if (NUMBER_TRACK_FORMATED) {
279 /* Just to have numbers like this : '01', '05', '12', ... */
280 tag->tracks_in_album = malloc(64);
281 sprintf(tag->tracks_in_album, "%.2d", atoi(string1+1));
284 /* Just to have numbers like this : '01', '05', '12', ... */
285 tag->track_number = malloc(64);
286 sprintf(tag->track_number, "%.2d", atoi(string));
290 tag->tracks_in_album = strdup(string1+1);
293 tag->track_number = strdup(string);
303 if(0 != (id3_frame = ID3Tag_FindFrameWithID(id3_tag, ID3FID_CONTENTTYPE))) {
304 if(0 != (id3_field = ID3Frame_GetField(id3_frame, ID3FN_TEXT))) {
306 * We manipulate only the name of the genre
308 if((num_chars = local__ID3Field_GetASCII_wrapper(id3_field, string, ID3V2_MAX_STRING_LEN, field_num)) > 0 && string != NULL) {
311 local__strip(string);
313 if((string[0]=='(') && (tmp=strchr(string, ')')) && (strlen((tmp+1))>0)) {
314 /* Convert a genre written as '(3)Dance' into 'Dance' */
315 tag->genre = strdup(tmp+1);
318 else if((string[0]=='(') && (tmp=strchr(string, ')'))) {
319 /* Convert a genre written as '(3)' into 'Dance' */
321 tag->genre = strdup(local__genre_to_string((unsigned)atoi(string+1)));
325 /* Genre is already written as 'Dance' */
326 tag->genre = strdup(string);
336 if(0 != (id3_frame = ID3Tag_FindFrameWithID(id3_tag, ID3FID_COMMENT))) {
337 if(0 != (id3_field = ID3Frame_GetField(id3_frame, ID3FN_TEXT))) {
338 if((num_chars = local__ID3Field_GetASCII_wrapper(id3_field, string, ID3V2_MAX_STRING_LEN, field_num)) > 0 && string != NULL) {
339 local__strip(string);
340 tag->comment = strdup(string);
344 if(0 != (id3_field = ID3Frame_GetField(id3_frame, ID3FN_DESCRIPTION))) {
345 char *comment1 = calloc(MAX_STRING_LEN+1);
346 num_chars = ID3Field_GetASCII(id3_field, comment1, MAX_STRING_LEN, Item_Num);
349 if(0 != (id3_field = ID3Frame_GetField(id3_frame, ID3FN_LANGUAGE))) {
350 char *comment2 = calloc(MAX_STRING_LEN+1);
351 num_chars = ID3Field_GetASCII(id3_field, comment2, MAX_STRING_LEN, Item_Num);
358 /* Free allocated data */
359 ID3Tag_Delete(id3_tag);
364 #endif /* ifdef FLAC__HAS_ID3LIB */
366 FLAC__bool FLAC_plugin__id3v2_tag_get(const char *filename, FLAC_Plugin__CanonicalTag *tag)
368 #ifdef FLAC__HAS_ID3LIB
369 return local__get_tag(filename, tag);
371 (void)filename, (void)tag;