| 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 |