87a5599140030bca496cdb4b97525f01062e68ae
[picodrive.git] / tools / bin_to_cso_mp3 / bin_to_cso_mp3.c
1 /*\r
2  * bin_to_cso_mp3\r
3  * originally written by Exophase as "bin_to_iso_ogg"\r
4  * updated for cso/mp3 by notaz\r
5  */\r
6 #include <stdio.h>\r
7 #include <stdlib.h>\r
8 #include <unistd.h>\r
9 #include <sys/stat.h>\r
10 #include <string.h>\r
11 \r
12 #ifndef MAX_PATH\r
13 #define MAX_PATH 1024\r
14 #endif\r
15 \r
16 #ifdef _WIN32\r
17 #include <windows.h>\r
18 \r
19 #define DIR_SEPARATOR_CHAR '\\'\r
20 #define PATH_SEPARATOR_CHAR ';'\r
21 #define LAME_BINARY "lame.exe"\r
22 #define CISO_BINARY "ciso.exe"\r
23 #define NULL_REDIR  "> NUL 2>&1"\r
24 #else\r
25 #define DIR_SEPARATOR_CHAR '/'\r
26 #define PATH_SEPARATOR_CHAR ':'\r
27 #define LAME_BINARY "lame"\r
28 #define CISO_BINARY "ciso"\r
29 #define NULL_REDIR  "> /dev/null 2>&1"\r
30 #define mkdir(x) mkdir(x, S_IRWXU)\r
31 #endif\r
32 \r
33 #define LAME_OPTIONS "-h --cbr"\r
34 \r
35 typedef unsigned char u8;\r
36 typedef unsigned short int u16;\r
37 typedef unsigned int u32;\r
38 typedef unsigned long long int u64;\r
39 typedef signed char s8;\r
40 typedef signed short int s16;\r
41 typedef signed int s32;\r
42 typedef signed long long int s64;\r
43 \r
44 typedef enum\r
45 {\r
46   TRACK_FILE_TYPE_BINARY,\r
47   TRACK_FILE_TYPE_WAVE,\r
48 } track_file_type_enum;\r
49 \r
50 typedef struct\r
51 {\r
52   u32 file_number;\r
53   u32 physical_offset;\r
54 \r
55   u32 sector_offset;\r
56   u32 sector_count;\r
57   u32 pregap_offset;\r
58 \r
59   u32 sector_size;\r
60   u32 format_type;\r
61 } cd_track_struct;\r
62 \r
63 typedef struct\r
64 {\r
65   track_file_type_enum type;\r
66   FILE *file_handle;\r
67 \r
68   u32 current_offset;\r
69 } cd_track_file_struct;\r
70 \r
71 typedef struct\r
72 {\r
73   FILE *bin_file;\r
74   cd_track_file_struct track_files[100];\r
75   u32 num_files;\r
76 \r
77   s32 first_track;\r
78   s32 last_track;\r
79   u32 num_physical_tracks;\r
80   u32 num_sectors;\r
81   s32 last_seek_track;\r
82 \r
83   cd_track_struct physical_tracks[100];\r
84   cd_track_struct *logical_tracks[100];\r
85 } cd_bin_struct;\r
86 \r
87 \r
88 cd_bin_struct cd_bin;\r
89 int opt_use_mp3 = 1;\r
90 int opt_mp3_bitrate = 128;\r
91 int opt_use_cso = 1;\r
92 \r
93 static void myexit(int code)\r
94 {\r
95 #ifdef _WIN32\r
96   system("pause");\r
97 #endif\r
98   exit(code);\r
99 }\r
100 \r
101 char *skip_whitespace(char *str)\r
102 {\r
103   while(*str == ' ')\r
104     str++;\r
105 \r
106   return str;\r
107 }\r
108 \r
109 s32 load_bin_cue(char *cue_file_name)\r
110 {\r
111   FILE *cue_file = fopen(cue_file_name, "rb");\r
112 \r
113   printf("loading cue file %s\n", cue_file_name);\r
114 \r
115   if(cue_file)\r
116   {\r
117     char line_buffer[256];\r
118     char *line_buffer_ptr;\r
119 \r
120     char bin_file_name[MAX_PATH];\r
121     char *separator_pos;\r
122     s32 current_physical_track_number = -1;\r
123     u32 current_physical_offset;\r
124     u32 current_pregap = 0;\r
125     u32 bin_file_size;\r
126 \r
127     cd_track_struct *current_physical_track = NULL;\r
128 \r
129     u32 i;\r
130 \r
131     // First, get filename. Only support binary right now.\r
132     fgets(line_buffer, 255, cue_file);\r
133 \r
134     strcpy(bin_file_name, strchr(line_buffer, '"') + 1);\r
135 \r
136     *(strrchr(bin_file_name, '"')) = 0;\r
137 \r
138     // Might have to change directory first.\r
139     separator_pos = strrchr(cue_file_name, DIR_SEPARATOR_CHAR);\r
140 \r
141     if(separator_pos)\r
142     {\r
143       char current_dir[MAX_PATH];\r
144       getcwd(current_dir, MAX_PATH);\r
145 \r
146       *separator_pos = 0;\r
147 \r
148       chdir(cue_file_name);\r
149 \r
150 #ifdef GP2X_BUILD\r
151       cd_bin.bin_file = open(bin_file_name, O_RDONLY);\r
152 #else\r
153       cd_bin.bin_file = fopen(bin_file_name, "rb");\r
154 #endif\r
155 \r
156       printf("loaded bin file %s (%p)\n", bin_file_name, cd_bin.bin_file);\r
157 \r
158       *separator_pos = DIR_SEPARATOR_CHAR;\r
159       chdir(current_dir);\r
160     }\r
161     else\r
162     {\r
163 #ifdef GP2X_BUILD\r
164       cd_bin.bin_file = open(bin_file_name, O_RDONLY);\r
165 #else\r
166       cd_bin.bin_file = fopen(bin_file_name, "rb");\r
167 #endif\r
168     }\r
169 \r
170     for(i = 0; i < 100; i++)\r
171     {\r
172       cd_bin.logical_tracks[i] = NULL;\r
173     }\r
174 \r
175     cd_bin.first_track = -1;\r
176     cd_bin.last_track = -1;\r
177     cd_bin.num_physical_tracks = 0;\r
178     cd_bin.num_sectors = 0;\r
179 \r
180     // Get line\r
181     while(fgets(line_buffer, 256, cue_file))\r
182     {\r
183       // Skip trailing whitespace\r
184       line_buffer_ptr = skip_whitespace(line_buffer);\r
185 \r
186       // Dirty, but should work - switch on first character.\r
187       switch(line_buffer_ptr[0])\r
188       {\r
189         // New track number\r
190         case 'T':\r
191         {\r
192           u32 new_track_number;\r
193           char track_type[64];\r
194 \r
195           sscanf(line_buffer_ptr, "TRACK %d %s", &new_track_number,\r
196            track_type);\r
197 \r
198           current_physical_track_number++;\r
199           current_physical_track =\r
200            cd_bin.physical_tracks + current_physical_track_number;\r
201 \r
202           current_physical_track->sector_size = 2352;\r
203 \r
204           if(!strcmp(track_type, "AUDIO"))\r
205           {\r
206             current_physical_track->format_type = 0;\r
207             current_physical_track->sector_size = 2352;\r
208           }\r
209 \r
210           if(!strcmp(track_type, "MODE1/2352"))\r
211           {\r
212             current_physical_track->format_type = 4;\r
213             current_physical_track->sector_size = 2352;\r
214           }\r
215 \r
216           if(!strcmp(track_type, "MODE1/2048"))\r
217           {\r
218             current_physical_track->format_type = 4;\r
219             current_physical_track->sector_size = 2048;\r
220           }\r
221 \r
222           cd_bin.logical_tracks[new_track_number] = current_physical_track;\r
223           cd_bin.num_physical_tracks++;\r
224 \r
225           if((cd_bin.first_track == -1) ||\r
226            (new_track_number < cd_bin.first_track))\r
227           {\r
228             cd_bin.first_track = new_track_number;\r
229           }\r
230 \r
231           if((cd_bin.last_track == -1) ||\r
232            (new_track_number > cd_bin.last_track))\r
233           {\r
234             cd_bin.last_track = new_track_number;\r
235           }\r
236 \r
237           break;\r
238         }\r
239 \r
240         // Pregap\r
241         case 'P':\r
242         {\r
243           u32 minutes, seconds, frames;\r
244 \r
245           sscanf(line_buffer_ptr, "PREGAP %d:%d:%d", &minutes,\r
246            &seconds, &frames);\r
247 \r
248           current_pregap += frames + (seconds * 75) + (minutes * 75 * 60);\r
249           break;\r
250         }\r
251 \r
252         // Index\r
253         case 'I':\r
254         {\r
255           u32 index_number;\r
256           u32 minutes, seconds, frames;\r
257           u32 sector_offset;\r
258 \r
259           sscanf(line_buffer_ptr, "INDEX %d %d:%d:%d", &index_number,\r
260            &minutes, &seconds, &frames);\r
261 \r
262           sector_offset = frames + (seconds * 75) + (minutes * 75 * 60);\r
263 \r
264           if(index_number == 1)\r
265           {\r
266             current_physical_track->pregap_offset = current_pregap;\r
267             current_physical_track->sector_offset = sector_offset;\r
268           }\r
269 \r
270           break;\r
271         }\r
272       }\r
273     }\r
274 \r
275     current_physical_offset = 0;\r
276 \r
277     for(i = 0; i < cd_bin.num_physical_tracks - 1; i++)\r
278     {\r
279       cd_bin.physical_tracks[i].sector_count =\r
280        cd_bin.physical_tracks[i + 1].sector_offset -\r
281        cd_bin.physical_tracks[i].sector_offset;\r
282 \r
283       cd_bin.physical_tracks[i].physical_offset = current_physical_offset;\r
284       current_physical_offset += (cd_bin.physical_tracks[i].sector_count *\r
285        cd_bin.physical_tracks[i].sector_size);\r
286 \r
287       cd_bin.physical_tracks[i].sector_offset +=\r
288        cd_bin.physical_tracks[i].pregap_offset;\r
289 \r
290       cd_bin.num_sectors += cd_bin.physical_tracks[i].sector_count;\r
291     }\r
292 \r
293 #ifdef GP2X_BUILD\r
294     bin_file_size = lseek(cd_bin.bin_file, 0, SEEK_END);\r
295     lseek(cd_bin.bin_file, 0, SEEK_SET);\r
296 #else\r
297     fseek(cd_bin.bin_file, 0, SEEK_END);\r
298     bin_file_size = ftell(cd_bin.bin_file);\r
299     fseek(cd_bin.bin_file, 0, SEEK_SET);\r
300 #endif\r
301 \r
302     // Set the last track data\r
303     cd_bin.physical_tracks[i].physical_offset = current_physical_offset;\r
304     cd_bin.physical_tracks[i].sector_offset +=\r
305      cd_bin.physical_tracks[i].pregap_offset;\r
306     cd_bin.physical_tracks[i].sector_count =\r
307      (bin_file_size - current_physical_offset) /\r
308      cd_bin.physical_tracks[i].sector_size;\r
309 \r
310     cd_bin.num_sectors += cd_bin.physical_tracks[i].sector_count;\r
311 \r
312     printf("finished loading cue %s\n", cue_file_name);\r
313     printf("bin file: %s (%p)\n", bin_file_name, cd_bin.bin_file);\r
314     printf("first track: %d, last track: %d\n", cd_bin.first_track,\r
315      cd_bin.last_track);\r
316 \r
317     for(i = cd_bin.first_track; i <= cd_bin.last_track; i++)\r
318     {\r
319       printf("track %d (%p):\n", i, cd_bin.logical_tracks[i]);\r
320       if(cd_bin.logical_tracks[i] == NULL)\r
321       {\r
322         printf("  (invalid)\n");\r
323       }\r
324       else\r
325       {\r
326         printf("  physical offset 0x%x\n",\r
327          cd_bin.logical_tracks[i]->physical_offset);\r
328         printf("  sector offset 0x%x\n",\r
329          cd_bin.logical_tracks[i]->sector_offset);\r
330         printf("  sector size %d\n",\r
331          cd_bin.logical_tracks[i]->sector_size);\r
332       }\r
333     }\r
334 \r
335     cd_bin.last_seek_track = 0;\r
336 \r
337     fclose(cue_file);\r
338     return 0;\r
339   }\r
340 \r
341   return -1;\r
342 }\r
343 \r
344 #define address8(base, offset)                                                \\r
345   *((u8 *)((u8 *)base + (offset)))                                            \\r
346 \r
347 #define address16(base, offset)                                               \\r
348   *((u16 *)((u8 *)base + (offset)))                                           \\r
349 \r
350 #define address32(base, offset)                                               \\r
351   *((u32 *)((u8 *)base + (offset)))                                           \\r
352 \r
353 // This will only work on little endian platforms for now.\r
354 \r
355 s32 convert_bin_to_wav(FILE *bin_file, char *output_dir, char *wav_file_name,\r
356  u32 sector_count)\r
357 {\r
358   FILE *wav_file;\r
359   u8 wav_header[36];\r
360   u8 *riff_header = wav_header + 0;\r
361   u8 *fmt_header = wav_header + 0x0C;\r
362   u8 sector_buffer[2352];\r
363   u32 byte_length = sector_count * 2352;\r
364   u32 i;\r
365 \r
366   chdir(output_dir);\r
367   wav_file = fopen(wav_file_name, "wb");\r
368 \r
369   printf("writing wav %s, %x sectors\n", wav_file_name, sector_count);\r
370 \r
371   // RIFF type chunk\r
372   memcpy(riff_header   + 0x00, "RIFF", 4);\r
373   address32(riff_header, 0x04) = byte_length + 44 - 8;\r
374   memcpy(riff_header   + 0x08, "WAVE", 4);\r
375 \r
376   // WAVE file chunk: format\r
377   memcpy(fmt_header   + 0x00, "fmt ", 4);\r
378   // Chunk data size\r
379   address32(fmt_header, 0x04) = 16;\r
380   // Compression code: PCM\r
381   address16(fmt_header, 0x08) = 1;\r
382   // Number of channels: Stereo\r
383   address16(fmt_header, 0x0a) = 2;\r
384   // Sample rate: 44100Hz\r
385   address32(fmt_header, 0x0c) = 44100;\r
386   // Average bytes per second: sample rate * 4\r
387   address32(fmt_header, 0x10) = 44100 * 4;\r
388   // Block align (bytes per sample)\r
389   address16(fmt_header, 0x14) = 4;\r
390   // Bit depth\r
391   address16(fmt_header, 0x16) = 16;\r
392 \r
393   // Write out header\r
394   fwrite(wav_header, 36, 1, wav_file);\r
395 \r
396   // DATA chunk\r
397   fprintf(wav_file, "data");\r
398   // length\r
399   fwrite(&byte_length, 4, 1, wav_file);\r
400 \r
401   // Write out sectors\r
402   for(i = 0; i < sector_count; i++)\r
403   {\r
404     printf("\b\b\b%3i", i*100 / sector_count);\r
405     fflush(stdout);\r
406     fread(sector_buffer, 2352, 1, bin_file);\r
407     fwrite(sector_buffer, 2352, 1, wav_file);\r
408   }\r
409   printf("\b\b\b100\n");\r
410 \r
411   fclose(wav_file);\r
412   chdir("..");\r
413   return 0;\r
414 }\r
415 \r
416 void convert_wav_to_ogg(char *wav_file_name, char *output_dir,\r
417  char *ogg_file_name)\r
418 {\r
419   char cmd_string[(MAX_PATH * 2) + 16];\r
420 \r
421   chdir(output_dir);\r
422   sprintf(cmd_string, "oggenc %s", wav_file_name);\r
423   system(cmd_string);\r
424 \r
425   unlink(wav_file_name);\r
426   chdir("..");\r
427 }\r
428 \r
429 void convert_wav_to_mp3(char *wav_file_name, char *output_dir,\r
430  char *mp3_file_name)\r
431 {\r
432   char cmd_string[(MAX_PATH * 2) + 16];\r
433 \r
434   chdir(output_dir);\r
435   sprintf(cmd_string, LAME_BINARY " " LAME_OPTIONS " -b %i \"%s\" \"%s\"",\r
436    opt_mp3_bitrate, wav_file_name, mp3_file_name);\r
437   if (system(cmd_string) != 0)\r
438   {\r
439     printf("failed to encode mp3\n");\r
440     myexit(1);\r
441   }\r
442 \r
443   unlink(wav_file_name);\r
444   chdir("..");\r
445 }\r
446 \r
447 s32 convert_bin_to_iso(FILE *bin_file, char *output_dir, char *iso_file_name,\r
448  u32 sector_count)\r
449 {\r
450   FILE *iso_file;\r
451   u8 sector_buffer[2352];\r
452   u32 i;\r
453 \r
454   chdir(output_dir);\r
455   iso_file = fopen(iso_file_name, "wb");\r
456   if (iso_file == NULL)\r
457   {\r
458     printf("failed to open: %s\n", iso_file_name);\r
459     myexit(1);\r
460   }\r
461   printf("writing iso %s, %x sectors\n", iso_file_name, sector_count);\r
462 \r
463   for(i = 0; i < sector_count; i++)\r
464   {\r
465     printf("\b\b\b%3i", i*100 / sector_count);\r
466     fflush(stdout);\r
467     fread(sector_buffer, 2352, 1, bin_file);\r
468     fwrite(sector_buffer + 16, 2048, 1, iso_file);\r
469   }\r
470   printf("\b\b\b100\n");\r
471 \r
472   fclose(iso_file);\r
473   chdir("..");\r
474   return 0;\r
475 }\r
476 \r
477 void convert_iso_to_cso(char *output_dir, char *iso_file_name, char *cso_file_name)\r
478 {\r
479   char cmd_string[(MAX_PATH * 2) + 16];\r
480 \r
481   chdir(output_dir);\r
482   sprintf(cmd_string, CISO_BINARY " 9 \"%s\" \"%s\"", iso_file_name, cso_file_name);\r
483   if (system(cmd_string) != 0)\r
484   {\r
485     printf("failed to convert iso to cso\n");\r
486     myexit(1);\r
487   }\r
488 \r
489   unlink(iso_file_name);\r
490   chdir("..");\r
491 }\r
492 \r
493 \r
494 #define sector_offset_to_msf(offset, minutes, seconds, frames)                \\r
495 {                                                                             \\r
496   u32 _offset = offset;                                                       \\r
497   minutes = (_offset / 75) / 60;                                              \\r
498   seconds = (_offset / 75) % 60;                                              \\r
499   frames = _offset % 75;                                                      \\r
500 }                                                                             \\r
501 \r
502 \r
503 s32 convert_bin_cue(char *output_name_base)\r
504 {\r
505   char output_file_name[MAX_PATH];\r
506   FILE *output_cue_file;\r
507   FILE *bin_file = cd_bin.bin_file;\r
508   cd_track_struct *current_track;\r
509   u32 m, s, f;\r
510   u32 current_pregap = 0;\r
511   u32 last_pregap = 0;\r
512   u32 i;\r
513   struct stat sb;\r
514 \r
515   if(stat(output_name_base, &sb))\r
516     mkdir(output_name_base);\r
517 \r
518   sprintf(output_file_name, "%s.cue", output_name_base);\r
519   chdir(output_name_base);\r
520   output_cue_file = fopen(output_file_name, "wb");\r
521   chdir("..");\r
522 \r
523   // Every track gets its own file. It's either going to be of type ISO\r
524   // or of type WAV.\r
525 \r
526   for(i = 0; i < 100; i++)\r
527   {\r
528     current_track = cd_bin.logical_tracks[i];\r
529     if(current_track != NULL)\r
530     {\r
531       switch(current_track->format_type)\r
532       {\r
533         char output_name_tmp[MAX_PATH];\r
534 \r
535         // Audio\r
536         case 0:\r
537         {\r
538           sprintf(output_file_name, "%s_%02d.mp3", output_name_base, i);\r
539           sprintf(output_name_tmp, "%s_%02d.wav", output_name_base, i);\r
540 \r
541           fprintf(output_cue_file, "FILE \"%s\" %s\n",\r
542            opt_use_mp3 ? output_file_name : output_name_tmp,\r
543            opt_use_mp3 ? "MP3" : "WAVE");\r
544           fprintf(output_cue_file, "  TRACK %02d AUDIO\n", i);\r
545           current_pregap = current_track->pregap_offset - last_pregap;\r
546           last_pregap = current_track->pregap_offset;\r
547           if(current_pregap > 0)\r
548           {\r
549             sector_offset_to_msf(current_pregap, m, s, f);\r
550             fprintf(output_cue_file, "    PREGAP %02d:%02d:%02d\n", m, s, f);\r
551           }\r
552           fprintf(output_cue_file, "    INDEX 01 00:00:00\n");\r
553           sector_offset_to_msf(current_track->sector_count, m, s, f);\r
554           fprintf(output_cue_file, "    REM LENGTH %02d:%02d:%02d\n", m, s, f);\r
555 \r
556           fseek(bin_file, current_track->physical_offset, SEEK_SET);\r
557           convert_bin_to_wav(bin_file, output_name_base, output_name_tmp,\r
558            current_track->sector_count);\r
559           if(opt_use_mp3)\r
560           {\r
561             convert_wav_to_mp3(output_name_tmp, output_name_base,\r
562              output_file_name);\r
563           }\r
564           break;\r
565         }\r
566 \r
567         // Data\r
568         default:\r
569           sprintf(output_file_name, "%s_%02d.cso", output_name_base, i);\r
570           sprintf(output_name_tmp, "%s_%02d.iso", output_name_base, i);\r
571           fprintf(output_cue_file, "FILE \"%s\" BINARY\n",\r
572            opt_use_cso ? output_file_name : output_name_tmp);\r
573           fprintf(output_cue_file, "  TRACK %02d MODE1/2048\n", i);\r
574           current_pregap = current_track->pregap_offset - last_pregap;\r
575           last_pregap = current_track->pregap_offset;\r
576           if(current_pregap > 0)\r
577           {\r
578             sector_offset_to_msf(current_pregap, m, s, f);\r
579             fprintf(output_cue_file, "    PREGAP %02d:%02d:%02d\n", m, s, f);\r
580           }\r
581           fprintf(output_cue_file, "    INDEX 01 00:00:00\n");\r
582 \r
583           fseek(bin_file, current_track->physical_offset, SEEK_SET);\r
584           convert_bin_to_iso(bin_file, output_name_base, output_name_tmp,\r
585            current_track->sector_count);\r
586           if(opt_use_cso)\r
587           {\r
588             convert_iso_to_cso(output_name_base, output_name_tmp, output_file_name);\r
589           }\r
590           break;\r
591       }\r
592     }\r
593   }\r
594 \r
595   fclose(output_cue_file);\r
596 \r
597   return 0;\r
598 }\r
599 \r
600 #ifdef _WIN32\r
601 static void update_path(void)\r
602 {\r
603   char buff1[MAX_PATH], buff2[MAX_PATH];\r
604   char *path;\r
605   int i;\r
606 \r
607   path = getenv("PATH");\r
608   GetModuleFileNameA(NULL, buff1, sizeof(buff1));\r
609   for (i = strlen(buff1)-1; i > 0; i--)\r
610     if (buff1[i] == '\\') break;\r
611   buff1[i] = 0;\r
612 \r
613   snprintf(buff2, sizeof(buff2), "%s;%s", path, buff1);\r
614   SetEnvironmentVariableA("PATH", buff2);\r
615 }\r
616 #endif\r
617 \r
618 int main(int argc, char *argv[])\r
619 {\r
620   char out_buff[MAX_PATH], *cue_file, *out_base;\r
621   int a;\r
622 \r
623   if(argc < 2)\r
624   {\r
625     printf("bin/cue to cso/mp3 converter\n");\r
626     printf("usage: %s [options] <input cue> [output base]\n", argv[0]);\r
627     printf("options:\n"\r
628            "   -m        output mp3 files for audio (default) (lame required)\n"\r
629            "   -b <rate> mp3 bitrate to use (default is 128)\n"\r
630            "   -w        output wav files for audio\n"\r
631            "   -c        output cso as data track (default) (ciso required)\n"\r
632            "   -i        output iso as data track\n");\r
633     return 0;\r
634   }\r
635 \r
636   for (a = 1; a < argc - 1; a++)\r
637   {\r
638     if      (strcmp(argv[a], "-m") == 0)\r
639       opt_use_mp3 = 1;\r
640     else if (strcmp(argv[a], "-w") == 0)\r
641       opt_use_mp3 = 0;\r
642     else if (strcmp(argv[a], "-c") == 0)\r
643       opt_use_cso = 1;\r
644     else if (strcmp(argv[a], "-i") == 0)\r
645       opt_use_cso = 0;\r
646     else if (strcmp(argv[a], "-b") == 0)\r
647     {\r
648       opt_mp3_bitrate = atoi(argv[++a]);\r
649     }\r
650     else\r
651       break;\r
652   }\r
653   cue_file = argv[a];\r
654   out_base = argv[a+1];\r
655 \r
656   /* some sanity checks */\r
657   if(strlen(cue_file) < 4 || strcasecmp(cue_file + strlen(cue_file) - 4, ".cue") != 0)\r
658   {\r
659     printf("error: not a cue file specified?\n");\r
660     myexit(1);\r
661   }\r
662 \r
663 #ifdef _WIN32\r
664   update_path();\r
665 #endif\r
666 \r
667   if(opt_use_mp3 && system(LAME_BINARY " --help " NULL_REDIR) != 0)\r
668   {\r
669     printf("LAME seems to be missing.\n"\r
670 #ifdef _WIN32\r
671       "Download from http://lame.sourceforge.net/links.php#Binaries and extract\n"\r
672       "lame.exe to the same directory as %s\n", argv[0]\r
673 #else\r
674       "Install lame using your packet manager, obtain binaries or build from\n"\r
675       "sources at http://lame.sourceforge.net/\n"\r
676 #endif\r
677       );\r
678     myexit(1);\r
679   }\r
680 \r
681   if(opt_use_cso && system(CISO_BINARY " " NULL_REDIR) != 0)\r
682   {\r
683     printf("CISO seems to be missing.\n"\r
684 #ifdef _WIN32\r
685       "Download ciso.exe and extract to the same directory as %s\n"\r
686       "You can take ciso.exe from yacc at http://yacc.pspgen.com/\n", argv[0]\r
687 #else\r
688       "Install ciso using your packet manager, obtain binaries or build from\n"\r
689       "sources at http://ciso.tenshu.fr/\n"\r
690 #endif\r
691       );\r
692     myexit(1);\r
693   }\r
694 \r
695   if(load_bin_cue(cue_file) == 0)\r
696   {\r
697     if(out_base == NULL)\r
698     {\r
699       char *p;\r
700       strncpy(out_buff, cue_file, sizeof(out_buff));\r
701       out_buff[sizeof(out_buff)-1] = 0;\r
702       p = strrchr(out_buff, DIR_SEPARATOR_CHAR);\r
703       if (p != NULL)\r
704       {\r
705         *p++ = 0;\r
706         chdir(out_buff);\r
707         memmove(out_buff, p, strlen(p)+1);\r
708       }\r
709       out_buff[strlen(out_buff)-4] = 0;\r
710       out_base = out_buff;\r
711     }\r
712     if(convert_bin_cue(out_base) != 0)\r
713       myexit(1);\r
714   }\r
715   else\r
716   {\r
717     printf("error: could not load cue file %s\n", cue_file);\r
718     myexit(1);\r
719   }\r
720 \r
721   return 0;\r
722 }\r
723 \r