cdreader.c (25115B)
1 #include "rc_hash.h" 2 3 #include "../rc_compat.h" 4 5 #include <ctype.h> 6 #include <string.h> 7 #include <stdlib.h> 8 9 /* internal helper functions in hash.c */ 10 extern void* rc_file_open(const char* path); 11 extern void rc_file_seek(void* file_handle, int64_t offset, int origin); 12 extern int64_t rc_file_tell(void* file_handle); 13 extern size_t rc_file_read(void* file_handle, void* buffer, int requested_bytes); 14 extern void rc_file_close(void* file_handle); 15 extern int rc_hash_error(const char* message); 16 extern const char* rc_path_get_filename(const char* path); 17 extern int rc_path_compare_extension(const char* path, const char* ext); 18 extern rc_hash_message_callback verbose_message_callback; 19 20 struct cdrom_t 21 { 22 void* file_handle; /* the file handle for reading the track data */ 23 int sector_size; /* the size of each sector in the track data */ 24 int sector_header_size; /* the offset to the raw data within a sector block */ 25 int raw_data_size; /* the amount of raw data within a sector block */ 26 int64_t file_track_offset;/* the offset of the track data within the file */ 27 int track_first_sector; /* the first absolute sector associated to the track (includes pregap) */ 28 int track_pregap_sectors; /* the number of pregap sectors */ 29 #ifndef NDEBUG 30 uint32_t track_id; /* the index of the track */ 31 #endif 32 }; 33 34 static int cdreader_get_sector(uint8_t header[16]) 35 { 36 int minutes = (header[12] >> 4) * 10 + (header[12] & 0x0F); 37 int seconds = (header[13] >> 4) * 10 + (header[13] & 0x0F); 38 int frames = (header[14] >> 4) * 10 + (header[14] & 0x0F); 39 40 /* convert the MSF value to a sector index, and subtract 150 (2 seconds) per: 41 * For data and mixed mode media (those conforming to ISO/IEC 10149), logical block address 42 * zero shall be assigned to the block at MSF address 00/02/00 */ 43 return ((minutes * 60) + seconds) * 75 + frames - 150; 44 } 45 46 static void cdreader_determine_sector_size(struct cdrom_t* cdrom) 47 { 48 /* Attempt to determine the sector and header sizes. The CUE file may be lying. 49 * Look for the sync pattern using each of the supported sector sizes. 50 * Then check for the presence of "CD001", which is gauranteed to be in either the 51 * boot record or primary volume descriptor, one of which is always at sector 16. 52 */ 53 const uint8_t sync_pattern[] = { 54 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 55 }; 56 57 uint8_t header[32]; 58 const int64_t toc_sector = 16 + cdrom->track_pregap_sectors; 59 60 cdrom->sector_size = 0; 61 cdrom->sector_header_size = 0; 62 cdrom->raw_data_size = 2048; 63 64 rc_file_seek(cdrom->file_handle, toc_sector * 2352 + cdrom->file_track_offset, SEEK_SET); 65 if (rc_file_read(cdrom->file_handle, header, sizeof(header)) < sizeof(header)) 66 return; 67 68 if (memcmp(header, sync_pattern, 12) == 0) 69 { 70 cdrom->sector_size = 2352; 71 72 if (memcmp(&header[25], "CD001", 5) == 0) 73 cdrom->sector_header_size = 24; 74 else 75 cdrom->sector_header_size = 16; 76 77 cdrom->track_first_sector = cdreader_get_sector(header) - (int)toc_sector; 78 } 79 else 80 { 81 rc_file_seek(cdrom->file_handle, toc_sector * 2336 + cdrom->file_track_offset, SEEK_SET); 82 rc_file_read(cdrom->file_handle, header, sizeof(header)); 83 84 if (memcmp(header, sync_pattern, 12) == 0) 85 { 86 cdrom->sector_size = 2336; 87 88 if (memcmp(&header[25], "CD001", 5) == 0) 89 cdrom->sector_header_size = 24; 90 else 91 cdrom->sector_header_size = 16; 92 93 cdrom->track_first_sector = cdreader_get_sector(header) - (int)toc_sector; 94 } 95 else 96 { 97 rc_file_seek(cdrom->file_handle, toc_sector * 2048 + cdrom->file_track_offset, SEEK_SET); 98 rc_file_read(cdrom->file_handle, header, sizeof(header)); 99 100 if (memcmp(&header[1], "CD001", 5) == 0) 101 { 102 cdrom->sector_size = 2048; 103 cdrom->sector_header_size = 0; 104 } 105 } 106 } 107 } 108 109 static void* cdreader_open_bin_track(const char* path, uint32_t track) 110 { 111 void* file_handle; 112 struct cdrom_t* cdrom; 113 114 if (track > 1) 115 { 116 if (verbose_message_callback) 117 verbose_message_callback("Cannot locate secondary tracks without a cue sheet"); 118 119 return NULL; 120 } 121 122 file_handle = rc_file_open(path); 123 if (!file_handle) 124 return NULL; 125 126 cdrom = (struct cdrom_t*)calloc(1, sizeof(*cdrom)); 127 if (!cdrom) 128 return NULL; 129 cdrom->file_handle = file_handle; 130 #ifndef NDEBUG 131 cdrom->track_id = track; 132 #endif 133 134 cdreader_determine_sector_size(cdrom); 135 136 if (cdrom->sector_size == 0) 137 { 138 int64_t size; 139 140 rc_file_seek(cdrom->file_handle, 0, SEEK_END); 141 size = rc_file_tell(cdrom->file_handle); 142 143 if ((size % 2352) == 0) 144 { 145 /* raw tracks use all 2352 bytes and have a 24 byte header */ 146 cdrom->sector_size = 2352; 147 cdrom->sector_header_size = 24; 148 } 149 else if ((size % 2048) == 0) 150 { 151 /* cooked tracks eliminate all header/footer data */ 152 cdrom->sector_size = 2048; 153 cdrom->sector_header_size = 0; 154 } 155 else if ((size % 2336) == 0) 156 { 157 /* MODE 2 format without 16-byte sync data */ 158 cdrom->sector_size = 2336; 159 cdrom->sector_header_size = 8; 160 } 161 else 162 { 163 free(cdrom); 164 165 if (verbose_message_callback) 166 verbose_message_callback("Could not determine sector size"); 167 168 return NULL; 169 } 170 } 171 172 return cdrom; 173 } 174 175 static int cdreader_open_bin(struct cdrom_t* cdrom, const char* path, const char* mode) 176 { 177 cdrom->file_handle = rc_file_open(path); 178 if (!cdrom->file_handle) 179 return 0; 180 181 /* determine sector size */ 182 cdreader_determine_sector_size(cdrom); 183 184 /* could not determine, which means we'll probably have more issues later 185 * but use the CUE provided information anyway 186 */ 187 if (cdrom->sector_size == 0) 188 { 189 /* All of these modes have 2048 byte payloads. In MODE1/2352 and MODE2/2352 190 * modes, the mode can actually be specified per sector to change the payload 191 * size, but that reduces the ability to recover from errors when the disc 192 * is damaged, so it's seldomly used, and when it is, it's mostly for audio 193 * or video data where a blip or two probably won't be noticed by the user. 194 * So, while we techincally support all of the following modes, we only do 195 * so with 2048 byte payloads. 196 * http://totalsonicmastering.com/cuesheetsyntax.htm 197 * MODE1/2048 ? CDROM Mode1 Data (cooked) [no header, no footer] 198 * MODE1/2352 ? CDROM Mode1 Data (raw) [16 byte header, 288 byte footer] 199 * MODE2/2336 ? CDROM-XA Mode2 Data [8 byte header, 280 byte footer] 200 * MODE2/2352 ? CDROM-XA Mode2 Data [24 byte header, 280 byte footer] 201 */ 202 if (memcmp(mode, "MODE2/2352", 10) == 0) 203 { 204 cdrom->sector_size = 2352; 205 cdrom->sector_header_size = 24; 206 } 207 else if (memcmp(mode, "MODE1/2048", 10) == 0) 208 { 209 cdrom->sector_size = 2048; 210 cdrom->sector_header_size = 0; 211 } 212 else if (memcmp(mode, "MODE2/2336", 10) == 0) 213 { 214 cdrom->sector_size = 2336; 215 cdrom->sector_header_size = 8; 216 } 217 else if (memcmp(mode, "MODE1/2352", 10) == 0) 218 { 219 cdrom->sector_size = 2352; 220 cdrom->sector_header_size = 16; 221 } 222 else if (memcmp(mode, "AUDIO", 5) == 0) 223 { 224 cdrom->sector_size = 2352; 225 cdrom->sector_header_size = 0; 226 cdrom->raw_data_size = 2352; /* no header or footer data on audio tracks */ 227 } 228 } 229 230 return (cdrom->sector_size != 0); 231 } 232 233 static char* cdreader_get_bin_path(const char* cue_path, const char* bin_name) 234 { 235 const char* filename = rc_path_get_filename(cue_path); 236 const size_t bin_name_len = strlen(bin_name); 237 const size_t cue_path_len = filename - cue_path; 238 const size_t needed = cue_path_len + bin_name_len + 1; 239 240 char* bin_filename = (char*)malloc(needed); 241 if (!bin_filename) 242 { 243 char buffer[64]; 244 snprintf(buffer, sizeof(buffer), "Failed to allocate %u bytes", (unsigned)needed); 245 rc_hash_error((const char*)buffer); 246 } 247 else 248 { 249 memcpy(bin_filename, cue_path, cue_path_len); 250 memcpy(bin_filename + cue_path_len, bin_name, bin_name_len + 1); 251 } 252 253 return bin_filename; 254 } 255 256 static int64_t cdreader_get_bin_size(const char* cue_path, const char* bin_name) 257 { 258 int64_t size = 0; 259 char* bin_filename = cdreader_get_bin_path(cue_path, bin_name); 260 if (bin_filename) 261 { 262 /* disable verbose messaging while getting file size */ 263 rc_hash_message_callback old_verbose_message_callback = verbose_message_callback; 264 void* file_handle; 265 verbose_message_callback = NULL; 266 267 file_handle = rc_file_open(bin_filename); 268 if (file_handle) 269 { 270 rc_file_seek(file_handle, 0, SEEK_END); 271 size = rc_file_tell(file_handle); 272 rc_file_close(file_handle); 273 } 274 275 verbose_message_callback = old_verbose_message_callback; 276 free(bin_filename); 277 } 278 279 return size; 280 } 281 282 static void* cdreader_open_cue_track(const char* path, uint32_t track) 283 { 284 void* cue_handle; 285 int64_t cue_offset = 0; 286 char buffer[1024]; 287 char* bin_filename = NULL; 288 char *ptr, *ptr2, *end; 289 int done = 0; 290 int session = 1; 291 size_t num_read = 0; 292 struct cdrom_t* cdrom = NULL; 293 294 struct track_t 295 { 296 uint32_t id; 297 int sector_size; 298 int sector_count; 299 int first_sector; 300 int pregap_sectors; 301 int is_data; 302 int file_track_offset; 303 int file_first_sector; 304 char mode[16]; 305 char filename[256]; 306 } current_track, previous_track, largest_track; 307 308 cue_handle = rc_file_open(path); 309 if (!cue_handle) 310 return NULL; 311 312 memset(¤t_track, 0, sizeof(current_track)); 313 memset(&previous_track, 0, sizeof(previous_track)); 314 memset(&largest_track, 0, sizeof(largest_track)); 315 316 do 317 { 318 num_read = rc_file_read(cue_handle, buffer, sizeof(buffer) - 1); 319 if (num_read == 0) 320 break; 321 322 buffer[num_read] = 0; 323 if (num_read == sizeof(buffer) - 1) 324 end = buffer + sizeof(buffer) * 3 / 4; 325 else 326 end = buffer + num_read; 327 328 for (ptr = buffer; ptr < end; ++ptr) 329 { 330 while (*ptr == ' ') 331 ++ptr; 332 333 if (strncasecmp(ptr, "INDEX ", 6) == 0) 334 { 335 int m = 0, s = 0, f = 0; 336 int index; 337 int sector_offset; 338 339 ptr += 6; 340 index = atoi(ptr); 341 342 while (*ptr != ' ' && *ptr != '\n') 343 ++ptr; 344 while (*ptr == ' ') 345 ++ptr; 346 347 /* convert mm:ss:ff to sector count */ 348 sscanf_s(ptr, "%d:%d:%d", &m, &s, &f); 349 sector_offset = ((m * 60) + s) * 75 + f; 350 351 if (current_track.first_sector == -1) 352 { 353 current_track.first_sector = sector_offset; 354 if (strcmp(current_track.filename, previous_track.filename) == 0) 355 { 356 previous_track.sector_count = current_track.first_sector - previous_track.first_sector; 357 current_track.file_track_offset += previous_track.sector_count * previous_track.sector_size; 358 } 359 360 /* if looking for the largest data track, determine previous track size */ 361 if (track == RC_HASH_CDTRACK_LARGEST && previous_track.sector_count > largest_track.sector_count && 362 previous_track.is_data) 363 { 364 memcpy(&largest_track, &previous_track, sizeof(largest_track)); 365 } 366 } 367 368 if (index == 1) 369 { 370 current_track.pregap_sectors = (sector_offset - current_track.first_sector); 371 372 if (verbose_message_callback) 373 { 374 char message[128]; 375 char* scan = current_track.mode; 376 while (*scan && !isspace((unsigned char)*scan)) 377 ++scan; 378 *scan = '\0'; 379 380 /* it's undesirable to truncate offset to 32-bits, but %lld isn't defined in c89. */ 381 snprintf(message, sizeof(message), "Found %s track %d (first sector %d, sector size %d, %d pregap sectors)", 382 current_track.mode, current_track.id, current_track.first_sector, current_track.sector_size, current_track.pregap_sectors); 383 verbose_message_callback(message); 384 } 385 386 if (current_track.id == track) 387 { 388 done = 1; 389 break; 390 } 391 392 if (track == RC_HASH_CDTRACK_FIRST_DATA && current_track.is_data) 393 { 394 track = current_track.id; 395 done = 1; 396 break; 397 } 398 399 if (track == RC_HASH_CDTRACK_FIRST_OF_SECOND_SESSION && session == 2) 400 { 401 track = current_track.id; 402 done = 1; 403 break; 404 } 405 } 406 } 407 else if (strncasecmp(ptr, "TRACK ", 6) == 0) 408 { 409 if (current_track.sector_size) 410 memcpy(&previous_track, ¤t_track, sizeof(current_track)); 411 412 ptr += 6; 413 current_track.id = atoi(ptr); 414 415 current_track.pregap_sectors = -1; 416 current_track.first_sector = -1; 417 418 while (*ptr != ' ') 419 ++ptr; 420 while (*ptr == ' ') 421 ++ptr; 422 memcpy(current_track.mode, ptr, sizeof(current_track.mode)); 423 current_track.is_data = (memcmp(current_track.mode, "MODE", 4) == 0); 424 425 if (current_track.is_data) 426 { 427 current_track.sector_size = atoi(ptr + 6); 428 } 429 else 430 { 431 /* assume AUDIO */ 432 current_track.sector_size = 2352; 433 } 434 } 435 else if (strncasecmp(ptr, "FILE ", 5) == 0) 436 { 437 if (current_track.sector_size) 438 { 439 memcpy(&previous_track, ¤t_track, sizeof(previous_track)); 440 441 if (previous_track.sector_count == 0) 442 { 443 const uint32_t file_sector_count = (uint32_t)cdreader_get_bin_size(path, previous_track.filename) / previous_track.sector_size; 444 previous_track.sector_count = file_sector_count - previous_track.first_sector; 445 } 446 447 /* if looking for the largest data track, check to see if this one is larger */ 448 if (track == RC_HASH_CDTRACK_LARGEST && previous_track.is_data && 449 previous_track.sector_count > largest_track.sector_count) 450 { 451 memcpy(&largest_track, &previous_track, sizeof(largest_track)); 452 } 453 } 454 455 memset(¤t_track, 0, sizeof(current_track)); 456 457 current_track.file_first_sector = previous_track.file_first_sector + 458 previous_track.first_sector + previous_track.sector_count; 459 460 ptr += 5; 461 ptr2 = ptr; 462 if (*ptr == '"') 463 { 464 ++ptr; 465 do 466 { 467 ++ptr2; 468 } while (*ptr2 && *ptr2 != '\n' && *ptr2 != '"'); 469 } 470 else 471 { 472 do 473 { 474 ++ptr2; 475 } while (*ptr2 && *ptr2 != '\n' && *ptr2 != ' '); 476 } 477 478 if (ptr2 - ptr < (int)sizeof(current_track.filename)) 479 memcpy(current_track.filename, ptr, ptr2 - ptr); 480 } 481 else if (strncasecmp(ptr, "REM ", 4) == 0) 482 { 483 ptr += 4; 484 while (*ptr == ' ') 485 ++ptr; 486 487 if (strncasecmp(ptr, "SESSION ", 8) == 0) 488 { 489 ptr += 8; 490 while (*ptr == ' ') 491 ++ptr; 492 session = atoi(ptr); 493 } 494 } 495 496 while (*ptr && *ptr != '\n') 497 ++ptr; 498 } 499 500 if (done) 501 break; 502 503 cue_offset += (ptr - buffer); 504 rc_file_seek(cue_handle, cue_offset, SEEK_SET); 505 506 } while (1); 507 508 rc_file_close(cue_handle); 509 510 if (track == RC_HASH_CDTRACK_LARGEST) 511 { 512 if (current_track.sector_size && current_track.is_data) 513 { 514 const uint32_t file_sector_count = (uint32_t)cdreader_get_bin_size(path, current_track.filename) / current_track.sector_size; 515 current_track.sector_count = file_sector_count - current_track.first_sector; 516 517 if (largest_track.sector_count > current_track.sector_count) 518 memcpy(¤t_track, &largest_track, sizeof(current_track)); 519 } 520 else 521 { 522 memcpy(¤t_track, &largest_track, sizeof(current_track)); 523 } 524 525 track = current_track.id; 526 } 527 else if (track == RC_HASH_CDTRACK_LAST && !done) 528 { 529 track = current_track.id; 530 } 531 532 if (current_track.id == track) 533 { 534 cdrom = (struct cdrom_t*)calloc(1, sizeof(*cdrom)); 535 if (!cdrom) 536 { 537 snprintf((char*)buffer, sizeof(buffer), "Failed to allocate %u bytes", (unsigned)sizeof(*cdrom)); 538 rc_hash_error((const char*)buffer); 539 return NULL; 540 } 541 542 cdrom->file_track_offset = current_track.file_track_offset; 543 cdrom->track_pregap_sectors = current_track.pregap_sectors; 544 cdrom->track_first_sector = current_track.file_first_sector + current_track.first_sector; 545 #ifndef NDEBUG 546 cdrom->track_id = current_track.id; 547 #endif 548 549 /* verify existance of bin file */ 550 bin_filename = cdreader_get_bin_path(path, current_track.filename); 551 if (bin_filename) 552 { 553 if (cdreader_open_bin(cdrom, bin_filename, current_track.mode)) 554 { 555 if (verbose_message_callback) 556 { 557 if (cdrom->track_pregap_sectors) 558 snprintf((char*)buffer, sizeof(buffer), "Opened track %d (sector size %d, %d pregap sectors)", 559 track, cdrom->sector_size, cdrom->track_pregap_sectors); 560 else 561 snprintf((char*)buffer, sizeof(buffer), "Opened track %d (sector size %d)", track, cdrom->sector_size); 562 563 verbose_message_callback((const char*)buffer); 564 } 565 } 566 else 567 { 568 if (cdrom->file_handle) 569 { 570 rc_file_close(cdrom->file_handle); 571 snprintf((char*)buffer, sizeof(buffer), "Could not determine sector size for %s track", current_track.mode); 572 } 573 else 574 { 575 snprintf((char*)buffer, sizeof(buffer), "Could not open %s", bin_filename); 576 } 577 578 rc_hash_error((const char*)buffer); 579 580 free(cdrom); 581 cdrom = NULL; 582 } 583 584 free(bin_filename); 585 } 586 } 587 588 return cdrom; 589 } 590 591 static void* cdreader_open_gdi_track(const char* path, uint32_t track) 592 { 593 void* file_handle; 594 char buffer[1024]; 595 char mode[16] = "MODE1/"; 596 char sector_size[16]; 597 char file[256]; 598 int64_t track_size; 599 int track_type; 600 char* bin_path = NULL; 601 uint32_t current_track = 0; 602 char* ptr, *ptr2, *end; 603 int lba = 0; 604 605 uint32_t largest_track = 0; 606 int64_t largest_track_size = 0; 607 char largest_track_file[256]; 608 char largest_track_sector_size[16]; 609 int largest_track_lba = 0; 610 611 int found = 0; 612 size_t num_read = 0; 613 int64_t file_offset = 0; 614 struct cdrom_t* cdrom = NULL; 615 616 file_handle = rc_file_open(path); 617 if (!file_handle) 618 return NULL; 619 620 file[0] = '\0'; 621 do 622 { 623 num_read = rc_file_read(file_handle, buffer, sizeof(buffer) - 1); 624 if (num_read == 0) 625 break; 626 627 buffer[num_read] = 0; 628 if (num_read == sizeof(buffer) - 1) 629 end = buffer + sizeof(buffer) * 3 / 4; 630 else 631 end = buffer + num_read; 632 633 ptr = buffer; 634 635 /* the first line contains the number of tracks, so we can get the last track index from it */ 636 if (track == RC_HASH_CDTRACK_LAST) 637 track = atoi(ptr); 638 639 /* first line contains the number of tracks and will be skipped */ 640 while (ptr < end) 641 { 642 /* skip until next newline */ 643 while (*ptr != '\n' && ptr < end) 644 ++ptr; 645 646 /* skip newlines */ 647 while ((*ptr == '\n' || *ptr == '\r') && ptr < end) 648 ++ptr; 649 650 /* line format: [trackid] [lba] [type] [sectorsize] [file] [?] */ 651 while (isspace((unsigned char)*ptr)) 652 ++ptr; 653 654 current_track = (uint32_t)atoi(ptr); 655 if (track && current_track != track && track != RC_HASH_CDTRACK_FIRST_DATA) 656 continue; 657 658 while (isdigit((unsigned char)*ptr)) 659 ++ptr; 660 ++ptr; 661 662 while (isspace((unsigned char)*ptr)) 663 ++ptr; 664 665 lba = atoi(ptr); 666 while (isdigit((unsigned char)*ptr)) 667 ++ptr; 668 ++ptr; 669 670 while (isspace((unsigned char)*ptr)) 671 ++ptr; 672 673 track_type = atoi(ptr); 674 while (isdigit((unsigned char)*ptr)) 675 ++ptr; 676 ++ptr; 677 678 while (isspace((unsigned char)*ptr)) 679 ++ptr; 680 681 ptr2 = sector_size; 682 while (isdigit((unsigned char)*ptr)) 683 *ptr2++ = *ptr++; 684 *ptr2 = '\0'; 685 ++ptr; 686 687 while (isspace((unsigned char)*ptr)) 688 ++ptr; 689 690 ptr2 = file; 691 if (*ptr == '\"') 692 { 693 ++ptr; 694 while (*ptr != '\"') 695 *ptr2++ = *ptr++; 696 ++ptr; 697 } 698 else 699 { 700 while (*ptr != ' ') 701 *ptr2++ = *ptr++; 702 } 703 *ptr2 = '\0'; 704 705 if (track == current_track) 706 { 707 found = 1; 708 break; 709 } 710 else if (track == RC_HASH_CDTRACK_FIRST_DATA && track_type == 4) 711 { 712 track = current_track; 713 found = 1; 714 break; 715 } 716 else if (track == RC_HASH_CDTRACK_LARGEST && track_type == 4) 717 { 718 track_size = cdreader_get_bin_size(path, file); 719 if (track_size > largest_track_size) 720 { 721 largest_track_size = track_size; 722 largest_track = current_track; 723 largest_track_lba = lba; 724 strcpy_s(largest_track_file, sizeof(largest_track_file), file); 725 strcpy_s(largest_track_sector_size, sizeof(largest_track_sector_size), sector_size); 726 } 727 } 728 } 729 730 if (found) 731 break; 732 733 file_offset += (ptr - buffer); 734 rc_file_seek(file_handle, file_offset, SEEK_SET); 735 736 } while (1); 737 738 rc_file_close(file_handle); 739 740 cdrom = (struct cdrom_t*)calloc(1, sizeof(*cdrom)); 741 if (!cdrom) 742 { 743 snprintf((char*)buffer, sizeof(buffer), "Failed to allocate %u bytes", (unsigned)sizeof(*cdrom)); 744 rc_hash_error((const char*)buffer); 745 return NULL; 746 } 747 748 /* if we were tracking the largest track, make it the current track. 749 * otherwise, current_track will be the requested track, or last track. */ 750 if (largest_track != 0 && largest_track != current_track) 751 { 752 current_track = largest_track; 753 strcpy_s(file, sizeof(file), largest_track_file); 754 strcpy_s(sector_size, sizeof(sector_size), largest_track_sector_size); 755 lba = largest_track_lba; 756 } 757 758 /* open the bin file for the track - construct mode parameter from sector_size */ 759 ptr = &mode[6]; 760 ptr2 = sector_size; 761 while (*ptr2 && *ptr2 != '\"') 762 *ptr++ = *ptr2++; 763 *ptr = '\0'; 764 765 bin_path = cdreader_get_bin_path(path, file); 766 if (cdreader_open_bin(cdrom, bin_path, mode)) 767 { 768 cdrom->track_pregap_sectors = 0; 769 cdrom->track_first_sector = lba; 770 #ifndef NDEBUG 771 cdrom->track_id = current_track; 772 #endif 773 774 if (verbose_message_callback) 775 { 776 snprintf((char*)buffer, sizeof(buffer), "Opened track %d (sector size %d)", current_track, cdrom->sector_size); 777 verbose_message_callback((const char*)buffer); 778 } 779 } 780 else 781 { 782 snprintf((char*)buffer, sizeof(buffer), "Could not open %s", bin_path); 783 rc_hash_error((const char*)buffer); 784 785 free(cdrom); 786 cdrom = NULL; 787 } 788 789 free(bin_path); 790 791 return cdrom; 792 } 793 794 static void* cdreader_open_track(const char* path, uint32_t track) 795 { 796 /* backwards compatibility - 0 used to mean largest */ 797 if (track == 0) 798 track = RC_HASH_CDTRACK_LARGEST; 799 800 if (rc_path_compare_extension(path, "cue")) 801 return cdreader_open_cue_track(path, track); 802 if (rc_path_compare_extension(path, "gdi")) 803 return cdreader_open_gdi_track(path, track); 804 805 return cdreader_open_bin_track(path, track); 806 } 807 808 static size_t cdreader_read_sector(void* track_handle, uint32_t sector, void* buffer, size_t requested_bytes) 809 { 810 int64_t sector_start; 811 size_t num_read, total_read = 0; 812 uint8_t* buffer_ptr = (uint8_t*)buffer; 813 814 struct cdrom_t* cdrom = (struct cdrom_t*)track_handle; 815 if (!cdrom) 816 return 0; 817 818 if (sector < (uint32_t)cdrom->track_first_sector) 819 return 0; 820 821 sector_start = (int64_t)(sector - cdrom->track_first_sector) * cdrom->sector_size + 822 cdrom->sector_header_size + cdrom->file_track_offset; 823 824 while (requested_bytes > (size_t)cdrom->raw_data_size) 825 { 826 rc_file_seek(cdrom->file_handle, sector_start, SEEK_SET); 827 num_read = rc_file_read(cdrom->file_handle, buffer_ptr, cdrom->raw_data_size); 828 total_read += num_read; 829 830 if (num_read < (size_t)cdrom->raw_data_size) 831 return total_read; 832 833 buffer_ptr += cdrom->raw_data_size; 834 sector_start += cdrom->sector_size; 835 requested_bytes -= cdrom->raw_data_size; 836 } 837 838 rc_file_seek(cdrom->file_handle, sector_start, SEEK_SET); 839 num_read = rc_file_read(cdrom->file_handle, buffer_ptr, (int)requested_bytes); 840 total_read += num_read; 841 842 return total_read; 843 } 844 845 static void cdreader_close_track(void* track_handle) 846 { 847 struct cdrom_t* cdrom = (struct cdrom_t*)track_handle; 848 if (cdrom) 849 { 850 if (cdrom->file_handle) 851 rc_file_close(cdrom->file_handle); 852 853 free(track_handle); 854 } 855 } 856 857 static uint32_t cdreader_first_track_sector(void* track_handle) 858 { 859 struct cdrom_t* cdrom = (struct cdrom_t*)track_handle; 860 if (cdrom) 861 return cdrom->track_first_sector + cdrom->track_pregap_sectors; 862 863 return 0; 864 } 865 866 void rc_hash_get_default_cdreader(struct rc_hash_cdreader* cdreader) 867 { 868 cdreader->open_track = cdreader_open_track; 869 cdreader->read_sector = cdreader_read_sector; 870 cdreader->close_track = cdreader_close_track; 871 cdreader->first_track_sector = cdreader_first_track_sector; 872 } 873 874 void rc_hash_init_default_cdreader(void) 875 { 876 struct rc_hash_cdreader cdreader; 877 rc_hash_get_default_cdreader(&cdreader); 878 rc_hash_init_custom_cdreader(&cdreader); 879 }