1 /* (PD) 2001 The Bitzi Corporation
2  * Please see file COPYING or http://bitzi.com/publicdomain
3  * for more info.
4  *
5  * This code is based on id3v1.cpp and id3v2.cpp from FreeAmp. EMusic.com
6  * has released this code into the Public Domain.
7  * (Thanks goes to Brett Thomas, VP Engineering Emusic.com)
8  *
9  * $Id: id3.c,v 1.8 2001/08/01 21:21:56 mayhemchaos Exp $
10  */
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <assert.h>
15 #include <errno.h>
16 #ifdef WIN32
17 #include <winsock.h>
18 #else
19 #include <netinet/in.h>
20 #include <sys/param.h>
21 #endif
22 
23 
24 #include "id3.h"
25 #include "bitcollider.h"
26 
27 #define DB printf("%s:%d\n", __FILE__, __LINE__);
28 
29 /* This version 2.2 handling is not completely up to spec -- this code
30    was added to handle parsing of Apples iTunes id3v2.2 tags, which
31    are not id3v2.2 compliant. I haven't seen any other programs use
32    the old id3v2.2 stuff, so this code is tweaked to make sure that
33    iTunes files can be parsed. Yuck.
34 
35    The 2.3 support is up to snuff and should work on all 2.2 compliant
36    id3v2 tags.
37 */
38 const int supportedVersion_v2_2 = 2;
39 const int supportedVersion_v2_3 = 3;
40 const unsigned frameHeaderSize_v2_3 = 10;
41 const unsigned frameHeaderSize_v2_2 = 6;
42 
43 ID3Info *read_ID3v1_tag(const char* fileName, ID3Info *info);
44 ID3Info *read_ID3v2_tag(const char* fileName);
45 
46 typedef struct _ID3Header
47 {
48    char          tag[3];
49    unsigned char versionMajor;
50    unsigned char versionRevision;
51    unsigned char flags;
52    unsigned char size[4];
53 } ID3Header;
54 typedef struct _FrameHeader_v2_3
55 {
56    char           tag[4];
57    unsigned int   size;
58    unsigned short flags;
59 } FrameHeader_v2_3;
60 typedef struct _FrameHeader_v2_2
61 {
62    char           tag[3];
63    unsigned char  size[3];
64 } FrameHeader_v2_2;
65 
66 typedef struct id3v1_0
67 {
68     char id[3];
69     char title[30];
70     char artist[30];
71     char album[30];
72     char year[4];
73     char comment[30];
74     unsigned char genre;
75 
76 } id3v1_0;
77 
78 typedef struct id3v1_1
79 {
80     char id[3];
81     char title[30];
82     char artist[30];
83     char album[30];
84     char year[4];
85     char comment[28];
86     char zero;
87     char track;
88     unsigned char genre;
89 } id3v1_1;
90 
91 typedef struct id3v1 {
92     union {
93         struct id3v1_0 v1_0;
94         struct id3v1_1 v1_1;
95     } id3;
96 } id3v1;
97 
98 #define v1_0 id3.v1_0
99 #define v1_1 id3.v1_1
100 
101 static char *genreList[] =
102 {
103      "Blues",
104      "Classic Rock",
105      "Country",
106      "Dance",
107      "Disco",
108      "Funk",
109      "Grunge",
110      "Hip-Hop",
111      "Jazz",
112      "Metal",
113      "New Age",
114      "Oldies",
115      "Other",
116      "Pop",
117      "R&B",
118      "Rap",
119      "Reggae",
120      "Rock",
121      "Techno",
122      "Industrial",
123      "Alternative",
124      "Ska",
125      "Death Metal",
126      "Pranks",
127      "Soundtrack",
128      "Euro-Techno",
129      "Ambient",
130      "Trip-Hop",
131      "Vocal",
132      "Jazz+Funk",
133      "Fusion",
134      "Trance",
135      "Classical",
136      "Instrumental",
137      "Acid",
138      "House",
139      "Game",
140      "Sound Clip",
141      "Gospel",
142      "Noise",
143      "AlternRock",
144      "Bass",
145      "Soul",
146      "Punk",
147      "Space",
148      "Meditative",
149      "Instrumental Pop",
150      "Instrumental Rock",
151      "Ethnic",
152      "Gothic",
153      "Darkwave",
154      "Techno-Industrial",
155      "Electronic",
156      "Pop-Folk",
157      "Eurodance",
158      "Dream",
159      "Southern Rock",
160      "Comedy",
161      "Cult",
162      "Gangsta",
163      "Top 40",
164      "Christian Rap",
165      "Pop/Funk",
166      "Jungle",
167      "Native American",
168      "Cabaret",
169      "New Wave",
170      "Psychadelic",
171      "Rave",
172      "Showtunes",
173      "Trailer",
174      "Lo-Fi",
175      "Tribal",
176      "Acid Punk",
177      "Acid Jazz",
178      "Polka",
179      "Retro",
180      "Musical",
181      "Rock & Roll",
182      "Hard Rock",
183      "Folk",
184      "Folk-Rock",
185      "National Folk",
186      "Swing",
187      "Fast Fusion",
188      "Bebob",
189      "Latin",
190      "Revival",
191      "Celtic",
192      "Bluegrass",
193      "Avantgarde",
194      "Gothic Rock",
195      "Progressive Rock",
196      "Psychedelic Rock",
197      "Symphonic Rock",
198      "Slow Rock",
199      "Big Band",
200      "Chorus",
201      "Easy Listening",
202      "Acoustic",
203      "Humour",
204      "Speech",
205      "Chanson",
206      "Opera",
207      "Chamber Music",
208      "Sonata",
209      "Symphony",
210      "Booty Bass",
211      "Primus",
212      "Porn Groove",
213      "Satire",
214      "Slow Jam",
215      "Club",
216      "Tango",
217      "Samba",
218      "Folklore",
219      "Ballad",
220      "Power Ballad",
221      "Rhythmic Soul",
222      "Freestyle",
223      "Duet",
224      "Punk Rock",
225      "Drum Solo",
226      "Acapella",
227      "Euro-House",
228      "Dance Hall",
229      "Goa",
230      "Drum & Bass",
231      "Club-House",
232      "Hardcore",
233      "Terror",
234      "Indie",
235      "BritPop",
236      "Negerpunk",
237      "Polsk Punk",
238      "Beat",
239      "Christian Gangsta",
240      "Heavy Metal",
241      "Black Metal",
242      "Crossover",
243      "Contemporary C",
244      "Christian Rock",
245      "Merengue",
246      "Salsa",
247      "Thrash Metal",
248      "Anime",
249      "JPop",
250      "SynthPop",
251      "\0"
252 };
253 
delete_ID3_tag(ID3Info * info)254 void delete_ID3_tag(ID3Info *info)
255 {
256     if (!info)
257        return;
258 
259     if (info->artist)
260        free(info->artist);
261     if (info->album)
262        free(info->album);
263     if (info->title)
264        free(info->title);
265     if (info->genre)
266        free(info->genre);
267     if (info->year)
268        free(info->year);
269     if (info->encoder)
270        free(info->encoder);
271     if (info->tracknumber)
272        free(info->tracknumber);
273 
274     free(info);
275 }
276 
handle_frame_v2_3(char * tag,char * frameData,ID3Info * info)277 void handle_frame_v2_3(char *tag, char *frameData, ID3Info *info)
278 {
279     char tagName[5];
280 
281     if (frameData == NULL || strlen(frameData) == 0)
282         return;
283 
284     strncpy(tagName, tag, 4);
285     tagName[4] = 0;
286 
287     if (strcmp(tagName, "TIT2") == 0)
288         info->title = strdup(frameData);
289 
290     if (strcmp(tagName, "TALB") == 0)
291         info->album = strdup(frameData);
292 
293     if (strcmp(tagName, "TPE1") == 0)
294         info->artist = strdup(frameData);
295 
296     if (strcmp(tagName, "TYER") == 0)
297         info->year = strdup(frameData);
298 
299     if (strcmp(tagName, "TCON") == 0)
300     {
301         int i;
302 
303         for(i = 0;; i++)
304         {
305            if (*genreList[i] == 0)
306               break;
307 
308            if (strcasecmp(genreList[i], frameData) == 0)
309            {
310               info->genre = malloc(10);
311               sprintf(info->genre, "%d", i);
312            }
313         }
314     }
315 
316     if (strcmp(tagName, "TRCK") == 0)
317         info->tracknumber = strdup(frameData);
318 
319     if (strcmp(tagName, "TSSE") == 0)
320         info->encoder = strdup(frameData);
321 }
322 
handle_frame_v2_2(char * tag,char * frameData,ID3Info * info)323 void handle_frame_v2_2(char *tag, char *frameData, ID3Info *info)
324 {
325     char tagName[5];
326 
327     if (frameData == NULL || strlen(frameData) == 0)
328         return;
329 
330     strncpy(tagName, tag, 3);
331     tagName[3] = 0;
332 
333     if (strcmp(tagName, "TT2") == 0)
334         info->title = strdup(frameData);
335 
336     if (strcmp(tagName, "TAL") == 0)
337         info->album = strdup(frameData);
338 
339     if (strcmp(tagName, "TP1") == 0)
340         info->artist = strdup(frameData);
341 
342     if (strcmp(tagName, "TYE") == 0)
343         info->year = strdup(frameData);
344 
345     if (strcmp(tagName, "TSI") == 0)
346         info->genre = strdup(frameData);
347 
348     if (strcmp(tagName, "TRK") == 0)
349     {
350         info->tracknumber = strdup(frameData);
351         sscanf(frameData, "%[0-9]", info->tracknumber);
352     }
353 
354     if (strcmp(tagName, "TSS") == 0)
355         info->encoder = strdup(frameData);
356 }
357 
read_ID3_tag(const char * fileName)358 ID3Info *read_ID3_tag(const char *fileName)
359 {
360     return read_ID3v1_tag(fileName, read_ID3v2_tag(fileName));
361 }
362 
read_ID3v2_tag(const char * fileName)363 ID3Info *read_ID3v2_tag(const char* fileName)
364 {
365     FILE            *inFile;
366     char             buffer[1024], *frameData;
367     ID3Header        head;
368     FrameHeader_v2_3 frame_v2_3;
369     FrameHeader_v2_2 frame_v2_2;
370     ID3Info         *info = NULL;
371     int              ret;
372     unsigned int     size, frameSize = 0, fileSize = 0;
373 
374     inFile = fopen(fileName, "rb");
375     if (inFile == NULL)
376         return NULL;
377 
378 	ret = fseek(inFile, 0, SEEK_END);
379 	fileSize = ftell(inFile);
380 	fseek(inFile, 0, SEEK_SET);
381 
382     ret = fread(&head, 1, sizeof(ID3Header), inFile);
383     if (ret != sizeof(ID3Header))
384     {
385         fclose(inFile);
386         return NULL;
387     }
388 
389     if (strncmp(head.tag, "ID3", 3))
390     {
391         fclose(inFile);
392         return NULL;
393     }
394 
395     if (head.versionMajor != supportedVersion_v2_2 &&
396         head.versionMajor != supportedVersion_v2_3)
397     {
398         fclose(inFile);
399         return NULL;
400     }
401     size = ( head.size[3] & 0x7F       ) |
402            ((head.size[2] & 0x7F) << 7 ) |
403            ((head.size[1] & 0x7F) << 14) |
404            ((head.size[0] & 0x7F) << 21);
405 
406 	// Check to make sure that the size we calculate are sane!
407 	if (size > fileSize)
408 	{
409         fclose(inFile);
410         return NULL;
411 	}
412 
413     if (head.flags & (1 << 6))
414     {
415         unsigned extHeaderSize;
416 
417         if (fread(&extHeaderSize, 1, sizeof(int), inFile) != sizeof(int))
418         {
419             fclose(inFile);
420             return NULL;
421         }
422         if (fread(buffer, 1, extHeaderSize, inFile) != extHeaderSize)
423         {
424             fclose(inFile);
425             return NULL;
426         }
427     }
428 
429     info = malloc(sizeof(ID3Info));
430     memset(info, 0, sizeof(ID3Info));
431     for(; size > 0;)
432     {
433         if (head.versionMajor == supportedVersion_v2_2)
434         {
435             if (fread(&frame_v2_2, 1, frameHeaderSize_v2_2, inFile) !=
436                 frameHeaderSize_v2_2)
437             {
438                 free(info);
439                 fclose(inFile);
440                 return NULL;
441             }
442             ((unsigned char *)&frameSize)[0] = 0;
443             ((unsigned char *)&frameSize)[1] = frame_v2_2.size[0];
444             ((unsigned char *)&frameSize)[2] = frame_v2_2.size[1];
445             ((unsigned char *)&frameSize)[3] = frame_v2_2.size[2];
446             frameSize = ntohl(frameSize);
447         }
448         if (head.versionMajor == supportedVersion_v2_3)
449         {
450             if (fread(&frame_v2_3, 1, frameHeaderSize_v2_3, inFile) !=
451                 frameHeaderSize_v2_3)
452             {
453                 free(info);
454                 fclose(inFile);
455                 return NULL;
456             }
457             frameSize = ntohl(frame_v2_3.size);
458         }
459 
460 		// If the frame size is funky, skip it and move on
461         if (frameSize == 0 || frameSize > fileSize)
462             break;
463 
464         frameData = malloc(frameSize + 1);
465         if (fread(frameData, 1, frameSize, inFile) != frameSize)
466         {
467             free(info);
468             free(frameData);
469             fclose(inFile);
470             return NULL;
471         }
472         frameData[frameSize] = 0;
473         if (head.versionMajor == supportedVersion_v2_2)
474             handle_frame_v2_2(frame_v2_2.tag, &frameData[1], info);
475         else
476             handle_frame_v2_3(frame_v2_3.tag, &frameData[1], info);
477 
478         free(frameData);
479         size -= (head.versionMajor == supportedVersion_v2_3 ?
480                 frameHeaderSize_v2_3 : frameHeaderSize_v2_2) + frameSize;
481     }
482 
483     fclose(inFile);
484 
485     return info;
486 }
487 
remove_trailing_spaces(char * string)488 void remove_trailing_spaces(char* string)
489 {
490 	char* cp = &(string[strlen(string)]);
491 
492 	do
493     {
494 	    *cp = '\0';
495 	    cp--;
496 	}while ((*cp == ' ') && (cp >= string));
497 }
498 
read_ID3v1_tag(const char * fileName,ID3Info * info)499 ID3Info *read_ID3v1_tag(const char* fileName, ID3Info *info)
500 {
501     id3v1  id3;
502     FILE  *fp;
503     char   buffer[31];
504 
505     fp = fopen(fileName, "rb");
506     if (fp == NULL)
507         return info;
508 
509     if (fseek(fp, -128, SEEK_END))
510     {
511         fclose(fp);
512         return info;
513     }
514 
515     if (fread(&id3, 1, 128, fp) != 128)
516     {
517         fclose(fp);
518         return info;
519     }
520 
521     if(strncmp(id3.v1_0.id, "TAG", 3))
522     {
523         fclose(fp);
524         return info;
525     }
526 
527     if (info == NULL)
528     {
529         info = malloc(sizeof(ID3Info));
530         memset(info, 0, sizeof(ID3Info));
531     }
532 
533     strncpy(buffer, id3.v1_0.artist, 30);
534     buffer[30] = 0;
535     remove_trailing_spaces(buffer);
536     if (strlen(buffer) && info->artist == NULL)
537         info->artist = strdup(buffer);
538 
539     strncpy(buffer, id3.v1_0.album, 30);
540     buffer[30] = 0;
541     remove_trailing_spaces(buffer);
542     if (strlen(buffer) && info->album == NULL)
543         info->album = strdup(buffer);
544 
545     strncpy(buffer, id3.v1_0.title, 30);
546     buffer[30] = 0;
547     remove_trailing_spaces(buffer);
548     if (strlen(buffer) && info->title == NULL)
549         info->title = strdup(buffer);
550 
551     strncpy(buffer, id3.v1_0.year,4);
552     buffer[4] = 0;
553     remove_trailing_spaces(buffer);
554     if (strlen(buffer) && info->year == NULL)
555     {
556         int check;
557 
558         if (sscanf(buffer, "%d", &check) == 1 && check >= 1000 && check < 3000)
559            info->year = strdup(buffer);
560     }
561 
562     if( id3.v1_1.zero == 0x00 && id3.v1_1.track != 0x00)
563     {
564         sprintf(buffer, "%d", id3.v1_1.track);
565         if (strlen(buffer) && info->tracknumber == NULL)
566             info->tracknumber = strdup(buffer);
567     }
568 
569     if (id3.v1_0.genre != 255)
570     {
571         sprintf(buffer, "%u", (unsigned int)id3.v1_0.genre);
572         if (strlen(buffer) && info->genre == NULL)
573            info->genre = strdup(buffer);
574     }
575 
576     fclose(fp);
577     return info;
578 }
579 
580