1 //
2 // A dirty sidtune format converter hack with almost no security code.
3 // Copyright (C) Michael Schwendt.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 //
19
20 #if defined(HAVE_FREEBSD)
21 #include <sys/types.h>
22 #endif
23 #include <ctype.h>
24 #include <dirent.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <iostream>
29 #include <iomanip>
30
31 #include <sidplay/sidtune.h>
32 #include <sidplay/fformat.h>
33
34 using std::cerr;
35 using std::cin;
36 using std::cout;
37 using std::endl;
38 using std::flush;
39
40 static bool toPSID = true,
41 toSIDPLAY = false,
42 checkOnly = false,
43 processDir = false,
44 recursive = false,
45 assumeAll = false;
46
47 static bool isDir(const char* file);
48 static void recurseDir(DIR* directory, const char* path);
49 static void handleFile(const char* file);
50 static void printUsage();
51
main(int argc,char * argv[])52 int main(int argc, char* argv[])
53 {
54 DIR *directory;
55 if ((directory = opendir(".")) == 0)
56 {
57 cerr << "ERROR: Cannot read current directory." << endl;
58 exit(-1);
59 }
60
61 if (argc < 2)
62 {
63 printUsage();
64 exit(-1);
65 }
66
67 int a = 0;
68
69 while (a++ < argc-1)
70 {
71 if (myStrNcaseCmp(argv[a],"--psid") == 0)
72 {
73 toPSID = true;
74 toSIDPLAY = false;
75 }
76 else if (myStrNcaseCmp(argv[a],"--sidplay") == 0)
77 {
78 toPSID = false;
79 toSIDPLAY = true;
80 }
81 else if (myStrNcaseCmp(argv[a],"--") == 0)
82 {
83 printUsage();
84 exit(-1);
85 }
86 else if (myStrNcaseCmp(argv[a],"-a") == 0)
87 {
88 assumeAll = true;
89 }
90 else if (myStrNcaseCmp(argv[a],"-c") == 0)
91 {
92 checkOnly = true;
93 }
94 else if (myStrNcaseCmp(argv[a],"-d") == 0)
95 {
96 processDir = true;
97 }
98 else if (myStrNcaseCmp(argv[a],"-r") == 0)
99 {
100 recursive = true;
101 }
102 else if (myStrNcaseCmp(argv[a],"-") == 0)
103 {
104 printUsage();
105 exit(-1);
106 }
107 }
108
109 if (recursive)
110 {
111 recurseDir(directory,".");
112 exit(0);
113 }
114
115 if (processDir)
116 {
117 dirent *entry;
118 while ((entry = readdir(directory)) != 0)
119 {
120 if ((strcmp(entry->d_name,".")!=0) &&
121 (strcmp(entry->d_name,"..")!=0) &&
122 !isDir(entry->d_name))
123 {
124 handleFile(entry->d_name);
125 }
126 }
127 closedir(directory);
128 exit(0);
129 }
130
131 // Check for any filenames given.
132 bool success = true;
133 a = 0;
134 while (a++ < argc-1)
135 {
136 success = true; // reset flag for each new file
137
138 if (myStrNcaseCmp(argv[a],"-") != 0)
139 {
140 handleFile(argv[a]);
141 }
142 }
143 }
144
printUsage()145 static void printUsage()
146 {
147 cerr
148 << "Usage: sidcon <options> [--psid|--sidplay] <files>" << endl
149 << "options: -a assume yes (y) on all questions" << endl
150 << " -c only check each file's loadaddress" << endl
151 << " -d process current directory" << endl
152 << " -r recurse into current directory tree" << endl;
153 }
154
handleFile(const char * file)155 static void handleFile(const char* file)
156 {
157 cout << file << ' ';
158
159 char* outFileName = 0;
160 sidTune mySidTune(file,true,0); // true => compile and run on MS Windows
161 sidTuneInfo mySTI;
162
163 bool success = mySidTune.getStatus();
164 bool saveIt = !checkOnly;
165
166 if (!success)
167 {
168 mySidTune.getInfo(mySTI);
169 cerr << mySTI.statusString << endl;
170 }
171
172 char* origDataName = 0;
173 char* infoFileName = 0;
174
175 if (success)
176 {
177 cout << '.';
178 success &= mySidTune.getInfo(mySTI);
179 if (mySTI.fixLoad)
180 {
181 cout << endl << "Duplicate C64 load address detected. Fix it? (y/n) " << flush;
182 bool fixIt = false;
183 if (assumeAll)
184 {
185 cout << endl;
186 fixIt = true;
187 }
188 else
189 {
190 char c;
191 cin >> c;
192 fixIt = (tolower(c)=='y');
193 }
194 if (fixIt)
195 {
196 mySidTune.fixLoadAddress();
197 saveIt = true;
198 }
199 }
200 success &= (mySTI.dataFileName!=0);
201 if (success)
202 {
203 success &= (0!=(outFileName = new char[strlen(mySTI.path)+strlen(mySTI.dataFileName)+4+1]));
204 if (success)
205 {
206 strcpy(outFileName,mySTI.path);
207 strcat(outFileName,mySTI.dataFileName);
208 origDataName = myStrDup(outFileName); // save it for error recovery
209 }
210 }
211 }
212
213 char* tmp = fileNameWithoutPath(tmpnam(NULL));
214 char* tmpDataName = new char[strlen(mySTI.path)+strlen(tmp)+1];
215 strcpy(tmpDataName,mySTI.path);
216 strcat(tmpDataName,tmp);
217
218 tmp = fileNameWithoutPath(tmpnam(NULL));
219 char* tmpInfoName = new char[strlen(mySTI.path)+strlen(tmp)+1];
220 strcpy(tmpInfoName,mySTI.path);
221 strcat(tmpInfoName,tmp);
222
223 if (success && saveIt)
224 {
225 cout << '.';
226 success &= (0==rename(outFileName,tmpDataName)); // outFileName = path+dataFileName
227 if (mySTI.infoFileName != 0)
228 {
229 strcpy(outFileName,mySTI.path);
230 strcat(outFileName,mySTI.infoFileName);
231 infoFileName = myStrDup(outFileName); // save it for error recovery
232 success &= (0==rename(outFileName,tmpInfoName));
233 }
234 else
235 {
236 tmpInfoName = 0;
237 }
238 }
239
240
241 if (success && saveIt)
242 {
243 cout << '.';
244 if (toPSID)
245 {
246 strcpy(fileExtOfPath(outFileName),".sid");
247 success &= (mySidTune.savePSIDfile(outFileName));
248 }
249 else if (toSIDPLAY)
250 {
251 strcpy(fileExtOfPath(outFileName),".c64");
252 success &= (mySidTune.saveC64dataFile(outFileName));
253 strcpy(fileExtOfPath(outFileName),".sid");
254 success &= (mySidTune.saveSIDfile(outFileName));
255 }
256
257 if (success)
258 {
259 remove(tmpDataName);
260 if (tmpInfoName != 0)
261 remove(tmpInfoName);
262 }
263 else // recover tmp files
264 {
265 rename(tmpDataName,origDataName);
266 if (tmpInfoName != 0)
267 rename(tmpInfoName,infoFileName);
268 }
269 }
270
271 if (success && saveIt)
272 {
273 cout << " SAVED" << endl;
274 }
275 else if (success)
276 {
277 cout << " OK" << endl;
278 }
279
280 if (tmpDataName != 0)
281 delete[] tmpDataName;
282 if (tmpInfoName != 0)
283 delete[] tmpInfoName;
284 if (outFileName != 0)
285 delete[] outFileName;
286 if (origDataName != 0)
287 delete[] origDataName;
288 if (infoFileName != 0)
289 delete[] infoFileName;
290 }
291
isDir(const char * file)292 bool isDir(const char* file)
293 {
294 DIR *directory;
295 if ((directory = opendir(file)) == 0)
296 return false;
297 else
298 {
299 closedir(directory);
300 return true;
301 }
302 }
303
recurseDir(DIR * directory,const char * path)304 void recurseDir(DIR* directory, const char* path)
305 {
306 dirent *entry;
307 while ((entry = readdir(directory)) != 0)
308 {
309 char* file = new char[strlen(path)+strlen(entry->d_name)+1+1];
310 strcpy(file,path);
311 strcat(file,"/");
312 strcat(file,entry->d_name);
313 if ((strcmp(entry->d_name,".")!=0) &&
314 (strcmp(entry->d_name,"..")!=0) &&
315 !isDir(file))
316 {
317 handleFile(file);
318 }
319 else if ((strcmp(entry->d_name,".")!=0) &&
320 (strcmp(entry->d_name,"..")!=0) &&
321 isDir(file))
322 {
323 char* newPath = new char[strlen(path)+strlen(entry->d_name)+1+1];
324 strcpy(newPath,path);
325 strcat(newPath,"/");
326 strcat(newPath,entry->d_name);
327 DIR* nextDir;
328 if ((nextDir = opendir(newPath)) == 0)
329 {
330 cerr << "ERROR: Cannot read directory ``" << newPath << "''." << endl;
331 }
332 else
333 {
334 recurseDir(nextDir,newPath);
335 }
336 delete[] newPath;
337 }
338 delete[] file;
339 }
340 closedir(directory);
341 }
342