1 /*
2  *  Copyright (C) 2009-2015  Christian Heckendorf <heckendorfc@gmail.com>
3  *
4  *  This program is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 3 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /* ID3......TTAG.....valueTTG2......value */
19 
intpow(const int base,int exp)20 static int intpow(const int base, int exp){
21 	int ret=base;
22 	if(!exp)return 1;
23 	while(--exp){
24 		ret*=base;
25 	}
26 	return ret;
27 }
28 
getTagData(unsigned char * buf,struct musicInfo * mi)29 int getTagData(unsigned char *buf, struct musicInfo *mi){
30 	int x=0,ret=0,y;
31 	unsigned char *tag=buf+4;
32 	unsigned char *temp=calloc(5,sizeof(char));
33 
34 	for(x=4;*tag==0 && x>0;x--)tag++;
35 	memcpy(temp,tag,x); // Info Size
36 	tag+=(x+3);
37 	y=ret=x;
38 
39 	//for(x=0;ret>0;ret--)x+=(int)pow((double)temp[y-ret],(double)ret); // Prep for strtol
40 	for(x=0;ret>0;ret--)x+=intpow(temp[y-ret],ret); // Should this be x+=temp[y-ret]*intpow(256,ret)? Not that it matters since max field size will be ~200.
41 
42 	if(memcmp("TIT2",buf,4)==0){
43 		memcpy(mi->title,tag,(x-1)>MI_TITLE_SIZE?MI_TITLE_SIZE:x-1);
44 	}
45 	else if(memcmp("TRCK",buf,4)==0){
46 		memcpy(mi->track,tag,(x-1)>MI_TRACK_SIZE?MI_TRACK_SIZE:x-1);
47 	}
48 	else if(memcmp("TALB",buf,4)==0){
49 		memcpy(mi->album,tag,(x-1)>MI_ALBUM_SIZE?MI_ALBUM_SIZE:x-1);
50 	}
51 	else if(memcmp("TYER",buf,4)==0){
52 		memcpy(mi->year,tag,(x-1)>MI_YEAR_SIZE?MI_YEAR_SIZE:x-1);
53 	}
54 	//else if(memcmp("TLEN",buf,4)==0){
55 		//memcpy(mi->length,tag,(x-1)>MI_LENGTH_SIZE?MI_LENGTH_SIZE:x-1);
56 	//}
57 	else if(memcmp("TPE1",buf,4)==0){
58 		memcpy(mi->artist,tag,(x-1)>MI_ARTIST_SIZE?MI_ARTIST_SIZE:x-1);
59 	}
60 	else if(memcmp("\0\0\0\0",buf,4)==0)return -1;
61 
62 	free(temp);
63 	return x+10;
64 }
65 
ID3v2Parse(FILE * ffd,struct musicInfo * mi)66 void ID3v2Parse(FILE *ffd, struct musicInfo *mi){
67 	int ret,total=3000,next=0;
68 	unsigned char buffer[255];
69 	fseek(ffd,next,SEEK_SET);
70 	if(fread(buffer,sizeof(char),10,ffd)<10)return;
71 
72 	next+=10;
73 	do{
74 		fseek(ffd,next,SEEK_SET);
75 		if(fread(buffer,sizeof(char),255,ffd)<255)next=total;
76 		ret=getTagData(buffer,mi);
77 		next+=ret;
78 	}while(ret>0 && next<total);
79 }
80 
ID3v1Parse(FILE * ffd,struct musicInfo * mi)81 void ID3v1Parse(FILE *ffd, struct musicInfo *mi){
82 	int next=-125;
83 	fseek(ffd,next,SEEK_END);
84 	if(fread(mi->title,sizeof(char),30,ffd)<30)return;
85 	next+=30;
86 
87 	fseek(ffd,next,SEEK_END);
88 	if(fread(mi->artist,sizeof(char),30,ffd)<30)return;
89 	next+=30;
90 
91 	fseek(ffd,next,SEEK_END);
92 	if(fread(mi->album,sizeof(char),30,ffd)<30)return;
93 	next+=30;
94 
95 	fseek(ffd,next,SEEK_END);
96 	if(fread(mi->year,sizeof(char),4,ffd)<4)return;
97 	next+=4;
98 }
99 
mp3Length(FILE * ffd,int quick)100 int mp3Length(FILE *ffd, int quick){
101 	int len;
102 	long rate;
103 	mpg123_init();
104 	mpg123_handle *m;
105 	if(!(m = mpg123_new(NULL, NULL))){
106 		fprintf(stderr,"Unable to create mpg123 handle\n");
107 		return -1;
108 	}
109 	mpg123_param(m, MPG123_FLAGS, MPG123_QUIET, 0);
110 	mpg123_open_fd(m,fileno(ffd));
111 	if(m == NULL) return -1;
112 
113 	if(!quick)
114 		mpg123_scan(m);
115 
116 	mpg123_getformat(m,&rate,NULL,NULL);
117 
118 	if(rate && (len=mpg123_length(m))!=MPG123_ERR)
119 		len/=rate;
120 	else
121 		len=-1;
122 
123 	mpg123_delete(m);
124 	mpg123_exit();
125 	return len;
126 }
127 
mp3_plugin_meta(FILE * ffd,struct musicInfo * mi)128 void mp3_plugin_meta(FILE *ffd, struct musicInfo *mi){
129 	int MAX_VERSION=4;
130 	int next=0;
131 	unsigned char buffer[255];
132 	fseek(ffd,next,SEEK_SET);
133 	if(fread(buffer,sizeof(char),10,ffd)<10)return;
134 	if(memcmp("ID3",buffer,3)==0 && buffer[4]<=MAX_VERSION){ // ID3v2
135 		ID3v2Parse(ffd,mi);
136 	}
137 	else{
138 		fseek(ffd,-128,SEEK_END);
139 		if(fread(buffer,sizeof(char),4,ffd)<4)return;
140 		if(memcmp("TAG",buffer,3)==0)ID3v1Parse(ffd,mi); // ID3v1
141 	}
142 
143 	mi->length=mp3Length(ffd,mi->length);
144 }
145