From 7ad3b810582c23eb12375c6ce804d263a4b5d8fd Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 2 Jan 2025 22:38:10 +0100 Subject: [PATCH] Rewritten the CD-ROM image handling and Cue sheet parsing, also fixes crashes when using VISO. --- src/cdrom/cdrom_image.c | 83 +- src/cdrom/cdrom_image_backend.c | 1594 +++++++++++------------ src/cdrom/cdrom_image_viso.c | 4 +- src/cdrom/cdrom_ioctl.c | 9 - src/include/86box/cdrom.h | 1 - src/include/86box/cdrom_image_backend.h | 80 +- src/include/86box/plat_cdrom.h | 1 - src/qt/dummy_cdrom_ioctl.c | 17 - src/qt/win_cdrom_ioctl.c | 20 - src/unix/dummy_cdrom_ioctl.c | 17 - 10 files changed, 858 insertions(+), 968 deletions(-) diff --git a/src/cdrom/cdrom_image.c b/src/cdrom/cdrom_image.c index f74e0d344..0c7870902 100644 --- a/src/cdrom/cdrom_image.c +++ b/src/cdrom/cdrom_image.c @@ -58,26 +58,32 @@ cdrom_image_log(const char *fmt, ...) of the audio while audio still plays. With an absolute conversion, the counter is fine. */ #define MSFtoLBA(m, s, f) ((((m * 60) + s) * 75) + f) -static void -image_get_tracks(cdrom_t *dev, int *first, int *last) -{ - cd_img_t *img = (cd_img_t *) dev->local; - TMSF tmsf; - - cdi_get_audio_tracks(img, first, last, &tmsf); -} - static void image_get_track_info(cdrom_t *dev, uint32_t track, int end, track_info_t *ti) { cd_img_t *img = (cd_img_t *) dev->local; - TMSF tmsf; + track_t *ct = NULL; - cdi_get_audio_track_info(img, end, track, &ti->number, &tmsf, &ti->attr); + for (int i = 0; i < img->tracks_num; i++) { + ct = &(img->tracks[i]); + if (ct->point == track) + break; + } - ti->m = tmsf.min; - ti->s = tmsf.sec; - ti->f = tmsf.fr; + ti->number = ct->point; + + if (ct == NULL) { + ti->attr = 0x14; + ti->m = 0; + ti->s = 2; + ti->f = 0; + } else { + uint32_t pos = end ? ct->idx[1].start : (ct->idx[1].start + ct->idx[1].length); + ti->attr = ct->attr; + ti->m = (pos / 75) / 60; + ti->s = (pos / 75) % 60; + ti->f = pos % 75; + } } static void @@ -113,24 +119,22 @@ static int image_get_capacity(cdrom_t *dev) { cd_img_t *img = (cd_img_t *) dev->local; - int first_track; - int last_track; - int number; - unsigned char attr; - uint32_t address = 0; uint32_t lb = 0; + track_t *lo = NULL; if (!img) return 0; - cdi_get_audio_tracks_lba(img, &first_track, &last_track, &lb); - - for (int c = 0; c <= last_track; c++) { - cdi_get_audio_track_info_lba(img, 0, c + 1, &number, &address, &attr); - if (address > lb) - lb = address; + for (int i = (img->tracks_num - 1); i >= 0; i--) { + if (img->tracks[i].point == 0xa2) { + lo = &(img->tracks[i]); + break; + } } + if (lo != NULL) + lb = lo->idx[1].start - 1; + return lb; } @@ -138,13 +142,9 @@ static int image_is_track_audio(cdrom_t *dev, uint32_t pos, int ismsf) { cd_img_t *img = (cd_img_t *) dev->local; - uint8_t attr; - TMSF tmsf; int m; int s; int f; - int number; - int track; if (!img || (dev->cd_status == CD_STATUS_DATA_ONLY)) return 0; @@ -156,29 +156,18 @@ image_is_track_audio(cdrom_t *dev, uint32_t pos, int ismsf) pos = MSFtoLBA(m, s, f) - 150; } - /* GetTrack requires LBA. */ - track = cdi_get_track(img, pos); - if (track == -1) - return 0; - else { - cdi_get_audio_track_info(img, 0, track, &number, &tmsf, &attr); - return attr == AUDIO_TRACK; - } + return cdi_is_audio(img, pos); } static int image_is_track_pre(cdrom_t *dev, uint32_t lba) { cd_img_t *img = (cd_img_t *) dev->local; - int track; - /* GetTrack requires LBA. */ - track = cdi_get_track(img, lba); + if (!img || (dev->cd_status == CD_STATUS_DATA_ONLY)) + return 0; - if (track != -1) - return cdi_get_audio_track_pre(img, track); - - return 0; + return cdi_is_pre(img, lba); } static int @@ -238,7 +227,6 @@ image_exit(cdrom_t *dev) } static const cdrom_ops_t cdrom_image_ops = { - image_get_tracks, image_get_track_info, image_get_raw_track_info, image_get_subchannel, @@ -270,14 +258,13 @@ cdrom_image_open(cdrom_t *dev, const char *fn) strcpy(dev->image_path, fn); /* Create new instance of the CDROM_Image class. */ - img = (cd_img_t *) malloc(sizeof(cd_img_t)); + img = (cd_img_t *) calloc(1, sizeof(cd_img_t)); /* This guarantees that if ops is not NULL, then neither is the image pointer. */ - if (!img) + if (img == NULL) return image_open_abort(dev); - memset(img, 0, sizeof(cd_img_t)); dev->local = img; /* Open the image. */ diff --git a/src/cdrom/cdrom_image_backend.c b/src/cdrom/cdrom_image_backend.c index fdc4f662f..3c09cb56c 100644 --- a/src/cdrom/cdrom_image_backend.c +++ b/src/cdrom/cdrom_image_backend.c @@ -6,20 +6,15 @@ * * This file is part of the 86Box distribution. * - * CD-ROM image file handling module, translated to C from - * cdrom_dosbox.cpp. - * - * + * CD-ROM image file handling module. * * Authors: Miran Grca, - * Fred N. van Kempen, - * The DOSBox Team, + * RichardG, * Cacodemon345 * - * Copyright 2016-2020 Miran Grca. - * Copyright 2017-2020 Fred N. van Kempen. - * Copyright 2002-2020 The DOSBox Team. - * Copyright 2024 Cacodemon345. + * Copyright 2016-2025 Miran Grca. + * Copyright 2016-2025 Miran Grca. + * Copyright 2024-2025 Cacodemon345. */ #define __STDC_FORMAT_MACROS #include @@ -278,285 +273,137 @@ bin_init(const char *filename, int *error) } static track_file_t * -track_file_init(const char *filename, int *error) +track_file_init(const char *filename, int *error, int *is_viso) { + track_file_t *tf; + + *is_viso = 0; + /* Current we only support .BIN files, either combined or one per track. In the future, more is planned. */ - return bin_init(filename, error); -} + tf = bin_init(filename, error); -static void -track_file_close(track_t *trk) -{ - if (trk == NULL) - return; + if (*error) { + if ((tf != NULL) && (tf->close != NULL)) { + tf->close(tf); + tf = NULL; + } - if (trk->file == NULL) - return; + tf = viso_init(filename, error); - if (trk->file->close == NULL) - return; - - trk->file->close(trk->file); - trk->file = NULL; -} - -/* Root functions. */ -static void -cdi_clear_tracks(cd_img_t *cdi) -{ - const track_file_t *last = NULL; - track_t *cur = NULL; - - if ((cdi->tracks == NULL) || (cdi->tracks_num == 0)) - return; - - for (int i = 0; i < cdi->tracks_num; i++) { - cur = &cdi->tracks[i]; - - /* Make sure we do not attempt to close a NULL file. */ - if (cur->file != last) { - last = cur->file; - track_file_close(cur); - } else - cur->file = NULL; + if (!*error) + *is_viso = 1; } - /* Now free the array. */ - free(cdi->tracks); - cdi->tracks = NULL; - - /* Mark that there's no tracks. */ - cdi->tracks_num = 0; + return tf; } -void -cdi_close(cd_img_t *cdi) +static void +index_file_close(track_index_t *idx) { - cdi_clear_tracks(cdi); - free(cdi); -} + if (idx == NULL) + return; -int -cdi_set_device(cd_img_t *cdi, const char *path) -{ - int ret; + if (idx->file == NULL) + return; - if ((ret = cdi_load_cue(cdi, path))) - return ret; + if (idx->file->close == NULL) + return; - if ((ret = cdi_load_iso(cdi, path))) - return ret; - - return 0; -} - -void -cdi_get_audio_tracks(cd_img_t *cdi, int *st_track, int *end, TMSF *lead_out) -{ - *st_track = 1; - *end = cdi->tracks_num - 1; - FRAMES_TO_MSF(cdi->tracks[*end].start + 150, &lead_out->min, &lead_out->sec, &lead_out->fr); -} - -void -cdi_get_audio_tracks_lba(cd_img_t *cdi, int *st_track, int *end, uint32_t *lead_out) -{ - *st_track = 1; - *end = cdi->tracks_num - 1; - *lead_out = cdi->tracks[*end].start; -} - -int -cdi_get_audio_track_pre(cd_img_t *cdi, int track) -{ - const track_t *trk = &cdi->tracks[track - 1]; - - if ((track < 1) || (track > cdi->tracks_num)) - return 0; - - return trk->pre; -} - -/* This replaces both Info and EndInfo, they are specified by a variable. */ -int -cdi_get_audio_track_info(cd_img_t *cdi, UNUSED(int end), int track, int *track_num, TMSF *start, uint8_t *attr) -{ - const track_t *trk = &cdi->tracks[track - 1]; - // const int pos = trk->start + 150; - const int pos = trk->indexes[1].start; - - if ((track < 1) || (track > cdi->tracks_num)) - return 0; - - FRAMES_TO_MSF(pos, &start->min, &start->sec, &start->fr); - - *track_num = trk->track_number; - *attr = trk->attr; - - return 1; -} - -int -cdi_get_audio_track_info_lba(cd_img_t *cdi, UNUSED(int end), int track, int *track_num, uint32_t *start, uint8_t *attr) -{ - const track_t *trk = &cdi->tracks[track - 1]; - - if ((track < 1) || (track > cdi->tracks_num)) - return 0; - - *start = (uint32_t) trk->start; - // *start = (uint32_t) trk->indexes[1].start - 150ULL; - - *track_num = trk->track_number; - *attr = trk->attr; - - return 1; + idx->file->close(idx->file); + idx->file = NULL; } void cdi_get_raw_track_info(cd_img_t *cdi, int *num, uint8_t *buffer) { - TMSF tmsf; - int track_num = 0; - uint8_t attr = 0; - int len = 0; - int first_track; - int last_track; + int len = 0; - cdi_get_audio_tracks(cdi, &first_track, &last_track, &tmsf); + cdrom_image_backend_log("cdi->tracks_num = %i\n", cdi->tracks_num); - *num = last_track + 3; - - cdi_get_audio_track_info(cdi, 0, 1, &track_num, &tmsf, &attr); - - buffer[len++] = 1; /* Session number */ - buffer[len++] = attr; /* Track ADR and Control */ - buffer[len++] = 0; /* TNO (always 0) */ - buffer[len++] = 0xA0; /* Point (for track points - track number) */ - buffer[len++] = 0; - buffer[len++] = 0; - buffer[len++] = 0; - buffer[len++] = 0; - buffer[len++] = track_num; /* First track number */ - buffer[len++] = 0; - buffer[len++] = 0; - - cdi_get_audio_track_info(cdi, 0, last_track, &track_num, &tmsf, &attr); - - buffer[len++] = 1; /* Session number */ - buffer[len++] = attr; /* Track ADR and Control */ - buffer[len++] = 0; /* TNO (always 0) */ - buffer[len++] = 0xA1; /* Point (for track points - track number) */ - buffer[len++] = 0; - buffer[len++] = 0; - buffer[len++] = 0; - buffer[len++] = 0; - buffer[len++] = track_num; /* Last track number */ - buffer[len++] = 0; - buffer[len++] = 0; - - cdi_get_audio_track_info(cdi, 0, last_track + 1, &track_num, &tmsf, &attr); - - cdrom_image_backend_log(" tracks(%i) = %02X, %02X, %02i:%02i.%02i\n", last_track, attr, - track_num, tmsf.min, tmsf.sec, tmsf.fr); - - buffer[len++] = 1; /* Session number */ - buffer[len++] = attr; /* Track ADR and Control */ - buffer[len++] = 0; /* TNO (always 0) */ - buffer[len++] = 0xA2; /* Point (for track points - track number) */ - buffer[len++] = 0; - buffer[len++] = 0; - buffer[len++] = 0; - buffer[len++] = 0; - buffer[len++] = tmsf.min; /* PM */ - buffer[len++] = tmsf.sec; /* PS */ - buffer[len++] = tmsf.fr; /* PF */ - - for (int i = 0; i < last_track; i++) { - cdi_get_audio_track_info(cdi, 0, i + 1, &track_num, &tmsf, &attr); - - cdrom_image_backend_log(" tracks(%i) = %02X, %02X, %02i:%02i.%02i\n", i, attr, - track_num, tmsf.min, tmsf.sec, tmsf.fr); - - buffer[len++] = 1; /* Session number */ - buffer[len++] = attr; /* Track ADR and Control */ - buffer[len++] = 0; /* TNO (always 0) */ - buffer[len++] = track_num; /* Point (for track points - track number) */ - /* Yes, this is correct - MSF followed by PMSF, the actual position is in PMSF. */ - buffer[len++] = 0; - buffer[len++] = 0; - buffer[len++] = 0; - buffer[len++] = 0; - buffer[len++] = tmsf.min; /* PM */ - buffer[len++] = tmsf.sec; /* PS */ - buffer[len++] = tmsf.fr; /* PF */ + for (int i = 0; i < cdi->tracks_num; i++) { + track_t *ct = &(cdi->tracks[i]); +#ifdef ENABLE_CDROM_IMAGE_BACKEND_LOG + int old_len = len; +#endif + buffer[len++] = ct->session; /* Session number */ + buffer[len++] = ct->attr; /* Track ADR and Control */ + buffer[len++] = ct->tno; /* TNO (always 0) */ + buffer[len++] = ct->point; /* Point (for track points - track number) */ + for (int j = 0; j < 4; j++) + buffer[len++] = ct->extra[j]; + buffer[len++] = (ct->idx[1].start / 75) / 60; + buffer[len++] = (ct->idx[1].start / 75) % 60; + buffer[len++] = ct->idx[1].start % 75; + cdrom_image_backend_log("%i: %02X %02X %02X %02X %02X %02X %02X\n", i, + buffer[old_len], buffer[old_len + 1], buffer[old_len + 2], buffer[old_len + 3], + buffer[old_len + 8], buffer[old_len + 9], buffer[old_len + 10]); } + + *num = cdi->tracks_num; } -int +static int cdi_get_track(cd_img_t *cdi, uint32_t sector) { - /* There must be at least two tracks - data and lead out. */ - if (cdi->tracks_num < 2) - return -1; + int ret = -1; - /* This has a problem - the code skips the last track, which is - lead out - is that correct? */ - for (int i = 0; i < (cdi->tracks_num - 1); i++) { - const track_t *cur = &cdi->tracks[i]; - const track_t *next = &cdi->tracks[i + 1]; - - /* Take into account cue sheets that do not start on sector 0. */ - // if ((i == 0) && (sector < cur->start)) - if ((i == 0) && (sector < cur->indexes[0].start)) - return cur->number; - - // if ((cur->start <= sector) && (sector < next->start)) - if ((cur->indexes[0].start <= sector) && (sector < next->indexes[0].start)) - return cur->number; + for (int i = 0; i < cdi->tracks_num; i++) { + track_t *ct = &(cdi->tracks[i]); + for (int j = 0; j < 3; j++) { + track_index_t *ci = &(ct->idx[j]); + if (((sector + 150) >= ci->start) && ((sector + 150) <= (ci->start + ci->length - 1))) { + ret = i; + break; + } + } } - return -1; + return ret; +} + +static void +cdi_get_track_and_index(cd_img_t *cdi, uint32_t sector, int *track, int *index) +{ + *track = -1; + *index = -1; + + for (int i = 0; i < cdi->tracks_num; i++) { + track_t *ct = &(cdi->tracks[i]); + for (int j = 0; j < 3; j++) { + track_index_t *ci = &(ct->idx[j]); + if (((sector + 150) >= ci->start) && ((sector + 150) <= (ci->start + ci->length - 1))) { + *track = i; + *index = j; + break; + } + } + } } /* TODO: See if track start is adjusted by 150 or not. */ int cdi_get_audio_sub(cd_img_t *cdi, uint32_t sector, uint8_t *attr, uint8_t *track, uint8_t *index, TMSF *rel_pos, TMSF *abs_pos) { - const int cur_track = cdi_get_track(cdi, sector); + int cur_track = cdi_get_track(cdi, sector); if (cur_track < 1) return 0; *track = (uint8_t) cur_track; - const track_t *trk = &cdi->tracks[*track - 1]; + const track_t *trk = &cdi->tracks[*track]; *attr = trk->attr; *index = 1; + /* Absolute position should be adjusted by 150, not the relative ones. */ FRAMES_TO_MSF(sector + 150, &abs_pos->min, &abs_pos->sec, &abs_pos->fr); - /* Absolute position should be adjusted by 150, not the relative ones. */ - // FRAMES_TO_MSF(sector - trk->start, &rel_pos->min, &rel_pos->sec, &rel_pos->fr); /* Relative position is relative Index 1 start - pre-gap values will be negative. */ - FRAMES_TO_MSF((int32_t) (sector + 150 - trk->indexes[1].start), &rel_pos->min, &rel_pos->sec, &rel_pos->fr); + FRAMES_TO_MSF((int32_t) (sector + 150 - trk->idx[1].start), &rel_pos->min, &rel_pos->sec, &rel_pos->fr); return 1; } -static int -cdi_get_sector_index(const track_t *trk, const uint32_t sector) -{ - int ret = 1; - - if ((sector + 150) < trk->indexes[1].start) - ret = 0; - else if ((sector + 150) >= trk->indexes[2].start) - ret = 2; - - return ret; -} - static __inline int bin2bcd(int x) { @@ -566,34 +413,37 @@ bin2bcd(int x) int cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector) { - const int track = cdi_get_track(cdi, sector) - 1; - const uint64_t sect = (uint64_t) sector; + const uint64_t sect = (uint64_t) sector; + int m = 0; + int s = 0; + int f = 0; + int ret = 0; + uint64_t offset = 0ULL; + int track; + int index; int raw_size; int cooked_size; - uint64_t offset; - int m = 0; - int s = 0; - int f = 0; - int ret = 0; uint8_t q[16] = { 0x00 }; + cdi_get_track_and_index(cdi, sector, &track, &index); + if (track < 0) return 0; - const track_t *trk = &cdi->tracks[track]; - const int track_is_raw = ((trk->sector_size == RAW_SECTOR_SIZE) || (trk->sector_size == 2448)); - - const uint64_t seek = trk->skip + ((sect - trk->start) * trk->sector_size); - const int index = cdi_get_sector_index(trk, sector); + const track_t *trk = &(cdi->tracks[track]); + const track_index_t *idx = &(trk->idx[index]); + const int track_is_raw = ((trk->sector_size == RAW_SECTOR_SIZE) || (trk->sector_size == 2448)); + const uint64_t seek = (sect + 150 - idx->start + idx->file_start) * trk->sector_size; + cdrom_image_backend_log("cdrom_read_sector(%08X): track %02X, index %02X, %016" PRIX64 ", %016" PRIX64 ", %i\n", - sector, track, index, trk->skip, trk->start, trk->sector_size); + sector, track, index, trk->start, trk->sector_size); if (track_is_raw) raw_size = trk->sector_size; else raw_size = 2448; - if (trk->mode2 && (trk->form != 1)) { + if ((trk->mode == 2) && (trk->form != 1)) { if (trk->form == 2) cooked_size = (track_is_raw ? 2328 : trk->sector_size); /* Both 2324 + ECC and 2328 variants are valid. */ else @@ -601,14 +451,12 @@ cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector) } else cooked_size = COOKED_SECTOR_SIZE; - const size_t length = (raw ? raw_size : cooked_size); - - if (trk->mode2 && (trk->form >= 1)) + if ((trk->mode == 2) && (trk->form >= 1)) offset = 24ULL; else offset = 16ULL; - if (!trk->indexes[index].in_file) { + if (idx->type < INDEX_NORMAL) { memset(buffer, 0x00, 2448); if (trk->attr & 0x04) { /* Construct the rest of the raw sector. */ @@ -620,12 +468,13 @@ cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector) buffer[1] = CDROM_BCD(s & 0xff); buffer[2] = CDROM_BCD(f & 0xff); /* Data, should reflect the actual sector type. */ - buffer[3] = trk->mode2 ? 2 : 1; + buffer[3] = trk->mode; ret = 1; } } else if (raw && !track_is_raw) { memset(buffer, 0x00, 2448); - const int temp = trk->file->read(trk->file, buffer + offset, seek, length); + /* We are doing a raw read but the track is cooked, length should be cooked size. */ + const int temp = idx->file->read(idx->file, buffer + offset, seek, cooked_size); if (temp <= 0) return temp; if (trk->attr & 0x04) { @@ -638,23 +487,29 @@ cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector) buffer[1] = CDROM_BCD(s & 0xff); buffer[2] = CDROM_BCD(f & 0xff); /* Data, should reflect the actual sector type. */ - buffer[3] = trk->mode2 ? 2 : 1; + buffer[3] = trk->mode; ret = 1; } } else if (!raw && track_is_raw) - return trk->file->read(trk->file, buffer, seek + offset, length); + /* The track is raw but we are doing a cooked read, length should be cooked size. */ + return idx->file->read(idx->file, buffer, seek + offset, cooked_size); else { - ret = trk->file->read(trk->file, buffer, seek, length); + /* The track is raw and we are doing a raw read, length should be raw size. */ + ret = idx->file->read(idx->file, buffer, seek, raw_size); if (raw && (raw_size == 2448)) return ret; } /* Construct Q. */ q[0] = (trk->attr >> 4) | ((trk->attr & 0xf) << 4); - q[1] = bin2bcd(trk->track_number); - q[2] = 1; /* TODO: Index number. */ - // FRAMES_TO_MSF(sector - trk->start, &m, &s, &f); - FRAMES_TO_MSF((int32_t) (sector + 150 - trk->indexes[1].start), &m, &s, &f); + q[1] = bin2bcd(trk->point); + q[2] = index; + if (index == 0) { + /* Pre-gap sector relative frame addresses count from 00:01:74 downwards. */ + FRAMES_TO_MSF((int32_t) (149 - (sector + 150 - idx->start)), &m, &s, &f); + } else { + FRAMES_TO_MSF((int32_t) (sector + 150 - idx->start), &m, &s, &f); + } q[3] = bin2bcd(m); q[4] = bin2bcd(s); q[5] = bin2bcd(f); @@ -671,85 +526,90 @@ cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector) return ret; } -int -cdi_read_sectors(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector, uint32_t num) -{ - int success = 1; - - /* TODO: This fails to account for Mode 2. Shouldn't we have a function - to get sector size? */ - const int sector_size = raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE; - const uint32_t buf_len = num * sector_size; - uint8_t *buf = (uint8_t *) calloc(1, buf_len * sizeof(uint8_t)); - - for (uint32_t i = 0; i < num; i++) { - success = cdi_read_sector(cdi, &buf[i * sector_size], raw, sector + i); - if (success <= 0) - break; - /* Based on the DOSBox patch, but check all 8 bytes and makes sure it's not an - audio track. */ - if (raw && (sector < cdi->tracks[0].length) && !cdi->tracks[0].mode2 && (cdi->tracks[0].attr != AUDIO_TRACK) && *(uint64_t *) &(buf[(i * sector_size) + 2068])) - return 0; - } - - memcpy((void *) buffer, buf, buf_len); - free(buf); - buf = NULL; - - return success; -} - /* TODO: Do CUE+BIN images with a sector size of 2448 even exist? */ int cdi_read_sector_sub(cd_img_t *cdi, uint8_t *buffer, uint32_t sector) { - const int track = cdi_get_track(cdi, sector) - 1; + int track; + int index; + + cdi_get_track_and_index(cdi, sector, &track, &index); if (track < 0) return 0; - const track_t *trk = &cdi->tracks[track]; - const uint64_t seek = trk->skip + (((uint64_t) sector - trk->start) * trk->sector_size); - if (trk->sector_size != 2448) + const track_t *trk = &(cdi->tracks[track]); + const track_index_t *idx = &(trk->idx[index]); + + const uint64_t seek = (((uint64_t) sector + 150 - idx->start + idx->file_start) * trk->sector_size); + + if ((idx->type < INDEX_NORMAL) && (trk->sector_size != 2448)) return 0; - return trk->file->read(trk->file, buffer, seek, 2448); + return idx->file->read(idx->file, buffer, seek, 2448); } int cdi_get_sector_size(cd_img_t *cdi, uint32_t sector) { - const int track = cdi_get_track(cdi, sector) - 1; + int track = cdi_get_track(cdi, sector); if (track < 0) return 0; - const track_t *trk = &cdi->tracks[track]; + const track_t *trk = &(cdi->tracks[track]); + return trk->sector_size; } +int +cdi_is_audio(cd_img_t *cdi, uint32_t sector) +{ + int track = cdi_get_track(cdi, sector); + + if (track < 0) + return 0; + + const track_t *trk = &(cdi->tracks[track]); + + return !!(trk->mode == 0); +} + +int +cdi_is_pre(cd_img_t *cdi, uint32_t sector) +{ + int track = cdi_get_track(cdi, sector); + + if (track < 0) + return 0; + + const track_t *trk = &(cdi->tracks[track]); + + return !!(trk->attr & 0x01); +} + int cdi_is_mode2(cd_img_t *cdi, uint32_t sector) { - const int track = cdi_get_track(cdi, sector) - 1; + int track = cdi_get_track(cdi, sector); if (track < 0) return 0; - const track_t *trk = &cdi->tracks[track]; + const track_t *trk = &(cdi->tracks[track]); - return !!(trk->mode2); + return !!(trk->mode == 2); } int cdi_get_mode2_form(cd_img_t *cdi, uint32_t sector) { - const int track = cdi_get_track(cdi, sector) - 1; + int track = cdi_get_track(cdi, sector); if (track < 0) return 0; - const track_t *trk = &cdi->tracks[track]; + const track_t *trk = &(cdi->tracks[track]); return trk->form; } @@ -773,133 +633,6 @@ cdi_can_read_pvd(track_file_t *file, uint64_t sector_size, int mode2, int form) return ((pvd[0] == 1 && !strncmp((char *) (&pvd[1]), "CD001", 5) && pvd[6] == 1) || (pvd[8] == 1 && !strncmp((char *) (&pvd[9]), "CDROM", 5) && pvd[14] == 1)); } -/* This reallocates the array and returns the pointer to the last track. */ -static void -cdi_track_push_back(cd_img_t *cdi, track_t *trk) -{ - /* This has to be done so situations in which realloc would misbehave - can be detected and reported to the user. */ - if ((cdi->tracks != NULL) && (cdi->tracks_num == 0)) - fatal("CD-ROM Image: Non-null tracks array at 0 loaded tracks\n"); - if ((cdi->tracks == NULL) && (cdi->tracks_num != 0)) - fatal("CD-ROM Image: Null tracks array at non-zero loaded tracks\n"); - - cdi->tracks = realloc(cdi->tracks, (cdi->tracks_num + 1) * sizeof(track_t)); - memcpy(&(cdi->tracks[cdi->tracks_num]), trk, sizeof(track_t)); - cdi->tracks_num++; -} - -int -cdi_get_iso_track(cd_img_t *cdi, track_t *trk, const char *filename) -{ - int error = 0; - int ret = 2; - memset(trk, 0, sizeof(track_t)); - - /* Data track (shouldn't there be a lead in track?). */ - trk->file = bin_init(filename, &error); - if (error) { - if ((trk->file != NULL) && (trk->file->close != NULL)) - trk->file->close(trk->file); - ret = 3; - trk->file = viso_init(filename, &error); - if (error) { - if ((trk->file != NULL) && (trk->file->close != NULL)) - trk->file->close(trk->file); - return 0; - } - } - trk->number = 1; - trk->track_number = 1; - trk->attr = DATA_TRACK; - - /* Try to detect ISO type. */ - trk->form = 0; - trk->mode2 = 0; - - if (cdi_can_read_pvd(trk->file, RAW_SECTOR_SIZE, 0, 0)) - trk->sector_size = RAW_SECTOR_SIZE; - else if (cdi_can_read_pvd(trk->file, 2336, 1, 0)) { - trk->sector_size = 2336; - trk->mode2 = 1; - } else if (cdi_can_read_pvd(trk->file, 2324, 1, 2)) { - trk->sector_size = 2324; - trk->mode2 = 1; - trk->form = 2; - trk->noskip = 1; - } else if (cdi_can_read_pvd(trk->file, 2328, 1, 2)) { - trk->sector_size = 2328; - trk->mode2 = 1; - trk->form = 2; - trk->noskip = 1; - } else if (cdi_can_read_pvd(trk->file, 2336, 1, 1)) { - trk->sector_size = 2336; - trk->mode2 = 1; - trk->form = 1; - trk->skip = 8; - } else if (cdi_can_read_pvd(trk->file, RAW_SECTOR_SIZE, 1, 0)) { - trk->sector_size = RAW_SECTOR_SIZE; - trk->mode2 = 1; - } else if (cdi_can_read_pvd(trk->file, RAW_SECTOR_SIZE, 1, 1)) { - trk->sector_size = RAW_SECTOR_SIZE; - trk->mode2 = 1; - trk->form = 1; - } else { - /* We use 2048 mode 1 as the default. */ - trk->sector_size = COOKED_SECTOR_SIZE; - } - - trk->length = trk->file->get_length(trk->file) / trk->sector_size; - - trk->indexes[0].in_file = 0; - trk->indexes[0].start = 0; - trk->indexes[0].length = 150; - trk->indexes[1].in_file = 1; - trk->indexes[1].start = 150; - trk->indexes[1].length = trk->length; - trk->indexes[2].in_file = 0; - trk->indexes[2].start = trk->length + 150; - trk->indexes[2].length = 0; - - cdrom_image_backend_log("ISO: Data track: length = %" PRIu64 ", sector_size = %i\n", trk->length, trk->sector_size); - return ret; -} - -int -cdi_load_iso(cd_img_t *cdi, const char *filename) -{ - int ret = 2; - track_t trk = { 0 }; - - cdi->tracks = NULL; - cdi->tracks_num = 0; - - ret = cdi_get_iso_track(cdi, &trk, filename); - - if (ret >= 1) { - cdi_track_push_back(cdi, &trk); - - /* Lead out track. */ - trk.number = 2; - trk.track_number = 0xAA; - // trk.attr = 0x16; /* Was originally 0x00, but I believe 0x16 is appropriate. */ - trk.start = trk.length; - trk.file = NULL; - - for (int i = 0; i < 3; i++) { - trk.indexes[i].in_file = 0; - trk.indexes[i].start = trk.length + 150; - trk.indexes[i].length = 0; - } - - trk.length = 0; - - cdi_track_push_back(cdi, &trk); - } - - return ret; -} - static int cdi_cue_get_buffer(char *str, char **line, int up) { @@ -1020,120 +753,432 @@ cdi_cue_get_flags(track_t *cur, char **line) if (!success) return 0; - cur->pre = (strstr(temp2, "PRE") != NULL); + if (strstr(temp2, "PRE") != NULL) + cur->attr |= 0x01; + if (strstr(temp2, "DCP") != NULL) + cur->attr |= 0x02; + if (strstr(temp2, "4CH") != NULL) + cur->attr |= 0x08; return 1; } -uint64_t total_pregap = 0ULL; - -static int -cdi_add_track(cd_img_t *cdi, track_t *cur, uint64_t *shift, uint64_t prestart, uint64_t cur_pregap) +static track_t * +cdi_insert_track(cd_img_t *cdi, uint8_t session, uint8_t point) { - /* Frames between index 0 (prestart) and 1 (current track start) must be skipped. */ - track_t *prev = NULL; + track_t *ct = NULL; - /* Skip *MUST* be calculated even if prestart is 0. */ - if (prestart > cur->start) - return 0; - /* If prestart is 0, there is no skip. */ - uint64_t skip = (prestart == 0) ? 0 : (cur->start - prestart); - - if ((cdi->tracks != NULL) && (cdi->tracks_num != 0)) - prev = &cdi->tracks[cdi->tracks_num - 1]; - else if ((cdi->tracks == NULL) && (cdi->tracks_num != 0)) { - fatal("NULL cdi->tracks with non-zero cdi->tracks_num\n"); - return 0; - } - - /* First track (track number must be 1). */ - if ((prev == NULL) || (cdi->tracks_num == 0)) { - /* I guess this makes sure the structure is not filled with invalid data. */ - if (cur->number != 1) - return 0; - cur->skip = skip * cur->sector_size; - if ((cur->sector_size != RAW_SECTOR_SIZE) && (cur->form > 0) && !cur->noskip) - cur->skip += 8; - cur->start += cur_pregap; - cdi_track_push_back(cdi, cur); - return 1; - } - - if (prev->indexes[2].length != 0) { - prev->indexes[2].start = cur->indexes[0].start - prev->indexes[2].length; - prev->indexes[1].length = prev->indexes[2].start - prev->indexes[1].start; - cdrom_image_backend_log("Index 2 (%i): %02i:%02i:%02i\n", prev->indexes[2].in_file, - (int) ((prev->indexes[2].start / 75) / 60), (int) ((prev->indexes[2].start / 75) % 60), - (int) (prev->indexes[2].start % 75)); - } else if (prev->indexes[2].in_file) - prev->indexes[2].length = cur->indexes[0].start - prev->indexes[2].start; - else { - prev->indexes[1].length = cur->indexes[0].start - prev->indexes[1].start; - prev->indexes[2].start = prev->indexes[1].start + prev->indexes[1].length; - prev->indexes[2].length = 0; - cdrom_image_backend_log("Index 2 (%i): %02i:%02i:%02i\n", prev->indexes[2].in_file, - (int) ((prev->indexes[2].start / 75) / 60), (int) ((prev->indexes[2].start / 75) % 60), - (int) (prev->indexes[2].start % 75)); - } - - /* Current track consumes data from the same file as the previous. */ - if (prev->file == cur->file) { - cur->start += *shift; - prev->length = cur->start - prev->start - skip; - cur->skip += prev->skip + (prev->length * prev->sector_size) + (skip * cur->sector_size); - cur->start += cur_pregap; + cdi->tracks_num++; + if (cdi->tracks == NULL) { + cdi->tracks = calloc(1, sizeof(track_t)); + ct = &(cdi->tracks[0]); } else { - const uint64_t temp = prev->file->get_length(prev->file) - (prev->skip); - prev->length = temp / ((uint64_t) prev->sector_size); - if ((temp % prev->sector_size) != 0) - /* Padding. */ - prev->length++; + cdi->tracks = realloc(cdi->tracks, cdi->tracks_num * sizeof(track_t)); + ct = &(cdi->tracks[cdi->tracks_num - 1]); + } + cdrom_image_backend_log("%02X: cdi->tracks[%2i] = %016" PRIX64 "\n", point, cdi->tracks_num - 1, (uint64_t) ct); - cur->start += prev->start + prev->length + cur_pregap; - cur->skip = skip * cur->sector_size; - if ((cur->sector_size != RAW_SECTOR_SIZE) && (cur->form > 0) && !cur->noskip) - cur->skip += 8; - *shift += prev->start + prev->length; + memset(ct, 0x00, sizeof(track_t)); + + ct->session = session; + ct->point = point; + + for (int i = 0; i < 3; i++) + ct->idx[i].type = (point > 99) ? INDEX_SPECIAL : INDEX_NONE; + + return ct; +} + +static void +cdi_last_3_passes(cd_img_t *cdi) +{ + track_t *ct = NULL; + track_t *lt = NULL; + track_index_t *ci = NULL; + track_file_t *tf = NULL; + uint64_t tf_len = 0ULL; + uint64_t cur_pos = 0ULL; + int map[256] = { 0 }; + int lead[3] = { 0 }; + int pos = 0; + int ls = 0; + uint64_t spg[256] = { 0ULL }; + track_t *lo[256] = { 0 }; + + cdrom_image_backend_log("A2 = %016" PRIX64 "\n", (uint64_t) &(cdi->tracks[2])); + + for (int i = 0; i < cdi->tracks_num; i++) { + ct = &(cdi->tracks[i]); + if (((ct->point >= 1) && (ct->point <= 99)) || (ct->point >= 0xb0)) { + if (ct->point == 0xb0) { + /* Point B0h found, add the previous three lead tracks. */ + for (int j = 0; j < 3; j++) { + map[pos] = lead[j]; + pos++; + } + } + + map[pos] = i; + pos++; + } else if ((ct->point >= 0xa0) && (ct->point <= 0xa2)) + lead[ct->point & 0x03] = i; } - /* Error checks. */ - if (cur->number <= 1) - return 0; - if ((prev->number + 1) != cur->number) - return 0; - if (cur->start < (prev->start + prev->length)) + /* The last lead tracks. */ + for (int i = 0; i < 3; i++) { + map[pos] = lead[i]; + pos++; + } +#ifdef ENABLE_CDROM_IMAGE_BACKEND_LOG + cdrom_image_backend_log("pos = %i, cdi->tracks_num = %i\n", pos, cdi->tracks_num); + for (int i = 0; i < pos; i++) + cdrom_image_backend_log("map[%02i] = %02X\n", i, map[i]); +#endif + + cdrom_image_backend_log("Second pass:\n"); + for (int i = (cdi->tracks_num - 1); i >= 0; i--) { + ct = &(cdi->tracks[map[i]]); + if (ct->idx[1].type != INDEX_SPECIAL) { + for (int j = 2; j >= 0; j--) { + ci = &(ct->idx[j]); + + if ((ci->type >= INDEX_ZERO) && (ci->file != tf)) { + tf = ci->file; + if (tf != NULL) { + tf_len = tf->get_length(tf) / ct->sector_size; + cdrom_image_backend_log(" File length: %016" PRIX64 " sectors\n", tf_len); + } + } + + if (ci->type == INDEX_NONE) { + /* Index was not in the cue sheet, keep its length at zero. */ + ci->file_start = tf_len; + } else if (ci->type == INDEX_NORMAL) { + /* Index was in the cue sheet and is present in the file. */ + ci->file_length = tf_len - ci->file_start; + tf_len -= ci->file_length; + } + + cdrom_image_backend_log(" TRACK %2i (%2i), ATTR %02X, INDEX %i: %2i, file_start = %016" + PRIX64 " (%2i:%02i:%02i), file_length = %016" PRIX64 " (%2i:%02i:%02i)\n", + i, map[i], + ct->attr, + j, ci->type, + ci->file_start, + (int) ((ci->file_start / 75) / 60), + (int) ((ci->file_start / 75) % 60), + (int) (ci->file_start % 75), + ci->file_length, + (int) ((ci->file_length / 75) / 60), + (int) ((ci->file_length / 75) % 60), + (int) (ci->file_length % 75)); + } + } + } + + cdrom_image_backend_log("Third pass:\n"); + for (int i = 0; i < cdi->tracks_num; i++) { + int session_changed = 0; + + ct = &(cdi->tracks[map[i]]); + if (ct->idx[1].type != INDEX_SPECIAL) { + if (ct->session != ls) { + /* The first track of a session always has a pre-gap of at least 0:02:00. */ + ci = &(ct->idx[0]); + if (ci->type == INDEX_NONE) { + ci->type = INDEX_ZERO; + ci->start = 0ULL; + ci->length = 150ULL; + } + + session_changed = 1; + ls = ct->session; + } + + for (int j = 0; j < 3; j++) { + ci = &(ct->idx[j]); + + if (ci->type == INDEX_NONE) + /* Index was not in the cue sheet, keep its length at zero. */ + ci->start = cur_pos; + else if (ci->type == INDEX_ZERO) { + /* Index was in the cue sheet and is not present in the file. */ + ci->start = cur_pos; + cur_pos += ci->length; + } else if (ci->type == INDEX_NORMAL) { + /* Index was in the cue sheet and is present in the file. */ + ci->start = cur_pos; + ci->length = ci->file_length; + cur_pos += ci->file_length; + } + + cdrom_image_backend_log(" TRACK %2i (%2i) (%2i), ATTR %02X, MODE %i, INDEX %i: %2i, " + "start = %016" PRIX64 " (%2i:%02i:%02i), length = %016" PRIX64 + " (%2i:%02i:%02i)\n", + i, map[i], + ct->point, ct->attr, + ct->mode, + j, ci->type, + ci->start, + (int) ((ci->start / 75) / 60), + (int) ((ci->start / 75) % 60), + (int) (ci->start % 75), + ci->length, + (int) ((ci->length / 75) / 60), + (int) ((ci->length / 75) % 60), + (int) (ci->length % 75)); + + /* Set the pre-gap of the first track of this session. */ + if (session_changed) + spg[ct->session] = ct->idx[0].start; + } + } + } + + /* Set the lead out starts for all sessions. */ + for (int i = 0; i <= ls; i++) { + lo[i] = NULL; + for (int j = (cdi->tracks_num - 1); j >= 0; j--) { + track_t *jt = &(cdi->tracks[j]); + if ((jt->session == ct->session) && (jt->point >= 1) && (jt->point <= 99)) { + lo[i] = &(cdi->tracks[j]); + break; + } + } + } + + cdrom_image_backend_log("Fourth pass:\n"); + for (int i = 0; i < cdi->tracks_num; i++) { + ct = &(cdi->tracks[i]); + lt = NULL; + switch (ct->point) { + case 0xa0: + for (int j = 0; j < cdi->tracks_num; j++) { + track_t *jt = &(cdi->tracks[j]); + if ((jt->session == ct->session) && (jt->point >= 1) && (jt->point <= 99)) { + lt = &(cdi->tracks[j]); + break; + } + } + if (lt != NULL) { + int disc_type = 0x00; + + ct->attr = lt->attr; + + ct->mode = lt->mode; + ct->form = lt->form; + + if (lt->mode == 2) + disc_type = (lt->form > 0) ? 0x20 : 0x10; + for (int j = 0; j < 3; j++) { + ci = &(ct->idx[j]); + ci->type = INDEX_ZERO; + ci->start = (lt->point * 60 * 75) + (disc_type * 75); + ci->length = 0; + } + } + break; + case 0xa1: + for (int j = (cdi->tracks_num - 1); j >= 0; j--) { + track_t *jt = &(cdi->tracks[j]); + if ((jt->session == ct->session) && (jt->point >= 1) && (jt->point <= 99)) { + lt = &(cdi->tracks[j]); + break; + } + } + if (lt != NULL) { + ct->attr = lt->attr; + + ct->mode = lt->mode; + ct->form = lt->form; + + for (int j = 0; j < 3; j++) { + ci = &(ct->idx[j]); + ci->type = INDEX_ZERO; + ci->start = (lt->point * 60 * 75); + ci->length = 0; + } + } + break; + case 0xa2: + if (lo[ct->session] != NULL) { + lt = lo[ct->session]; + + ct->attr = lt->attr; + + ct->mode = lt->mode; + ct->form = lt->form; + + if (ct->idx[1].type != INDEX_NORMAL) { + track_index_t *li = &(lt->idx[2]); + + for (int j = 0; j < 3; j++) { + ci = &(ct->idx[j]); + ci->type = INDEX_ZERO; + ci->start = li->start + li->length; + ci->length = 0; + } + } + } + break; + case 0xb0: + /* + B0 MSF (*NOT* PMSF) points to the beginning of the pre-gap + of the corresponding session's first track. + */ + ct->extra[0] = (spg[ct->session] / 75) / 60; + ct->extra[1] = (spg[ct->session] / 75) % 60; + ct->extra[2] = spg[ct->session] % 75; + + /* + B0 PMSF points to the start of the lead out track + of the last session. + */ + if (lo[ls] != NULL) { + lt = lo[ls]; + track_index_t *li = &(lt->idx[2]); + + ct->idx[1].start = li->start + li->length; + } + break; + } + +#ifdef ENABLE_CDROM_IMAGE_BACKEND_LOG + if ((ct->point >= 0xa0) && (ct->point <= 0xa2)) + cdrom_image_backend_log(" TRACK %02X, SESSION %i: start = %016" PRIX64 " (%2i:%02i:%02i)\n", + ct->point, ct->session, + ct->idx[1].start, + (int) ((ct->idx[1].start / 75) / 60), + (int) ((ct->idx[1].start / 75) % 60), + (int) (ct->idx[1].start % 75)); +#endif + } +} + +int +cdi_load_iso(cd_img_t *cdi, const char *filename) +{ + track_t *ct = NULL; + track_index_t *ci = NULL; + track_file_t *tf = NULL; + int success; + int error = 1; + int is_viso = 0; + + cdi->tracks = NULL; + success = 1; + + cdrom_image_backend_log("First pass:\n"); + cdi->tracks_num = 0; + + cdi_insert_track(cdi, 1, 0xa0); + cdi_insert_track(cdi, 1, 0xa1); + cdi_insert_track(cdi, 1, 0xa2); + + /* Data track (shouldn't there be a lead in track?). */ + tf = track_file_init(filename, &error, &is_viso); + + if (error) { + cdrom_image_backend_log("ISO: cannot open file '%s'!\n", filename); + + if (tf != NULL) { + tf->close(tf); + tf = NULL; + } + success = 0; + } else if (is_viso) + success = 3; + + if (success) { + ct = cdi_insert_track(cdi, 1, 1); + ci = &(ct->idx[1]); + + ct->form = 0; + ct->mode = 0; + + for (int i = 0; i < 3; i++) + ct->idx[i].type = INDEX_NONE; + + ct->attr = DATA_TRACK; + + /* Try to detect ISO type. */ + ct->mode = 1; + ct->form = 0; + + ci->type = INDEX_NORMAL; + ci->file_start = 0ULL; + + ci->file = tf; + + /* For Mode 2 XA, skip the first 8 bytes in every sector when sector size = 2336. */ + if (cdi_can_read_pvd(ci->file, RAW_SECTOR_SIZE, 0, 0)) + ct->sector_size = RAW_SECTOR_SIZE; + else if (cdi_can_read_pvd(ci->file, 2336, 1, 0)) { + ct->sector_size = 2336; + ct->mode = 2; + } else if (cdi_can_read_pvd(ci->file, 2324, 1, 2)) { + ct->sector_size = 2324; + ct->mode = 2; + ct->form = 2; + } else if (cdi_can_read_pvd(ci->file, 2328, 1, 2)) { + ct->sector_size = 2328; + ct->mode = 2; + ct->form = 2; + } else if (cdi_can_read_pvd(ci->file, 2336, 1, 1)) { + ct->sector_size = 2336; + ct->mode = 2; + ct->form = 1; + ct->skip = 8; + } else if (cdi_can_read_pvd(ci->file, RAW_SECTOR_SIZE, 1, 0)) { + ct->sector_size = RAW_SECTOR_SIZE; + ct->mode = 2; + } else if (cdi_can_read_pvd(ci->file, RAW_SECTOR_SIZE, 1, 1)) { + ct->sector_size = RAW_SECTOR_SIZE; + ct->mode = 2; + ct->form = 1; + } else { + /* We use 2048 mode 1 as the default. */ + ct->sector_size = COOKED_SECTOR_SIZE; + } + + cdrom_image_backend_log("TRACK 1: Mode = %i, Form = %i, Sector size = %08X\n", + ct->mode, ct->form, ct->sector_size); + } + + tf = NULL; + + if (!success) return 0; - cdi_track_push_back(cdi, cur); + cdi_last_3_passes(cdi); - return 1; + return success; } int cdi_load_cue(cd_img_t *cdi, const char *cuefile) { - track_t trk; - char pathname[MAX_FILENAME_LENGTH]; - uint64_t shift = 0ULL; - uint64_t prestart = 0ULL; - uint64_t cur_pregap = 0ULL; - uint64_t frame = 0ULL; - uint64_t index; - int iso_file_used = 0; - int success; - int error; - int can_add_track = 0; - FILE *fp; - char buf[MAX_LINE_LENGTH]; - char *line; - char *command; - char *type; + track_t *ct = NULL; + track_index_t *ci = NULL; + track_file_t *tf = NULL; + uint64_t frame = 0ULL; + uint64_t last = 0ULL; + uint8_t session = 1; + int success; + int error; + int is_viso = 0; + int lead[3] = { 0 }; + char pathname[MAX_FILENAME_LENGTH]; + char buf[MAX_LINE_LENGTH]; + FILE *fp; + char *line; + char *command; + char *type; + char temp; cdi->tracks = NULL; cdi->tracks_num = 0; - memset(&trk, 0, sizeof(track_t)); - /* Get a copy of the filename into pathname, we need it later. */ memset(pathname, 0, MAX_FILENAME_LENGTH * sizeof(char)); path_get_dirname(pathname, cuefile); @@ -1145,11 +1190,20 @@ cdi_load_cue(cd_img_t *cdi, const char *cuefile) success = 0; - for (;;) { + cdrom_image_backend_log("First pass:\n"); + cdi->tracks_num = 0; + + for (int i = 0; i < 3; i++) { + lead[i] = cdi->tracks_num; + (void *) cdi_insert_track(cdi, session, 0xa0 + i); + } + cdrom_image_backend_log("lead[2] = %016" PRIX64 "\n", (uint64_t) &(cdi->tracks[lead[2]])); + + while (1) { line = buf; /* Read a line from the cuesheet file. */ - if (feof(fp) || fgets(buf, sizeof(buf), fp) == NULL || ferror(fp)) + if (feof(fp) || (fgets(buf, sizeof(buf), fp) == NULL) || ferror(fp)) break; /* Do two iterations to make sure to nuke even if it's \r\n or \n\r, @@ -1164,183 +1218,16 @@ cdi_load_cue(cd_img_t *cdi, const char *cuefile) /* nuke trailing newline */ } } - cdrom_image_backend_log("line = %s\n", line); + cdrom_image_backend_log(" line = %s\n", line); (void) cdi_cue_get_keyword(&command, &line); - if (!strcmp(command, "TRACK")) { - if (can_add_track) - success = cdi_add_track(cdi, &trk, &shift, prestart, cur_pregap); - else - success = 1; - if (!success) - break; - - cur_pregap = 0; - prestart = 0; - trk.number = cdi_cue_get_number(&line); - trk.track_number = trk.number; - cdrom_image_backend_log("cdi_load_cue(): Track %02X\n", trk.number); - success = cdi_cue_get_keyword(&type, &line); - - memset(trk.indexes, 0x00, sizeof(trk.indexes)); - - if (!success) - break; - - if (iso_file_used) { - /* - We don't alter anything of the detected track type with - the one specified in the CUE file, except its numbers. - */ - can_add_track = 1; - - iso_file_used = 0; - } else { - trk.start = 0; - trk.skip = 0; - - trk.form = 0; - trk.mode2 = 0; - - trk.pre = 0; - - if (!strcmp(type, "AUDIO")) { - trk.sector_size = RAW_SECTOR_SIZE; - trk.attr = AUDIO_TRACK; - } else if (!strcmp(type, "MODE1/2048")) { - trk.sector_size = COOKED_SECTOR_SIZE; - trk.attr = DATA_TRACK; - } else if (!strcmp(type, "MODE1/2352")) { - trk.sector_size = RAW_SECTOR_SIZE; - trk.attr = DATA_TRACK; - } else if (!strcmp(type, "MODE1/2448")) { - trk.sector_size = 2448; - trk.attr = DATA_TRACK; - } else if (!strcmp(type, "MODE2/2048")) { - trk.form = 1; - trk.sector_size = COOKED_SECTOR_SIZE; - trk.attr = DATA_TRACK; - trk.mode2 = 1; - } else if (!strcmp(type, "MODE2/2324")) { - trk.form = 2; - trk.sector_size = 2324; - trk.attr = DATA_TRACK; - trk.mode2 = 1; - } else if (!strcmp(type, "MODE2/2328")) { - trk.form = 2; - trk.sector_size = 2328; - trk.attr = DATA_TRACK; - trk.mode2 = 1; - } else if (!strcmp(type, "MODE2/2336")) { - trk.form = 1; - trk.sector_size = 2336; - trk.attr = DATA_TRACK; - trk.mode2 = 1; - } else if (!strcmp(type, "MODE2/2352")) { - /* Assume this is XA Mode 2 Form 1. */ - trk.form = 1; - trk.sector_size = RAW_SECTOR_SIZE; - trk.attr = DATA_TRACK; - trk.mode2 = 1; - } else if (!strcmp(type, "MODE2/2448")) { - /* Assume this is XA Mode 2 Form 1. */ - trk.form = 1; - trk.sector_size = 2448; - trk.attr = DATA_TRACK; - trk.mode2 = 1; - } else if (!strcmp(type, "CDG/2448")) { - trk.sector_size = 2448; - trk.attr = DATA_TRACK; - trk.mode2 = 1; - } else if (!strcmp(type, "CDI/2336")) { - trk.sector_size = 2336; - trk.attr = DATA_TRACK; - trk.mode2 = 1; - } else if (!strcmp(type, "CDI/2352")) { - trk.sector_size = RAW_SECTOR_SIZE; - trk.attr = DATA_TRACK; - trk.mode2 = 1; - } else - success = 0; - - cdrom_image_backend_log("cdi_load_cue(): Format: %i bytes per sector, %02X, %i, %i\n", - trk.sector_size, trk.attr, trk.mode2, trk.form); - - can_add_track = 1; - } - } else if (!strcmp(command, "INDEX")) { - index = cdi_cue_get_number(&line); - success = cdi_cue_get_frame(&frame, &line); - - switch (index) { - case 0: - prestart = frame; - trk.indexes[0].in_file = 1; - trk.indexes[0].start = prestart + total_pregap; - break; - - case 1: - if (trk.indexes[0].in_file) - trk.indexes[0].length = frame - prestart; - else if (cur_pregap > 0) { - trk.indexes[0].start = frame + total_pregap; - trk.indexes[0].length = cur_pregap; - total_pregap += trk.indexes[0].length; - } else if (trk.number == 1) { - trk.indexes[0].start = 0; - trk.indexes[0].length = 150; - total_pregap += trk.indexes[0].length; - } else { - trk.indexes[0].start = frame + total_pregap; - trk.indexes[0].length = 0; - } - cdrom_image_backend_log("Index 0 (%i): %02i:%02i:%02i\n", trk.indexes[0].in_file, - (int) ((trk.indexes[0].start / 75) / 60), - (int) ((trk.indexes[0].start / 75) % 60), - (int) (trk.indexes[0].start % 75)); - - if (cur_pregap > 0) - trk.start = frame + cur_pregap; - else - trk.start = frame; - trk.indexes[1].start = trk.indexes[0].start + trk.indexes[0].length; - trk.indexes[1].in_file = 1; - cdrom_image_backend_log("Index 1 (%i): %02i:%02i:%02i\n", trk.indexes[1].in_file, - (int) ((trk.indexes[1].start / 75) / 60), - (int) ((trk.indexes[1].start / 75) % 60), - (int) (trk.indexes[1].start % 75)); - break; - - case 2: - trk.indexes[2].in_file = 1; - if (cur_pregap > 0) - trk.indexes[2].start = frame + cur_pregap; - else - trk.indexes[2].start = frame; - trk.indexes[1].length = trk.indexes[2].start - trk.indexes[1].start; - trk.indexes[2].length = 0; - cdrom_image_backend_log("Index 2 (%i): %02i:%02i:%02i\n", trk.indexes[2].in_file, - (int) ((trk.indexes[2].start / 75) / 60), - (int) ((trk.indexes[2].start / 75) % 60), - (int) (trk.indexes[2].start % 75)); - break; - - default: - /* Ignore other indices. */ - break; - } - } else if (!strcmp(command, "FILE")) { + if (!strcmp(command, "FILE")) { + /* The file for the track. */ char filename[MAX_FILENAME_LENGTH]; char ansi[MAX_FILENAME_LENGTH]; - if (can_add_track) - success = cdi_add_track(cdi, &trk, &shift, prestart, cur_pregap); - else - success = 1; - if (!success) - break; - can_add_track = 0; + tf = NULL; memset(ansi, 0, MAX_FILENAME_LENGTH * sizeof(char)); memset(filename, 0, MAX_FILENAME_LENGTH * sizeof(char)); @@ -1352,61 +1239,177 @@ cdi_load_cue(cd_img_t *cdi, const char *cuefile) if (!success) break; - trk.file = NULL; error = 1; + is_viso = 0; if (!strcmp(type, "BINARY") || !strcmp(type, "MOTOROLA")) { - int fn_len = 0; - if (!path_abs(ansi)) { + if (!path_abs(ansi)) path_append_filename(filename, pathname, ansi); - } else { + else strcpy(filename, ansi); - } - fn_len = strlen(filename); - if ((tolower((int) filename[fn_len - 1]) == 'o' - && tolower((int) filename[fn_len - 2]) == 's' - && tolower((int) filename[fn_len - 3]) == 'i' - && filename[fn_len - 4] == '.') - || plat_dir_check(filename)) { - error = !cdi_get_iso_track(cdi, &trk, filename); - if (!error) { - iso_file_used = 1; - } - } else - trk.file = track_file_init(filename, &error); + + tf = track_file_init(filename, &error, &is_viso); - if (trk.file) { - trk.file->motorola = !strcmp(type, "MOTOROLA"); - } + if (tf) + tf->motorola = !strcmp(type, "MOTOROLA"); } else if (!strcmp(type, "WAVE") || !strcmp(type, "AIFF") || !strcmp(type, "MP3")) { - if (!path_abs(ansi)) { + if (!path_abs(ansi)) path_append_filename(filename, pathname, ansi); - } else { + else strcpy(filename, ansi); - } - trk.file = audio_init(filename, &error); + tf = audio_init(filename, &error); } if (error) { cdrom_image_backend_log("CUE: cannot open file '%s' in cue sheet!\n", filename); - if (trk.file != NULL) { - trk.file->close(trk.file); - trk.file = NULL; + if (tf != NULL) { + tf->close(tf); + tf = NULL; } success = 0; - } - } else if (!strcmp(command, "PREGAP")) - success = cdi_cue_get_frame(&cur_pregap, &line); - else if (!strcmp(command, "POSTGAP")) { - success = cdi_cue_get_frame(&trk.indexes[2].length, &line); - trk.indexes[2].in_file = 0; + } else if (is_viso) + success = 3; + } else if (!strcmp(command, "TRACK")) { + int t = cdi_cue_get_number(&line); + success = cdi_cue_get_keyword(&type, &line); + + if (!success) + break; + + ct = cdi_insert_track(cdi, session, t); + + cdrom_image_backend_log(" TRACK %i\n", t); + + ct->form = 0; + ct->mode = 0; + + if (!strcmp(type, "AUDIO")) { + ct->sector_size = RAW_SECTOR_SIZE; + ct->attr = AUDIO_TRACK; + } else if (!memcmp(type, "MODE", 4)) { + uint32_t mode; + ct->attr = DATA_TRACK; + sscanf(type, "MODE%" PRIu32 "/%" PRIu32, &mode, &(ct->sector_size)); + ct->mode = mode; + if (ct->mode == 2) switch(ct->sector_size) { + case 2324: case 2328: + ct->form = 2; + break; + case 2048: case 2336: case 2352: case 2448: + ct->form = 1; + break; + } + if ((ct->sector_size == 2336) && (ct->mode == 2) && (ct->form == 1)) + ct->skip = 8; + } else if (!memcmp(type, "CD", 2)) { + ct->attr = DATA_TRACK; + ct->mode = 2; + sscanf(type, "CD%c/%i", &temp, &(ct->sector_size)); + } else + success = 0; + + if (success) + last = ct->sector_size; + } else if (!strcmp(command, "INDEX")) { + int t = cdi_cue_get_number(&line); + ci = &(ct->idx[t]); + + cdrom_image_backend_log(" INDEX %i (1)\n", t); + + ci->type = INDEX_NORMAL; + ci->file = tf; + success = cdi_cue_get_frame(&frame, &line); + ci->file_start = frame; + } else if (!strcmp(command, "PREGAP")) { + ci = &(ct->idx[0]); + cdrom_image_backend_log(" INDEX 0 (0)\n"); + + ci->type = INDEX_ZERO; + ci->file = tf; + success = cdi_cue_get_frame(&frame, &line); + ci->length = frame; + } else if (!strcmp(command, "PAUSE")) { + ci = &(ct->idx[1]); + cdrom_image_backend_log(" INDEX 1 (0)\n"); + + ci->type = INDEX_ZERO; + ci->file = tf; + success = cdi_cue_get_frame(&frame, &line); + ci->length = frame; + } else if (!strcmp(command, "POSTGAP")) { + ci = &(ct->idx[2]); + cdrom_image_backend_log(" INDEX 2 (0)\n"); + + ci->type = INDEX_ZERO; + ci->file = tf; + success = cdi_cue_get_frame(&frame, &line); + ci->length = frame; + } else if (!strcmp(command, "ZERO")) { + ci = &(ct->idx[1]); + cdrom_image_backend_log(" INDEX 1 (0)\n"); + + ci->type = INDEX_ZERO; + ci->file = tf; + success = cdi_cue_get_frame(&frame, &line); + ci->length = frame; } else if (!strcmp(command, "FLAGS")) - success = cdi_cue_get_flags(&trk, &line); - else if (!strcmp(command, "CATALOG") || !strcmp(command, "CDTEXTFILE") || !strcmp(command, "ISRC") || !strcmp(command, "PERFORMER") || !strcmp(command, "POSTGAP") || !strcmp(command, "REM") || !strcmp(command, "SONGWRITER") || !strcmp(command, "TITLE") || !strcmp(command, "")) { + success = cdi_cue_get_flags(ct, &line); + else if (!strcmp(command, "REM")) { + success = 1; + char *space = strstr(line, " "); + if (space != NULL) { + space++; + if (space < (line + strlen(line))) { + (void) cdi_cue_get_keyword(&command, &space); + if (!strcmp(command, "LEAD-OUT")) { + ct = &(cdi->tracks[lead[2]]); + cdrom_image_backend_log("lead[2] = %016" PRIX64 "\n", (uint64_t) ct); + ct->sector_size = last; + ci = &(ct->idx[1]); + ci->type = INDEX_NORMAL; + ci->file = tf; + success = cdi_cue_get_frame(&frame, &space); + ci->file_start = frame; + + cdrom_image_backend_log(" LEAD-OUT\n"); + } else if (!strcmp(command, "SESSION")) { + session = cdi_cue_get_number(&space); + + if (session > 1) { + ct = cdi_insert_track(cdi, session - 1, 0xb0); + ci = &(ct->idx[1]); + ci->start = (0x40 * 60 * 75) + (0x02 * 75); + + if (session == 2) { + ct->extra[3] = 0x02; + + /* 5F:00:00 on Wembley, C0:00:00 in the spec. And what's in PMSF? */ + ct = cdi_insert_track(cdi, session - 1, 0xc0); + ci = &(ct->idx[1]); + ct->extra[0] = 0x5f; /* Optimum recording power. */ + } else + ct->extra[3] = 0x01; + + for (int i = 0; i < 3; i++) { + lead[i] = cdi->tracks_num; + (void *) cdi_insert_track(cdi, session, 0xa0 + i); + } + cdrom_image_backend_log("lead[2] = %016" PRIX64 "\n", + (uint64_t) &(cdi->tracks[lead[2]])); + } + + cdrom_image_backend_log(" SESSION %i\n", session); + } + } + } + } else if (!strcmp(command, "CATALOG") || !strcmp(command, "CDTEXTFILE") || + !strcmp(command, "ISRC") || !strcmp(command, "PERFORMER") || + !strcmp(command, "SONGWRITER") || !strcmp(command, "TITLE") || + !strcmp(command, "")) /* Ignored commands. */ success = 1; - } else { + else { cdrom_image_backend_log("CUE: unsupported command '%s' in cue sheet!\n", command); success = 0; @@ -1416,94 +1419,75 @@ cdi_load_cue(cd_img_t *cdi, const char *cuefile) break; } + tf = NULL; + fclose(fp); + if (!success) return 0; - /* Add last track. */ - cdrom_image_backend_log("LEAD OUT\n"); - if (!cdi_add_track(cdi, &trk, &shift, prestart, cur_pregap)) - return 0; + cdi_last_3_passes(cdi); - /* Add lead out track. */ - cdrom_image_backend_log("END OF CUE\n"); - trk.number++; - memset(trk.indexes, 0x00, sizeof(trk.indexes)); - trk.track_number = 0xAA; - // trk.attr = 0x16; - trk.start = 0; - trk.length = 0; - trk.file = NULL; - if (!cdi_add_track(cdi, &trk, &shift, 0, 0)) - return 0; + return success; +} - track_t *cur = &cdi->tracks[cdi->tracks_num - 1]; - track_t *prev = &cdi->tracks[cdi->tracks_num - 2]; +/* Root functions. */ +static void +cdi_clear_tracks(cd_img_t *cdi) +{ + track_file_t *last = NULL; + track_t *cur = NULL; + track_index_t *idx = NULL; - for (int i = 0; i < 3; i++) { - cur->indexes[i].in_file = 0; - cur->indexes[i].start = prev->indexes[1].start + prev->length - 150; - cur->indexes[i].length = 0; - } + if ((cdi->tracks == NULL) || (cdi->tracks_num == 0)) + return; - if (prev->indexes[2].length != 0) { - prev->indexes[2].start = cur->indexes[0].start - prev->indexes[2].length; - prev->indexes[1].length = prev->indexes[2].start - prev->indexes[1].start; - } else if (prev->indexes[2].in_file) - prev->indexes[2].length = cur->indexes[0].start - prev->indexes[2].start; - else { - prev->indexes[1].length = cur->indexes[0].start - prev->indexes[1].start; - prev->indexes[2].start = prev->indexes[1].start + prev->indexes[1].length; - prev->indexes[2].length = 0; - } - -#ifdef ENABLE_CDROM_IMAGE_BACKEND_LOG for (int i = 0; i < cdi->tracks_num; i++) { - track_t *t = &(cdi->tracks[i]); - for (int j = 0; j < 3; j++) { - track_index_t *ti = &(t->indexes[j]); - cdrom_image_backend_log("Track %02X.%01X (%i): %02i:%02i:%02i-%02i:%02i:%02i\n", - t->track_number, j, - ti->in_file, - (int) ((ti->start / 75) / 60), - (int) ((ti->start / 75) % 60), - (int) (ti->start % 75), - (int) (((ti->start + ti->length - 1) / 75) / 60), - (int) (((ti->start + ti->length - 1) / 75) % 60), - (int) ((ti->start + ti->length - 1) % 75)); + cur = &cdi->tracks[i]; + + if ((cur->point >= 1) && (cur->point <= 99)) for (int j = 0; j < 3; j++) { + idx = &(cur->idx[j]); + + /* Make sure we do not attempt to close a NULL file. */ + if (idx->file != NULL) { + if (idx->file != last) { + last = idx->file; + index_file_close(idx); + } else + idx->file = NULL; + } } } -#endif - return 1; + /* Now free the array. */ + free(cdi->tracks); + cdi->tracks = NULL; + + /* Mark that there's no tracks. */ + cdi->tracks_num = 0; +} + +void +cdi_close(cd_img_t *cdi) +{ + cdi_clear_tracks(cdi); + free(cdi); } int -cdi_has_data_track(cd_img_t *cdi) +cdi_set_device(cd_img_t *cdi, const char *path) { - if ((cdi == NULL) || (cdi->tracks == NULL)) - return 0; + int ret; - /* Data track has attribute 0x14. */ - for (int i = 0; i < cdi->tracks_num; i++) { - if (cdi->tracks[i].attr == DATA_TRACK) - return 1; - } - - return 0; -} - -int -cdi_has_audio_track(cd_img_t *cdi) -{ - if ((cdi == NULL) || (cdi->tracks == NULL)) - return 0; - - /* Audio track has attribute 0x10. */ - for (int i = 0; i < cdi->tracks_num; i++) { - if (cdi->tracks[i].attr == AUDIO_TRACK) - return 1; - } + if ((ret = cdi_load_cue(cdi, path))) + return ret; + + cdi_clear_tracks(cdi); + + if ((ret = cdi_load_iso(cdi, path))) + return ret; + + cdi_close(cdi); return 0; } diff --git a/src/cdrom/cdrom_image_viso.c b/src/cdrom/cdrom_image_viso.c index edca09d91..24f60836d 100644 --- a/src/cdrom/cdrom_image_viso.c +++ b/src/cdrom/cdrom_image_viso.c @@ -8,9 +8,7 @@ * * Virtual ISO CD-ROM image back-end. * - * - * - * Authors: RichardG + * Authors: RichardG, * * Copyright 2022 RichardG. */ diff --git a/src/cdrom/cdrom_ioctl.c b/src/cdrom/cdrom_ioctl.c index eccb75fef..2bb691f30 100644 --- a/src/cdrom/cdrom_ioctl.c +++ b/src/cdrom/cdrom_ioctl.c @@ -55,14 +55,6 @@ cdrom_ioctl_log(const char *fmt, ...) of the audio while audio still plays. With an absolute conversion, the counter is fine. */ #define MSFtoLBA(m, s, f) ((((m * 60) + s) * 75) + f) -static void -ioctl_get_tracks(cdrom_t *dev, int *first, int *last) -{ - TMSF tmsf; - - plat_cdrom_get_audio_tracks(dev->local, first, last, &tmsf); -} - static void ioctl_get_track_info(cdrom_t *dev, uint32_t track, int end, track_info_t *ti) { @@ -209,7 +201,6 @@ ioctl_exit(cdrom_t *dev) } static const cdrom_ops_t cdrom_ioctl_ops = { - ioctl_get_tracks, ioctl_get_track_info, ioctl_get_raw_track_info, ioctl_get_subchannel, diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index 8fb0bc742..efb45ecfb 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -218,7 +218,6 @@ typedef struct raw_track_info_t { /* Define the various CD-ROM drive operations (ops). */ typedef struct cdrom_ops_t { - void (*get_tracks)(struct cdrom *dev, int *first, int *last); void (*get_track_info)(struct cdrom *dev, uint32_t track, int end, track_info_t *ti); void (*get_raw_track_info)(struct cdrom *dev, int *num, raw_track_info_t *rti); void (*get_subchannel)(struct cdrom *dev, uint32_t lba, subchannel_t *subc); diff --git a/src/include/86box/cdrom_image_backend.h b/src/include/86box/cdrom_image_backend.h index 2e3aa85b9..64ce88d83 100644 --- a/src/include/86box/cdrom_image_backend.h +++ b/src/include/86box/cdrom_image_backend.h @@ -6,16 +6,15 @@ * * This file is part of the 86Box distribution. * - * CD-ROM image file handling module header , translated to C - * from cdrom_dosbox.h. + * CD-ROM image file handling module header. * * Authors: Miran Grca, - * Fred N. van Kempen, - * The DOSBox Team, + * RichardG, + * Cacodemon345 * - * Copyright 2016-2020 Miran Grca. - * Copyright 2017-2020 Fred N. van Kempen. - * Copyright 2002-2020 The DOSBox Team. + * Copyright 2016-2025 Miran Grca. + * Copyright 2016-2025 Miran Grca. + * Copyright 2024-2025 Cacodemon345. */ #ifndef CDROM_IMAGE_BACKEND_H #define CDROM_IMAGE_BACKEND_H @@ -57,72 +56,59 @@ typedef struct track_file_t { int motorola; } track_file_t; -#define BLOCK_EMPTY 0 /* Empty block. */ -#define BLOCK_ZERO 1 /* Block not in the file, return all 0x00's. */ -#define BLOCK_NORMAL 2 /* Block in the file. */ - -#define BLOCK_NONE ((uint64_t) -1LL) +#define INDEX_SPECIAL -2 /* Track A0h onwards. */ +#define INDEX_NONE -1 /* Empty block. */ +#define INDEX_ZERO 0 /* Block not in the file, return all 0x00's. */ +#define INDEX_NORMAL 1 /* Block in the file. */ typedef struct track_index_t { - /* Is the current block in the file? If not, return all 0x00's. */ - int in_file; + /* Is the current block in the file? If not, return all 0x00's. -1 means not yet loaded. */ + int32_t type; /* The amount of bytes to skip at the beginning of each sector. */ - int skip; + int32_t skip; /* Starting and ending sector LBA - negative in order to accomodate LBA -150 to -1 to read the pregap of track 1. */ uint64_t start; uint64_t length; + uint64_t file_start; + uint64_t file_length; + track_file_t *file; } track_index_t; typedef struct track_t { - int pregap_len; /* Pre-gap - not in file. */ - int index0_len; /* Pre-gap - in file. */ - int postgap_len; /* Post-gap - not in file. */ - int blocks_num; /* Number of blocks. */ - int number; - int track_number; - int attr; - int sector_size; - int mode2; - int form; - int pre; - int noskip; /* Do not skip by 8 bytes.*/ - uint64_t start; - uint64_t length; - uint64_t skip; - track_index_t indexes[3]; - track_file_t *file; + uint8_t session; + uint8_t attr; + uint8_t tno; + uint8_t point; + uint8_t extra[4]; + uint8_t mode; + uint8_t form; + uint8_t pad; + uint8_t skip; + uint32_t sector_size; + track_index_t idx[3]; } track_t; typedef struct cd_img_t { - int tracks_num; - track_t *tracks; + int32_t tracks_num; + track_t *tracks; } cd_img_t; /* Binary file functions. */ -extern void cdi_close(cd_img_t *cdi); -extern int cdi_set_device(cd_img_t *cdi, const char *path); -extern void cdi_get_audio_tracks(cd_img_t *cdi, int *st_track, int *end, TMSF *lead_out); -extern void cdi_get_audio_tracks_lba(cd_img_t *cdi, int *st_track, int *end, uint32_t *lead_out); -extern int cdi_get_audio_track_pre(cd_img_t *cdi, int track); -extern int cdi_get_audio_track_info(cd_img_t *cdi, int end, int track, int *track_num, - TMSF *start, uint8_t *attr); -extern int cdi_get_audio_track_info_lba(cd_img_t *cdi, int end, int track, int *track_num, - uint32_t *start, uint8_t *attr); extern void cdi_get_raw_track_info(cd_img_t *cdi, int *num, uint8_t *buffer); -extern int cdi_get_track(cd_img_t *cdi, uint32_t sector); extern int cdi_get_audio_sub(cd_img_t *cdi, uint32_t sector, uint8_t *attr, uint8_t *track, uint8_t *index, TMSF *rel_pos, TMSF *abs_pos); extern int cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector); -extern int cdi_read_sectors(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector, uint32_t num); extern int cdi_read_sector_sub(cd_img_t *cdi, uint8_t *buffer, uint32_t sector); extern int cdi_get_sector_size(cd_img_t *cdi, uint32_t sector); +extern int cdi_is_audio(cd_img_t *cdi, uint32_t sector); +extern int cdi_is_pre(cd_img_t *cdi, uint32_t sector); extern int cdi_is_mode2(cd_img_t *cdi, uint32_t sector); extern int cdi_get_mode2_form(cd_img_t *cdi, uint32_t sector); extern int cdi_load_iso(cd_img_t *cdi, const char *filename); extern int cdi_load_cue(cd_img_t *cdi, const char *cuefile); -extern int cdi_has_data_track(cd_img_t *cdi); -extern int cdi_has_audio_track(cd_img_t *cdi); +extern void cdi_close(cd_img_t *cdi); +extern int cdi_set_device(cd_img_t *cdi, const char *path); /* Virtual ISO functions. */ extern int viso_read(void *priv, uint8_t *buffer, uint64_t seek, size_t count); diff --git a/src/include/86box/plat_cdrom.h b/src/include/86box/plat_cdrom.h index 1e70e014b..643013a08 100644 --- a/src/include/86box/plat_cdrom.h +++ b/src/include/86box/plat_cdrom.h @@ -53,7 +53,6 @@ extern void plat_cdrom_get_raw_track_info(void *local, int *num, raw_track_i extern int plat_cdrom_is_track_audio(void *local, uint32_t sector); extern int plat_cdrom_is_track_pre(void *local, uint32_t sector); extern uint32_t plat_cdrom_get_last_block(void *local); -extern void plat_cdrom_get_audio_tracks(void *local, int *st_track, int *end, TMSF *lead_out); extern int plat_cdrom_get_audio_track_info(void *local, int end, int track, int *track_num, TMSF *start, uint8_t *attr); extern int plat_cdrom_get_audio_sub(void *local, uint32_t sector, uint8_t *attr, uint8_t *track, diff --git a/src/qt/dummy_cdrom_ioctl.c b/src/qt/dummy_cdrom_ioctl.c index 8555642e6..4ed0333a7 100644 --- a/src/qt/dummy_cdrom_ioctl.c +++ b/src/qt/dummy_cdrom_ioctl.c @@ -144,23 +144,6 @@ plat_cdrom_ext_medium_changed(void *local) return ret; } -void -plat_cdrom_get_audio_tracks(void *local, int *st_track, int *end, TMSF *lead_out) -{ - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; - - plat_cdrom_read_toc(ioctl); - - *st_track = 1; - *end = 1; - lead_out->min = 0; - lead_out->sec = 0; - lead_out->fr = 2; - - dummy_cdrom_ioctl_log("plat_cdrom_get_audio_tracks(): %02i, %02i, %02i:%02i:%02i\n", - *st_track, *end, lead_out->min, lead_out->sec, lead_out->fr); -} - /* This replaces both Info and EndInfo, they are specified by a variable. */ int plat_cdrom_get_audio_track_info(void *local, UNUSED(int end), int track, int *track_num, TMSF *start, uint8_t *attr) diff --git a/src/qt/win_cdrom_ioctl.c b/src/qt/win_cdrom_ioctl.c index 7e3a588c3..9d82d68cc 100644 --- a/src/qt/win_cdrom_ioctl.c +++ b/src/qt/win_cdrom_ioctl.c @@ -398,26 +398,6 @@ plat_cdrom_ext_medium_changed(void *local) return ret; } -void -plat_cdrom_get_audio_tracks(void *local, int *st_track, int *end, TMSF *lead_out) -{ - win_cdrom_ioctl_t *ioctl = (win_cdrom_ioctl_t *) local; - PCDROM_TOC toc = (PCDROM_TOC) ioctl->cur_toc; - - plat_cdrom_read_toc(ioctl); - - PTRACK_DATA ltd = &toc->TrackData[toc->LastTrack]; - - *st_track = 1; - *end = toc->LastTrack; - lead_out->min = ltd->Address[1]; - lead_out->sec = ltd->Address[2]; - lead_out->fr = ltd->Address[3]; - - win_cdrom_ioctl_log("plat_cdrom_get_audio_tracks(): %02i, %02i, %02i:%02i:%02i\n", - *st_track, *end, lead_out->min, lead_out->sec, lead_out->fr); -} - /* This replaces both Info and EndInfo, they are specified by a variable. */ int plat_cdrom_get_audio_track_info(void *local, UNUSED(int end), int track, int *track_num, TMSF *start, uint8_t *attr) diff --git a/src/unix/dummy_cdrom_ioctl.c b/src/unix/dummy_cdrom_ioctl.c index 8555642e6..4ed0333a7 100644 --- a/src/unix/dummy_cdrom_ioctl.c +++ b/src/unix/dummy_cdrom_ioctl.c @@ -144,23 +144,6 @@ plat_cdrom_ext_medium_changed(void *local) return ret; } -void -plat_cdrom_get_audio_tracks(void *local, int *st_track, int *end, TMSF *lead_out) -{ - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; - - plat_cdrom_read_toc(ioctl); - - *st_track = 1; - *end = 1; - lead_out->min = 0; - lead_out->sec = 0; - lead_out->fr = 2; - - dummy_cdrom_ioctl_log("plat_cdrom_get_audio_tracks(): %02i, %02i, %02i:%02i:%02i\n", - *st_track, *end, lead_out->min, lead_out->sec, lead_out->fr); -} - /* This replaces both Info and EndInfo, they are specified by a variable. */ int plat_cdrom_get_audio_track_info(void *local, UNUSED(int end), int track, int *track_num, TMSF *start, uint8_t *attr)