Mercurial > repos > blastem
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 } |