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