1 /**
2  *   (c) 2003-2006 Nathan Hjelm <hjelmn@users.sourceforge.net>
3  *   v1.1 id3.c
4  *
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.
9  *
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.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program; if not, write to the Free Software
17  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  **/
19 
20 #include <stdlib.h>
21 #include <stdio.h>
22 
23 #include <string.h>
24 #include <errno.h>
25 
26 #include <sys/ioctl.h>
27 #include <sys/types.h>
28 #include <sys/uio.h>
29 #include <sys/stat.h>
30 
31 #include <time.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 
35 #include "rioi.h"
36 #include "genre.h"
37 
38 #ifdef HAVE_LIBGEN_H
39 #include <libgen.h>
40 #endif
41 
42 #define ID3FLAG_EXTENDED 0x40
43 #define ID3FLAG_FOOTER   0x10
44 
45                        /* v2.2 v2.3 */
46 char *ID3_TITLE[2]   = {"TT2", "TIT2"};
47 char *ID3_ARTIST[2]  = {"TP1", "TPE1"};
48 char *ID3_ALBUM[2]   = {"TAL", "TALB"};
49 char *ID3_TRACK[2]   = {"TRK", "TRCK"};
50 char *ID3_YEAR[2]    = {"TYE", "TYER"};
51 char *ID3_GENRE[2]   = {"TCO", "TCON"};
52 char *ID3_ENCODER[2] = {"TEN", "TENC"};
53 char *ID3_COMMENT[2] = {"COM", "COMM"};
54 char *ID3_BPM[2]     = {"TBP", "TBPM"};
55 char *ID3_YEARNEW[2] = {"TYE", "TDRC"};
56 char *ID3_DISC[2]    = {"TPA", "TPOS"};
57 char *ID3_ARTWORK[2] = {"PIC", "APIC"};
58 
59 static int find_id3 (int version, FILE *fh, unsigned char *tag_data, int *tag_datalen,
60 		     int *id3_len, int *major_version);
61 static void one_pass_parse_id3 (FILE *fh, unsigned char *tag_data, int tag_datalen, int version,
62                                 int id3v2_majorversion, rio_file_t *mp3_file);
63 static int synchsafe_to_int (unsigned char *buf, int nbytes);
64 
65 static int synchsafe_to_int (unsigned char *buf, int nbytes) {
66   int id3v2_len = 0;
67   int error = 0;
68   int i;
69 
70   for (i = 0 ; i < nbytes ; i++) {
71     id3v2_len <<= 7;
72     id3v2_len += buf[i] & 0x7f;
73     if (buf[i] & 0xf0)
74       error = 1;
75   }
76 
77   if (error) {
78     id3v2_len = 0;
79     for (i = 0 ; i < nbytes ; i++) {
80       id3v2_len <<= 8;
81       id3v2_len += buf[i] & 0xff;
82     }
83   }
84 
85   return id3v2_len;
86 }
87 
88 int id3v2_size (unsigned char data[14]) {
89   int major_version;
90   unsigned char id3v2_flags;
91   int id3v2_len = 0;
92   int id3v2_extendedlen = 0;
93   int head;
94 
95   memcpy (&head, data, 4);
96   head = big32_2_arch32 (head);
97 
98   if ((head & 0xffffff00) == 0x49443300) {
99     major_version = head & 0xff;
100 
101     id3v2_flags = data[5];
102     id3v2_len   = 10 + synchsafe_to_int (&data[6], 4);
103 
104     if (id3v2_flags & ID3FLAG_EXTENDED) {
105       /* Skip extended header */
106       if (major_version != 3)
107 	id3v2_len += synchsafe_to_int (&data[10], 4);
108       else
109 	id3v2_len += big32_2_arch32 (((int *)&data[10])[0]);
110     }
111 
112     /* total length = 10 (header) + extended header length (flag 0x40) + id3v2len + 10 (footer, if present -- flag 0x10) */
113     id3v2_len += (id3v2_flags & ID3FLAG_FOOTER) ? 10 : 0;
114   }
115 
116   return id3v2_len;
117 }
118 
119 /*
120   find_id3 takes in a file descriptor, a pointer to where the tag data is to be put,
121   and a pointer to where the data length is to be put.
122 
123   find_id3 returns:
124     0 for no id3 tags
125     1 for id3v1 tag
126     2 for id3v2 tag
127 
128   The file descriptor is reset to the start of the file on completion.
129 */
130 static int find_id3 (int version, FILE *fh, unsigned char *tag_data, int *tag_datalen,
131 		     int *id3_len, int *major_version) {
132     int head;
133     unsigned char data[10];
134 
135     char id3v2_flags;
136     int  id3v2_len;
137     int  id3v2_extendedlen;
138 
139     fread(&head, 4, 1, fh);
140 
141     head = big32_2_arch32(head);
142 
143     if (version == 2) {
144       /* version 2 */
145       if ((head & 0xffffff00) == 0x49443300) {
146 	fread(data, 1, 10, fh);
147 
148 	*major_version = head & 0xff;
149 
150 	id3v2_flags = data[1];
151 
152 	id3v2_len = *id3_len = synchsafe_to_int (&data[2], 4);
153 
154 	*id3_len += 10; /* total length = id3v2len + 010 + footer (if present) */
155 	*id3_len += (id3v2_flags & 0x10) ? 10 : 0; /* ID3v2 footer */
156 
157 	/* the 6th bit of the flag field being set indicates that an
158 	   extended header is present */
159 	if (id3v2_flags & 0x40) {
160 	  /* Skip extended header */
161 	  id3v2_extendedlen = synchsafe_to_int (&data[6], 4);
162 
163 	  fseek(fh, 0xa + id3v2_extendedlen, SEEK_SET);
164 	  *tag_datalen = id3v2_len - id3v2_extendedlen;
165 	} else {
166 	  /* Skip standard header */
167 	  fseek(fh, 0xa, SEEK_SET);
168 	  *tag_datalen = id3v2_len;
169 	}
170 
171 	return 2;
172       }
173     } else if (version == 1) {
174       fseek(fh, 0, SEEK_SET);
175 
176       /* tag not at beginning? */
177       if ((head & 0xffffff00) != 0x54414700) {
178 	/* maybe end */
179 	fseek(fh, -128, SEEK_END);
180 	fread(&head, 1, 4, fh);
181 	fseek(fh, -128, SEEK_END);
182 
183 	head = big32_2_arch32(head);
184       }
185 
186       /* version 1 */
187       if ((head & 0xffffff00) == 0x54414700) {
188 	fread(tag_data, 1, 128, fh);
189 
190 	return 1;
191       }
192     }
193 
194     /* no id3 found */
195     return 0;
196 }
197 
198 static char *id3v1_string (unsigned char *unclean) {
199   int i;
200   static char buffer[31];
201 
202   memset (buffer, 0, 31);
203 
204   for (i = 0 ; i < 30 && unclean[i] != 0xff ; i++)
205     buffer[i] = unclean[i];
206 
207   for (i = strlen (buffer) - 1 ; i >= 0 && buffer[i] == ' ' ; i--)
208     buffer[i] = '\0';
209 
210   return buffer;
211 }
212 
213 /*
214   parse_id3
215 */
216 static void one_pass_parse_id3 (FILE *fh, unsigned char *tag_data, int tag_datalen, int version,
217 				int id3v2_majorversion, rio_file_t *mp3_file) {
218   int i, j;
219   unsigned char *dstp;
220   char *slash;
221 
222   if (version == 2) {
223     unsigned char *tag_temp;
224     char genre_temp[4];
225     char encoding[11];
226     char identifier[5];
227     int newv = (id3v2_majorversion > 2) ? 1 : 0;
228 
229     memset (identifier, 0, 5);
230 
231     for (i = 0 ; i < tag_datalen ; ) {
232       size_t length = 0;
233 
234       fread (tag_data, 1, (id3v2_majorversion > 2) ? 10 : 6, fh);
235 
236       if (tag_data[0] == 0)
237 	return;
238 
239       memcpy (identifier, tag_data, newv ? 4 : 3);
240 
241       if (id3v2_majorversion > 2) {
242 	/* id3v2.3 does not use synchsafe integers in frame headers. */
243 	if (id3v2_majorversion == 3 || strcmp (identifier, "APIC") == 0 ||
244 	    strcmp (identifier, "COMM") == 0 || strcmp (identifier, "COM ") == 0 ||
245 	    strcmp (identifier, "GEOB")) {
246 	  length = big32_2_arch32(((int *)tag_data)[1]);
247 	} else
248 	  length = synchsafe_to_int (&tag_data[4], 4);
249 
250 	i += 10 + length;
251       } else {
252 	length = (tag_data[3] << 16) | (tag_data[4] << 8) | tag_data[5];
253 
254 	i += 6 + length;
255       }
256 
257       if (length < 0) {
258 	fprintf (stderr, "id3v2 tag data length is < 0... Aborting!\n");
259 	break;
260       } else if (length == 0)
261 	continue;
262 
263       if (length < 2) {
264 	fseek (fh, length, SEEK_CUR);
265 
266 	continue;
267       }
268 
269       if (length > 128) {
270 	fseek (fh, length - 128, SEEK_CUR);
271 	if (strcmp (identifier, "APIC") != 0 &&
272 	    strcmp (identifier, "PIC") != 0)
273 	  length = 128;
274       }
275 
276       memset (tag_data, 0, 128);
277       fread (tag_data, 1, (length < 128) ? length : 128, fh);
278 
279       tag_temp = tag_data;
280 
281       /* Get the tag encoding */
282       switch (*tag_temp) {
283       case 0x00:
284 	sprintf (encoding, "ISO-8859-1");
285 	tag_temp++;
286 	break;
287       case 0x01:
288 	sprintf (encoding, "UTF-16LE");
289 	tag_temp += 3;
290 	break;
291       case 0x03:
292 	sprintf (encoding, "UTF-16BE");
293 	tag_temp++;
294 	break;
295       case 0x04:
296 	sprintf (encoding, "UTF-8");
297 	tag_temp++;
298 	break;
299       default:
300 	sprintf (encoding, "ISO-8859-1");
301       }
302 
303       if (strcmp (identifier, "APIC") != 0 &&
304 	  strcmp (identifier, "PIC") != 0) {
305 	for ( ; length && *tag_temp == '\0' ; tag_temp++, length--);
306 	for ( ; length && *(tag_temp+length-1) == '\0' ; length--);
307 	/*      length--; */
308       }
309 
310       if (length <= 0)
311 	continue;
312 
313       dstp = NULL;
314 
315       if (strcmp (identifier, ID3_TITLE[newv]) == 0) {
316 	dstp = (unsigned char *)mp3_file->title;
317 	length = (length > 63) ? 63 : length;
318       } else if (strcmp (identifier, ID3_ARTIST[newv]) == 0) {
319 	dstp = (unsigned char *)mp3_file->artist;
320 	length = (length > 63) ? 63 : length;
321       } else if (strcmp (identifier, ID3_TRACK[newv]) == 0) {
322 	/* some id3 tags have track/total tracks in the TRK field */
323 	slash = strchr ((char *)tag_temp, '/');
324 
325 	if (slash) *slash = 0;
326 
327 	mp3_file->trackno2 = strtol ((char *)tag_temp, NULL, 10);
328 
329 	if (slash) *slash = '/';
330       } else if (strcmp (identifier, ID3_ALBUM[newv]) == 0) {
331 	dstp = (unsigned char *)mp3_file->album;
332 	length = (length > 63) ? 63 : length;
333       } else if (strcmp (identifier, ID3_YEARNEW[newv]) == 0 ||
334 		 strcmp (identifier, ID3_YEAR[newv]) == 0) {
335 	dstp = mp3_file->year2;
336 	length = (length > 4) ? 4 : length;
337       } else if (strcmp (identifier, ID3_GENRE[newv]) == 0) {
338 	if (tag_temp[0] != '(') {
339 	  dstp = mp3_file->genre2;
340 	  length = (length > 22) ? 22 : length;
341 	} else {
342 	  /* 41 is right parenthesis */
343 	  for (j = 0 ; (*(tag_temp + 1 + j) != 41) ; j++) {
344 	    genre_temp[j] = *(tag_temp + 1 + j);
345 	  }
346 
347 	  genre_temp[j] = 0;
348 
349 	  if (atoi (genre_temp) > 147)
350 	    continue;
351 
352 	  length = (strlen (genre_table[atoi(genre_temp)]) > 22) ? 22 : strlen (genre_table[atoi(genre_temp)]);
353 	  memmove (mp3_file->genre2, genre_table[atoi(genre_temp)], length);
354 	}
355       } else
356 	continue;
357 
358       if (dstp)
359 	strncpy ((char *)dstp, (char *)tag_temp, length);
360     }
361   } else if (version == 1) {
362     char *tmp;
363 
364     if (strlen (mp3_file->title) == 0) {
365       tmp = id3v1_string (&tag_data[3]);
366       strncpy (mp3_file->title, tmp, strlen (tmp));
367     }
368 
369     if (strlen (mp3_file->artist) == 0) {
370       tmp = id3v1_string (&tag_data[33]);
371       strncpy (mp3_file->artist, tmp, strlen (tmp));
372     }
373 
374     if (strlen (mp3_file->album) == 0) {
375       tmp = id3v1_string (&tag_data[63]);
376       strncpy (mp3_file->album, tmp, strlen (tmp));
377     }
378 
379     if (strlen ((char *)mp3_file->genre2) == 0 && tag_data[127] != 0xff)
380       strncpy ((char *)mp3_file->genre2, genre_table[tag_data[127]], strlen (genre_table[tag_data[127]]));
381 
382     if (mp3_file->trackno2 == 0)
383       if (tag_data[126] != 0xff)
384 	mp3_file->trackno2 = tag_data[126];
385   }
386 }
387 
388 int get_id3_info (char *file_name, rio_file_t *mp3_file) {
389   int tag_datalen = 0, id3_len = 0;
390   unsigned char tag_data[128];
391   int version;
392   int id3v2_majorversion;
393   int has_v2 = 0;
394   FILE *fh;
395 
396   if ((fh = fopen (file_name, "r")) == NULL)
397     return errno;
398 
399   /* built-in id3tag reading -- id3v2, id3v1 */
400   if ((version = find_id3(2, fh, tag_data, &tag_datalen, &id3_len, &id3v2_majorversion)) != 0) {
401     one_pass_parse_id3(fh, tag_data, tag_datalen, version, id3v2_majorversion, mp3_file);
402     has_v2 = 1;
403   }
404 
405   /* some mp3's have both tags so check v1 even if v2 is available */
406   if ((version = find_id3(1, fh, tag_data, &tag_datalen, NULL, &id3v2_majorversion)) != 0)
407     one_pass_parse_id3(fh, tag_data, tag_datalen, version, id3v2_majorversion, mp3_file);
408 
409   /* Set the file descriptor at the end of the id3v2 header (if one exists) */
410   fseek (fh, id3_len, SEEK_SET);
411 
412   if (strlen (mp3_file->title) == 0) {
413     char *tfile_name = strdup (file_name);
414     char *tmp = (char *)basename(tfile_name);
415     int i;
416 
417     for (i = strlen(tmp) - 1 ; i > 0 ; i--)
418       if (tmp[i] == '.') {
419 	tmp[i] = 0;
420 	break;
421       }
422 
423     memmove (mp3_file->title, tmp, (strlen(tmp) > 63) ? 63 : strlen(tmp));
424     free (tfile_name);
425   }
426 
427   fclose (fh);
428 
429   if (has_v2)
430     return 2;
431   else
432     return 1;
433 }
434 
435