comparison 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
comparison
equal deleted inserted replaced
2058:70260f6051dd 2059:6399a776e981
1 #include <ctype.h>
2
3 #include "system.h"
4 #include "util.h"
5
6 static char* cmd_start(char *cur)
7 {
8 while (*cur && isblank(*cur))
9 {
10 cur++;
11 }
12 return cur;
13 }
14
15 static char* next_line(char *cur)
16 {
17 while (*cur && *cur != '\n')
18 {
19 cur++;
20 }
21 if (*cur) {
22 return cur + 1;
23 }
24 return NULL;
25 }
26
27 static uint32_t timecode_to_lba(char *timecode)
28 {
29 char *end;
30 int seconds = 0, frames = 0;
31 int minutes = strtol(timecode, &end, 10);
32 if (end) {
33 timecode = end + 1;
34 seconds = strtol(timecode, &end, 10);
35 if (end) {
36 timecode = end + 1;
37 frames = strtol(timecode, NULL, 10);
38 }
39 }
40 seconds += minutes * 60;
41 return seconds * 75 + frames;
42
43 }
44
45 uint8_t parse_cue(system_media *media)
46 {
47 char *line = media->buffer;
48 media->num_tracks = 0;
49 do {
50 char *cmd = cmd_start(line);
51 if (cmd) {
52 if (startswith(cmd, "TRACK ")) {
53 media->num_tracks++;
54 }
55 line = next_line(cmd);
56 } else {
57 line = NULL;
58 }
59 } while (line);
60 track_info *tracks = calloc(sizeof(track_info), media->num_tracks);
61 media->tracks = tracks;
62 line = media->buffer;
63 int track = -1;
64 do {
65 char *cmd = cmd_start(line);
66 if (cmd) {
67 if (startswith(cmd, "TRACK ")) {
68 track++;
69 cmd += 6;
70 char *end;
71 int file_track = strtol(cmd, &end, 10);
72 if (file_track != (track + 1)) {
73 warning("Expected track %d, but found track %d in CUE sheet\n", track + 1, file_track);
74 }
75 cmd = cmd_start(end);
76 if (cmd) {
77 tracks[track].type = startswith(cmd, "AUDIO") ? TRACK_AUDIO : TRACK_DATA;
78 }
79 } else if (startswith(cmd, "FILE ")) {
80 if (media->f) {
81 warning("CUE sheets with multiple FILE commands are not supported\n");
82 } else {
83 cmd += 5;
84 cmd = strchr(cmd, '"');
85 if (cmd) {
86 cmd++;
87 char *end = strchr(cmd, '"');
88 if (end) {
89 char *fname;
90 //TODO: zipped BIN/CUE support
91 if (is_absolute_path(cmd)) {
92 fname = malloc(end-cmd + 1);
93 memcpy(fname, cmd, end-cmd);
94 fname[end-cmd] = 0;
95 } else {
96 size_t dirlen = strlen(media->dir);
97 fname = malloc(dirlen + 1 + (end-cmd) + 1);
98 memcpy(fname, media->dir, dirlen);
99 fname[dirlen] = PATH_SEP[0];
100 memcpy(fname + dirlen + 1, cmd, end-cmd);
101 fname[dirlen + 1 + (end-cmd)] = 0;
102 }
103 media->f = fopen(fname, "rb");
104 if (!media->f) {
105 fatal_error("Failed to open %s specified by FILE command in CUE sheet %s.%s\n", fname, media->name, media->extension);
106 }
107 free(fname);
108 }
109 }
110 }
111 } else if (track >= 0) {
112 if (startswith(cmd, "PREGAP ")) {
113 tracks[track].fake_pregap = timecode_to_lba(cmd + 7);
114 } else if (startswith(cmd, "INDEX ")) {
115 char *after;
116 int index = strtol(cmd + 6, &after, 10);
117 if (!index) {
118 tracks[track].pregap_lba = timecode_to_lba(after);
119 } else if (index == 1) {
120 tracks[track].start_lba = timecode_to_lba(after);
121 }
122 }
123 }
124 if (cmd) {
125 line = next_line(cmd);
126 } else {
127 line = NULL;
128 }
129 } else {
130 line = NULL;
131 }
132 } while (line);
133 for (uint32_t i = 0; i < (media->num_tracks - 1); i++)
134 {
135 uint32_t next = i + 1;
136 tracks[i].end_lba = tracks[next].pregap_lba ? tracks[next].pregap_lba : tracks[next].start_lba;
137 }
138 if (media->f) {
139 //end of last track is implicitly defined by file size
140 tracks[media->num_tracks-1].end_lba = file_size(media->f) / 2352;
141 //replace cue sheet with first sector
142 free(media->buffer);
143 media->buffer = calloc(2048, 1);
144 fseek(media->f, 16, SEEK_SET);
145 media->size = fread(media->buffer, 1, 2048, media->f);
146 }
147 return tracks > 0 && media->f != NULL;
148 }