1 /*
2     MP3Info - Displays and allows editing of MP3 ID3 tags and various
3               technical aspects of MP3 files.
4 
5     mp3info.c - main part of console version of MP3Info
6 
7     Copyright (C) 2000-2006 Cedric Tefft <cedric@phreaker.net>
8 
9     This program is free software; you can redistribute it and/or modify
10     it under the terms of the GNU General Public License as published by
11     the Free Software Foundation; either version 2 of the License, or
12     (at your option) any later version.
13 
14     This program is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with this program; if not, write to the Free Software
21     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 
23   ***************************************************************************
24 
25   This program is based in part on MP3Info 0.5 by Ricardo Cerqueira <rmc@rccn.net>
26 
27 */
28 
29 
30 #define __MAIN
31 #include "mp3info.h"
32 #undef __MAIN
33 #include <sys/stat.h>
34 
35 char FILENAME_FORMAT_STRING[]="File: %F\n";
36 char ID3_FORMAT_STRING[]="Title:   %-30t Track: %n\nArtist:  %a\nAlbum:   %-30l Year:  %y\nComment: %-30c Genre: %g [%G]\n";
37 char TECH_FORMAT_STRING[]="Media Type:  MPEG %2.1v Layer %L\nAudio:       %r KB/s, %qKHz (%o)\nEmphasis:    %e\nCRC:         %E\nCopyright:   %C\nOriginal:    %O\nPadding:     %p\nLength:      %m:%02s\n";
38 
main(int argc,char * argv[])39 int main(int argc, char *argv[]) {
40    FILE  *fp;
41    int c, i, interactive = 0, view_only=1,delete_tag=0,file_open,retcode=0;
42    int want_id3=1,scantype=SCAN_NONE,fullscan_vbr=0;
43    int show_techinfo=0,force_mode=0,quickscan=1;
44    int new_track=0,new_genre=0,firstfilearg;
45    id3tag new_tag;
46    char *print_format=NULL;
47    char error_msg[256];
48    unsigned int g,n;
49    int vbr_report=VBR_VARIABLE;
50    mp3info mp3;
51 
52 
53    new_tag.title[0]=new_tag.artist[0]=new_tag.album[0]=new_tag.year[0]=
54    new_tag.comment[0]=new_tag.track[0]=new_tag.genre[0]=1;
55    /* use something REALLY unlikely... -- so we could clear the tag... */
56 
57    if (argc < 2 ) /* Only command is given. Short help */ {
58 	   printf("%s %s\n"\
59 		  "\n  MP3Info comes with ABSOLUTELY NO WARRANTY.  This is free software, and\n"\
60 		  "  you are welcome to redistribute it under certain conditions.\n"\
61 		  "  See the file 'LICENSE' for more information.\n"\
62 		  "\nUse 'mp3info -h' for a usage summary or see the mp3info man page for a\n"\
63 		  "complete description.\n",VERSION,COPYRIGHT);
64 	   return 0;
65    }
66 
67 
68 
69    while ((c=getopt(argc,argv,"vhGidfxFt:a:l:y:c:n:g:p:r:"))!=-1) {
70 
71 	switch(c) {
72 		case 'v': /* View mode is now automatic when no changes are
73 			     made to the ID3 tag. This switch is accepted
74 			     only for backward compatibility */
75 			break;
76 		case 'h':
77 			display_help(); return 0;
78 			break;
79 		case 'G':
80 			display_genres(alphagenreindex,typegenre); return 0;
81 			break;
82 		case 'i':
83 			view_only=0;
84 			interactive = 1;
85 			break;
86 		case 'd':
87 			view_only=0;
88 			delete_tag=1;
89 			break;
90 		case 'p':
91 			print_format=optarg;
92 			translate_escapes(print_format);
93 			want_id3=0;
94 			break;
95 	        case 'f':
96 			force_mode=1;
97 			break;
98 		case 'x':
99 			show_techinfo=1;
100 			break;
101 		case 't':
102 			strncpy(new_tag.title,optarg,TEXT_FIELD_LEN);
103 			view_only=0;
104 			break;
105 		case 'a':
106 			strncpy(new_tag.artist,optarg,TEXT_FIELD_LEN);
107 			view_only=0;
108 			break;
109 		case 'l':
110 			strncpy(new_tag.album,optarg,TEXT_FIELD_LEN);
111 			view_only=0;
112 			break;
113 		case 'y':
114 			strncpy(new_tag.year,optarg,INT_FIELD_LEN);
115 			view_only=0;
116 			break;
117 		case 'c':
118 			strncpy(new_tag.comment,optarg,TEXT_FIELD_LEN);
119 			view_only=0;
120 			break;
121 		case 'n':
122 			n=atoi(optarg);
123 			if(n <= 255) {
124 				new_tag.track[0] = (unsigned char) n;
125 				new_track=1;
126 				view_only=0;
127 			} else {
128 				fprintf(stderr,"Error: '%s' is not a valid track number.\n",optarg);
129 				fprintf(stderr,"Valid track numbers are integers from 0 to 255.\n");
130 				fprintf(stderr,"Use a value of '0' to remove the track number field\n");
131 				retcode |= 6;
132 				return retcode;
133 			}
134 			break;
135 		case 'g':
136 			g=get_genre(optarg);
137 			if(g <= 255) {
138 				new_tag.genre[0] = (unsigned char) g;
139 				new_genre=1;
140 				view_only=0;
141 			} else {
142 				fprintf(stderr,"Error: '%s' is not a recognized genre name or number.\n",optarg);
143 				fprintf(stderr,"Use the '-G' option to see a list of valid genre names and numbers\n");
144 				retcode |= 6;
145 				return retcode;
146 			}
147 			sscanf(optarg,"%u",&g);
148 			break;
149 		case 'r':
150 			switch(optarg[0]) {
151 				case 'a': vbr_report=VBR_AVERAGE; break;
152 				case 'm': vbr_report=VBR_MEDIAN; break;
153 				case 'v': vbr_report=VBR_VARIABLE; break;
154 				default:
155 					fprintf(stderr,"Error: %s is not a valid option to the VBR reporting switch (-r)\n",optarg);
156 					fprintf(stderr,"Valid options are 'a', 'm' and 'v'.  Run '%s -h' for more info.\n",argv[0]);
157 					retcode |= 6;
158 					return retcode;
159 			}
160 			break;
161 		case 'F': quickscan=0; break;
162 	}
163    }
164 
165    if(!view_only)
166 	scantype=SCAN_QUICK;
167 
168    if(print_format) {
169    	determine_tasks(print_format,&want_id3,&scantype,&fullscan_vbr,vbr_report);
170    } else if(view_only) {
171    	determine_tasks(ID3_FORMAT_STRING,&want_id3,&scantype,&fullscan_vbr,vbr_report);
172 	if(show_techinfo)
173 		determine_tasks(TECH_FORMAT_STRING,&want_id3,&scantype,&fullscan_vbr,vbr_report);
174    }
175 
176 
177    if(!quickscan && (scantype == SCAN_QUICK))
178    	scantype=SCAN_FULL;
179 
180    firstfilearg=optind;
181 
182    for(i=optind;i < argc; i++) { /* Iterate over all filenames */
183       file_open=0;
184       if (view_only == 1) {
185         if ( !( fp=fopen(argv[i],"rb") ) ) {
186   	        sprintf(error_msg,"Error opening MP3: %s",argv[i]);
187                 perror(error_msg);
188 		retcode |= 1;
189         } else {
190 		file_open=1;
191 	}
192       } else {
193         if ( !( fp=fopen(argv[i],"rb+") ) ) {
194   	        sprintf(error_msg,"Error opening MP3: %s",argv[i]);
195                 perror(error_msg);
196 	        retcode |= 1;
197         } else {
198 		file_open=1;
199 	}
200       }
201 
202       if(file_open == 1) {
203 	memset(&mp3,0,sizeof(mp3info));
204 	mp3.filename=argv[i];
205 	mp3.file=fp;
206 	get_mp3_info(&mp3,scantype,fullscan_vbr);
207 
208 	if((scantype != SCAN_NONE) && !mp3.header_isvalid && !force_mode) {
209 		fprintf(stderr,"%s is corrupt or is not a standard MP3 file.\n",mp3.filename);
210 		retcode |= 2;
211 	}
212 
213 	if(view_only) {
214 	   if(want_id3 && !mp3.id3_isvalid)
215 		fprintf(stderr,"%s does not have an ID3 1.x tag.\n",mp3.filename);
216 
217 	    if(print_format) {
218 		format_output(print_format,&mp3,vbr_report);
219             } else {
220 
221 		if(mp3.id3_isvalid || (show_techinfo && mp3.header_isvalid))
222   	          	format_output(FILENAME_FORMAT_STRING,&mp3,vbr_report);
223 
224        		if(mp3.id3_isvalid)
225 			format_output(ID3_FORMAT_STRING,&mp3,vbr_report);
226 
227             	if(show_techinfo && mp3.header_isvalid)
228 			format_output(TECH_FORMAT_STRING,&mp3,vbr_report);
229 
230        	    	printf("\n");
231 
232 	    }
233 
234 	} else if(mp3.header_isvalid || force_mode) {
235 
236 	     if(new_tag.title[0]!=1) {
237 		  strncpy(mp3.id3.title,new_tag.title,TEXT_FIELD_LEN);
238 	     }
239 
240 	     if(new_tag.artist[0]!=1) {
241 		  strncpy(mp3.id3.artist,new_tag.artist,TEXT_FIELD_LEN);
242 	     }
243 
244 	     if(new_tag.album[0]!=1) {
245 		  strncpy(mp3.id3.album,new_tag.album,TEXT_FIELD_LEN);
246 	     }
247 
248 	     if(new_tag.comment[0]!=1) {
249 			strncpy(mp3.id3.comment,new_tag.comment,TEXT_FIELD_LEN);
250 	     }
251 
252 	     if(new_track) {
253 		  mp3.id3.track[0]=new_tag.track[0];
254 		  if(new_tag.track[0] == '\0') {
255 		     pad(mp3.id3.comment,TEXT_FIELD_LEN);
256 		  }
257 	     }
258 
259 	     if(new_tag.year[0]!=1) {
260 		  strncpy(mp3.id3.year,new_tag.year,INT_FIELD_LEN);
261 	     }
262 
263 	     if(new_genre) {
264 		  mp3.id3.genre[0]=new_tag.genre[0];
265 	     }
266 
267 	     if( interactive ) {
268 	 	  tagedit_curs(mp3.filename,i-firstfilearg+1,argc-firstfilearg,&(mp3.id3));
269 	     }
270 
271 
272 
273              /* Finally! Get it done! */
274              if(!delete_tag) {
275 	          write_tag(&mp3);
276              }
277 
278 	 } else {
279 		fprintf(stderr,"Use the -f switch to add ID3 info to this file anyway.\n");
280 	 }
281 
282          fclose(mp3.file);
283 
284          if(delete_tag && mp3.id3_isvalid) {
285 		truncate(mp3.filename,mp3.datasize);
286 	 }
287 
288 
289       }
290 
291    }
292 
293    if(optind == argc) {
294 	fprintf(stderr,"No MP3 files specified!\n");
295 	retcode |= 8;
296    }
297 
298 
299    return retcode;
300 
301 }
302 
303 
304