1 /* id3.c
2  *
3  * Copyright (c) 1998-2004  Mike Oliphant <grip@nostatic.org>
4  *
5  *   http://www.nostatic.org/grip
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
20  * USA
21  */
22 
23 #include <glib/gi18n.h>
24 #include <stdio.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include "grip_id3.h"
28 
29 static void ID3Put(char *dest,char *src,int len,char *encoding);
30 
31 /* this array contains string representations of all known ID3 tags */
32 /* taken from mp3id3 in the mp3tools 0.7 package */
33 
34 ID3Genre id3_genres[] = {
35   {"Alternative",20},
36   {"Blues",0},
37   {"Classical",32},
38   {"Country",2},
39   {"Folk",80},
40   {"Jazz",8},
41   {"Metal",9},
42   {"Pop",13},
43   {"Rap",15},
44   {"Reggae",16},
45   {"Rock",17},
46   {"Other",12},
47   {"Abstract",148},
48   {"Acapella",123},
49   {"Acid Jazz",74},
50   {"Acid Punk",73},
51   {"Acid",34},
52   {"Acoustic",99},
53   {"AlternRock",40},
54   {"Ambient",26},
55   {"Anime",145},
56   {"Art Rock",149},
57   {"Audio Theatre",184},
58   {"Audiobook",183},
59   {"Avantgarde",90},
60   {"Ballad",116},
61   {"Baroque",150},
62   {"Bass",41},
63   {"Beat",135},
64   {"Bebob",85},
65   {"Bhangra",151},
66   {"Big Band",96},
67   {"Big Beat",152},
68   {"Black Metal",138},
69   {"Bluegrass",89},
70   {"Booty Bass",107},
71   {"Breakbeat",153},
72   {"BritPop",132},
73   {"Cabaret",65},
74   {"Celtic",88},
75   {"Chamber Music",104},
76   {"Chanson",102},
77   {"Chillout",154},
78   {"Chorus",97},
79   {"Christian Gangsta Rap",136},
80   {"Christian Rap",61},
81   {"Christian Rock",141},
82   {"Classic Rock",1},
83   {"Club",112},
84   {"Club-House",128},
85   {"Comedy",57},
86   {"Contemporary Christian",140},
87   {"Crossover",139},
88   {"Cult",58},
89   {"Dance Hall",125},
90   {"Dance",3},
91   {"Darkwave",50},
92   {"Death Metal",22},
93   {"Disco",4},
94   {"Downtempo",155},
95   {"Dream",55},
96   {"Drum & Bass",127},
97   {"Drum Solo",122},
98   {"Dub",156},
99   {"Dubstep",189},
100   {"Duet",120},
101   {"EBM",157},
102   {"Easy Listening",98},
103   {"Eclectic",158},
104   {"Electro",159},
105   {"Electroclash",160},
106   {"Electronic",52},
107   {"Emo",161},
108   {"Ethnic",48},
109   {"Euro-Techno",25},
110   {"Euro-house",124},
111   {"Eurodance",54},
112   {"Experimental",162},
113   {"Fast Fusion",84},
114   {"Folk/Rock",81},
115   {"Folklore",115},
116   {"Freestyle",119},
117   {"Funk",5},
118   {"Fusion",30},
119   {"G-Funk",188},
120   {"Game",36},
121   {"Gangsta",59},
122   {"Garage",163},
123   {"Garage Rock",190},
124   {"Global",164},
125   {"Goa",126},
126   {"Gospel",38},
127   {"Gothic Rock",91},
128   {"Gothic",49},
129   {"Grunge",6},
130   {"Hard Rock",79},
131   {"Hardcore",129},
132   {"Heavy Metal",137},
133   {"Hip-Hop",7},
134   {"House",35},
135   {"Humour",100},
136   {"IDM",165},
137   {"Illbient",166},
138   {"Indie Rock",187},
139   {"Indie",131},
140   {"Industrial",19},
141   {"Industro-Goth",167},
142   {"Instrumental Pop",46},
143   {"Instrumental Rock",47},
144   {"Instrumental",33},
145   {"JPop",146},
146   {"Jam Band",168},
147   {"Jazz+Funk",29},
148   {"Jungle",63},
149   {"Krautrock",169},
150   {"Latin",86},
151   {"Leftfield",170},
152   {"Lo-Fi",71},
153   {"Lounge",171},
154   {"Math Rock",172},
155   {"Meditative",45},
156   {"Merengue",142},
157   {"Musical",77},
158   {"National Folk",82},
159   {"Native American",64},
160   {"Negerpunk",133},
161   {"Neoclassical",182},
162   {"Neue Deutsche Welle",185},
163   {"New Age",10},
164   {"New Romantic",173},
165   {"New Wave",66},
166   {"Noise",39},
167   {"Nu-Breakz",174},
168   {"Oldies",11},
169   {"Opera",103},
170   {"Podcast",186},
171   {"Polka",75},
172   {"Polsk Punk",134},
173   {"Pop-Folk",53},
174   {"Pop/Funk",62},
175   {"Porn Groove",109},
176   {"Post-Punk",175},
177   {"Post-Rock",176},
178   {"Power Ballad",117},
179   {"Pranks",23},
180   {"Primus",108},
181   {"Progressive Rock",92},
182   {"Psybient",191},
183   {"Psychedelic",67},
184   {"Psychedelic Rock",93},
185   {"Psytrance",177},
186   {"Punk Rock",121},
187   {"Punk",43},
188   {"R&B",14},
189   {"Rave",68},
190   {"Reggaestep",192},
191   {"Retro",76},
192   {"Revival",87},
193   {"Rhythmic Soul",118},
194   {"Rock & Roll",78},
195   {"Salsa",143},
196   {"Samba",114},
197   {"Satire",110},
198   {"Shoegaze",178},
199   {"Showtunes",69},
200   {"Ska",21},
201   {"Slow Jam",111},
202   {"Slow Rock",95},
203   {"Sonata",105},
204   {"Soul",42},
205   {"Sound Clip",37},
206   {"Soundtrack",24},
207   {"Southern Rock",56},
208   {"Space Rock",179},
209   {"Space",44},
210   {"Speech",101},
211   {"Swing",83},
212   {"Symphonic Rock",94},
213   {"Symphony",106},
214   {"SynthPop",147},
215   {"Tango",113},
216   {"Techno",18},
217   {"Techno-Industrial",51},
218   {"Terror",130},
219   {"Thrash Metal",144},
220   {"Top 40",60},
221   {"Trailer",70},
222   {"Trance",31},
223   {"Tribal",72},
224   {"Trip-Hop",27},
225   {"Trop Rock",180},
226   {"Vocal",28},
227   {"World Music",181},
228   {NULL,193}
229 };
230 
231 /* This array maps CDDB_ genre numbers to closest id3 genre */
232 int cddb_2_id3[] =
233 {
234   12,         /* CDDB_UNKNOWN */
235   0,          /* CDDB_BLUES */
236   32,         /* CDDB_CLASSICAL */
237   2,          /* CDDB_COUNTRY */
238   12,         /* CDDB_DATA */
239   80,         /* CDDB_FOLK */
240   8,          /* CDDB_JAZZ */
241   12,         /* CDDB_MISC */
242   10,         /* CDDB_NEWAGE */
243   16,         /* CDDB_REGGAE */
244   17,         /* CDDB_ROCK */
245   24,         /* CDDB_SOUNDTRACK */
246 };
247 
248 /* ID3 tag structure */
249 
250 typedef struct _id3_tag {
251   char tag[3];
252   char title[30];
253   char artist[30];
254   char album[30];
255   char year[4];
256   char comment[28];
257   unsigned char id3v1_1_mark;
258   unsigned char tracknum;
259   unsigned char genre;
260 } ID3v1Tag;
261 
262 #ifdef HAVE_ID3V2
263 
264 #include <id3.h>
265 
266 /* Things you might want to mess with. Surprisingly, the code will probably
267    cope with you just messing with this section. */
268 #define NUM_FRAMES 7
269 static ID3_FrameID frameids[ NUM_FRAMES ] = {
270     ID3FID_TITLE, ID3FID_LEADARTIST, ID3FID_ALBUM, ID3FID_YEAR,
271     ID3FID_COMMENT, ID3FID_CONTENTTYPE, ID3FID_TRACKNUM
272 };
273 /* End of the section you're supposed to mess with */
274 
ID3v2TagFile(char * filename,char * title,char * artist,char * album,char * year,char * comment,unsigned char genre,unsigned char tracknum,char * id3v2_encoding)275 gboolean ID3v2TagFile(char *filename, char *title, char *artist, char *album,
276 		      char *year, char *comment, unsigned char genre, unsigned
277 		      char tracknum,char *id3v2_encoding)
278 {
279   ID3Tag *tag;
280   ID3Field *field;
281   ID3Frame *frames[ NUM_FRAMES ];
282   int i;
283   gboolean retval = TRUE;
284   mode_t mask;
285   char *conv_str;
286   gsize rb,wb;
287 
288   tag = ID3Tag_New();
289 
290   if(tag) {
291     ID3Tag_Link(tag,filename);
292     /* GRR. No error. */
293 
294     for ( i = 0; i < NUM_FRAMES; i++ ) {
295       frames[ i ] = ID3Frame_NewID( frameids[ i ] );
296 
297       if ( frames[ i ] ) {
298 	char *c_data = NULL;
299 	char gen[ 6 ] = "(   )"; /* max unsigned char: 255 */
300 	char trk[ 4 ] = "  "; /* max CDDA tracks: 99 */
301 
302 	switch( frameids[ i ] ) {
303 	case ID3FID_TITLE:
304 	  c_data = title;
305 	  break;
306 
307 	case ID3FID_LEADARTIST:
308 	  c_data = artist;
309 	  break;
310 
311 	case ID3FID_ALBUM:
312 	  c_data = album;
313 	  break;
314 
315 	case ID3FID_YEAR:
316 	  c_data = year;
317 	  break;
318 
319 	case ID3FID_COMMENT:
320 	  c_data = comment;
321 	  break;
322 
323 	case ID3FID_CONTENTTYPE:
324 	  c_data = gen;
325 	  snprintf( gen, 6, "(%d)", genre );
326 	  break;
327 
328 	case ID3FID_TRACKNUM:
329 	  c_data = trk;
330 	  snprintf( trk, 4, "%d", tracknum );
331 	  break;
332 
333 	default:
334 	  /* Doh! */
335 	  g_printerr(_("unknown ID3 field\n"));
336 	  break;
337 	}
338 
339 	if(c_data != NULL) {
340 	  field = ID3Frame_GetField( frames[i], ID3FN_TEXT );
341 
342 	  if(field) {
343             /*            if(!strcasecmp(id3v2_encoding,"utf-8")) {
344 	      ID3Field_SetUNICODE(field,(unicode_t *)c_data);
345 	    }
346 	    else {
347             */
348 
349             /* Always encode pretending it is ascii */
350 
351             conv_str=g_convert_with_fallback(c_data,strlen(c_data),id3v2_encoding,
352                                "utf-8",NULL,&rb,&wb,NULL);
353 
354             if(!conv_str) {
355               printf("***convert failed\n");
356 
357               conv_str=strdup(c_data);
358             }
359 
360             ID3Field_SetASCII(field,conv_str);
361 
362             g_free(conv_str);
363 	  } else {
364 	    retval = FALSE;
365 	  }
366 	}
367       } else { /* Frame->new() failed */
368 	retval = FALSE;
369 	break;
370       }
371     }
372     if ( retval != FALSE ) {
373       /* It would be really nice if I could have done something like
374 	 ID3Tag_AddFrames( tag, frames, NUM_FRAMES ), but the
375 	 prototypes work against me one way or another. So, this will
376 	 do instead. */
377       for ( i = 0; i < NUM_FRAMES; i++ ) {
378 	/* Strictly speaking I should look for existing tags and
379 	   delete them, but hey. We're making fresh mp3 files, right?
380 	*/
381 	ID3Tag_AddFrame( tag, frames[ i ] );
382       }
383     }
384 
385     if(ID3Tag_UpdateByTagType(tag,ID3TT_ID3V2) != ID3E_NoError ) {
386       retval = FALSE;
387     }
388 
389     ID3Tag_Delete( tag );
390 
391     /* Reset permissions based on users umask to work around a bug in the
392        id3v2 library */
393     mask = umask(0);
394     umask(mask);
395     chmod(filename, 0666 & ~mask);
396 
397   } else { /* Tag -> new() failed */
398     retval = FALSE;
399   }
400 
401   return retval;
402 }
403 
404 #endif /* HAVE_ID3V2 */
405 
406 /* Add an ID3v1 tag to a file */
407 
ID3v1TagFile(char * filename,char * title,char * artist,char * album,char * year,char * comment,unsigned char genre,unsigned char tracknum,char * id3_encoding)408 gboolean ID3v1TagFile(char *filename,char *title,char *artist,char *album,
409 		      char *year,char *comment,unsigned char genre,
410 		      unsigned char tracknum, char *id3_encoding)
411 {
412   FILE *fp;
413   ID3v1Tag tag;
414 
415   fp=fopen(filename,"a");
416 
417   ID3Put(tag.tag,"TAG",3,id3_encoding);
418 
419   ID3Put(tag.title,title,30,id3_encoding);
420 
421   ID3Put(tag.artist,artist,30,id3_encoding);
422 
423   ID3Put(tag.album,album,30,id3_encoding);
424 
425   ID3Put(tag.year,year,4,NULL);
426 
427   ID3Put(tag.comment,comment,28,id3_encoding);
428 
429   tag.id3v1_1_mark = 0U;
430 
431   tag.tracknum=tracknum;
432   tag.genre=genre;
433 
434   fwrite(&tag,sizeof(ID3v1Tag),1,fp);
435 
436   fclose(fp);
437 
438   return TRUE;
439 }
440 
441 /* Copy a string padding with zeros */
442 
ID3Put(char * dest,char * src,int len,char * encoding)443 static void ID3Put(char *dest,char *src,int len,char *encoding)
444 {
445   int pos;
446   int srclen;
447   char *conv_str;
448   gsize rb,wb;
449 
450   if(encoding&&strcasecmp(encoding,"utf-8")) {
451     conv_str=g_convert_with_fallback(src,strlen(src),encoding,"utf-8",NULL,&rb,&wb,NULL);
452 
453     if(!conv_str) conv_str=strdup(src);
454   }
455   else conv_str=strdup(src);
456 
457   srclen=strlen(conv_str);
458 
459   for(pos=0;pos<len;pos++) {
460     if(pos<srclen) dest[pos]=conv_str[pos];
461     else dest[pos]=0;
462   }
463 
464   g_free(conv_str);
465 }
466 
ID3GenreString(int genre)467 char *ID3GenreString(int genre)
468 {
469   int num;
470 
471   for(num=0;id3_genres[num].name;num++) {
472     if(id3_genres[num].num==genre) return id3_genres[num].name;
473   }
474 
475   return NULL;
476 }
477 
ID3GenreByNum(int num)478 ID3Genre *ID3GenreByNum(int num)
479 {
480   if(!id3_genres[num].name) return NULL;
481 
482   return &(id3_genres[num]);
483 }
484 
485 /* Return the id3 genre id from the text name */
ID3GenreValue(char * genre)486 int ID3GenreValue(char *genre)
487 {
488   int pos;
489 
490   for(pos=0;id3_genres[pos].name;pos++)
491     if(!strcasecmp(genre,id3_genres[pos].name))
492       return id3_genres[pos].num;
493 
494   return 12;
495 }
496 
ID3GenrePos(int genre)497 int ID3GenrePos(int genre)
498 {
499   int num;
500 
501   for(num=0;id3_genres[num].name;num++) {
502     if(id3_genres[num].num==genre) return num;
503   }
504 
505   return 0;
506 }
507 
DiscDB2ID3(int discdb_genre)508 int DiscDB2ID3(int discdb_genre)
509 {
510   return cddb_2_id3[discdb_genre];
511 }
512 
ID32DiscDB(int id3_genre)513 int ID32DiscDB(int id3_genre)
514 {
515   int discdb;
516 
517   for(discdb=0;discdb<12;discdb++) {
518     if(cddb_2_id3[discdb]==id3_genre) return discdb;
519   }
520 
521   return 12;
522 }
523