Mercurial > repos > blastem
diff cue.c @ 2059:6399a776e981 segacd
Add basic support for BIN/CUE images
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 21 Jan 2022 21:59:46 -0800 |
parents | |
children | 7c1760b5b3e5 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cue.c Fri Jan 21 21:59:46 2022 -0800 @@ -0,0 +1,148 @@ +#include <ctype.h> + +#include "system.h" +#include "util.h" + +static char* cmd_start(char *cur) +{ + while (*cur && isblank(*cur)) + { + cur++; + } + return cur; +} + +static char* next_line(char *cur) +{ + while (*cur && *cur != '\n') + { + cur++; + } + if (*cur) { + return cur + 1; + } + return NULL; +} + +static uint32_t timecode_to_lba(char *timecode) +{ + char *end; + int seconds = 0, frames = 0; + int minutes = strtol(timecode, &end, 10); + if (end) { + timecode = end + 1; + seconds = strtol(timecode, &end, 10); + if (end) { + timecode = end + 1; + frames = strtol(timecode, NULL, 10); + } + } + seconds += minutes * 60; + return seconds * 75 + frames; + +} + +uint8_t parse_cue(system_media *media) +{ + char *line = media->buffer; + media->num_tracks = 0; + do { + char *cmd = cmd_start(line); + if (cmd) { + if (startswith(cmd, "TRACK ")) { + media->num_tracks++; + } + line = next_line(cmd); + } else { + line = NULL; + } + } while (line); + track_info *tracks = calloc(sizeof(track_info), media->num_tracks); + media->tracks = tracks; + line = media->buffer; + int track = -1; + do { + char *cmd = cmd_start(line); + if (cmd) { + if (startswith(cmd, "TRACK ")) { + track++; + cmd += 6; + char *end; + int file_track = strtol(cmd, &end, 10); + if (file_track != (track + 1)) { + warning("Expected track %d, but found track %d in CUE sheet\n", track + 1, file_track); + } + cmd = cmd_start(end); + if (cmd) { + tracks[track].type = startswith(cmd, "AUDIO") ? TRACK_AUDIO : TRACK_DATA; + } + } else if (startswith(cmd, "FILE ")) { + if (media->f) { + warning("CUE sheets with multiple FILE commands are not supported\n"); + } else { + cmd += 5; + cmd = strchr(cmd, '"'); + if (cmd) { + cmd++; + char *end = strchr(cmd, '"'); + if (end) { + char *fname; + //TODO: zipped BIN/CUE support + if (is_absolute_path(cmd)) { + fname = malloc(end-cmd + 1); + memcpy(fname, cmd, end-cmd); + fname[end-cmd] = 0; + } else { + size_t dirlen = strlen(media->dir); + fname = malloc(dirlen + 1 + (end-cmd) + 1); + memcpy(fname, media->dir, dirlen); + fname[dirlen] = PATH_SEP[0]; + memcpy(fname + dirlen + 1, cmd, end-cmd); + fname[dirlen + 1 + (end-cmd)] = 0; + } + media->f = fopen(fname, "rb"); + if (!media->f) { + fatal_error("Failed to open %s specified by FILE command in CUE sheet %s.%s\n", fname, media->name, media->extension); + } + free(fname); + } + } + } + } else if (track >= 0) { + if (startswith(cmd, "PREGAP ")) { + tracks[track].fake_pregap = timecode_to_lba(cmd + 7); + } else if (startswith(cmd, "INDEX ")) { + char *after; + int index = strtol(cmd + 6, &after, 10); + if (!index) { + tracks[track].pregap_lba = timecode_to_lba(after); + } else if (index == 1) { + tracks[track].start_lba = timecode_to_lba(after); + } + } + } + if (cmd) { + line = next_line(cmd); + } else { + line = NULL; + } + } else { + line = NULL; + } + } while (line); + for (uint32_t i = 0; i < (media->num_tracks - 1); i++) + { + uint32_t next = i + 1; + tracks[i].end_lba = tracks[next].pregap_lba ? tracks[next].pregap_lba : tracks[next].start_lba; + } + if (media->f) { + //end of last track is implicitly defined by file size + tracks[media->num_tracks-1].end_lba = file_size(media->f) / 2352; + //replace cue sheet with first sector + free(media->buffer); + media->buffer = calloc(2048, 1); + fseek(media->f, 16, SEEK_SET); + media->size = fread(media->buffer, 1, 2048, media->f); + } + return tracks > 0 && media->f != NULL; +}