2 * (C) GraÅžvydas "notaz" Ignotas, 2010
4 * This work is licensed under the terms of any of these licenses
6 * - GNU GPL, version 2 or later.
7 * - GNU LGPL, version 2.1 or later.
8 * See the COPYING file in the top-level directory.
18 #define CD_FRAMESIZE_RAW 2352
20 static const char *cd_fname;
21 static unsigned int *cd_index_table;
22 static unsigned int cd_index_len;
25 static unsigned char cdbuffer[CD_FRAMESIZE_RAW];
26 static unsigned char cdbuffer_compressed[CD_FRAMESIZE_RAW + 100];
27 static int current_sector;
30 extern long CDR__getStatus(struct CdrStat *stat);
36 unsigned char Time[3]; // current playing time
40 enum {DATA, CDDA} type;
41 char start[3]; // MSF-format
42 char length[3]; // MSF-format
45 #define MAXTRACKS 100 /* How many tracks can a CD hold? */
47 static int numtracks = 0;
49 #define btoi(b) ((b) / 16 * 10 + (b) % 16) /* BCD to u_char */
50 #define MSF2SECT(m, s, f) (((m) * 60 + (s) - 2) * 75 + (f))
52 // return Starting and Ending Track
54 // byte 0 - start track
56 static long CDRgetTN(unsigned char *buffer)
59 buffer[1] = numtracks > 0 ? numtracks : 1;
69 static long CDRgetTD(unsigned char track, unsigned char *buffer)
79 // time: byte 0 - minute; byte 1 - second; byte 2 - frame
81 static long CDRreadTrack(unsigned char *time)
83 unsigned int start_byte, size;
84 unsigned long cdbuffer_size;
90 sector = MSF2SECT(btoi(time[0]), btoi(time[1]), btoi(time[2]));
91 if (sector == current_sector) {
92 // it's already there, nothing to do
93 //printf("hit sect %d\n", sector);
97 if (sector >= cd_index_len) {
98 fprintf(stderr, "sector %d is past track end\n", sector);
102 start_byte = cd_index_table[sector];
103 if (fseek(cd_file, start_byte, SEEK_SET) != 0) {
104 fprintf(stderr, "seek error for sector %d at %x: ",
110 size = cd_index_table[sector + 1] - start_byte;
111 if (size > sizeof(cdbuffer_compressed)) {
112 fprintf(stderr, "sector %d is too large: %u\n", sector, size);
116 if (fread(cdbuffer_compressed, 1, size, cd_file) != size) {
117 fprintf(stderr, "read error for sector %d at %x: ",
123 cdbuffer_size = sizeof(cdbuffer);
124 ret = uncompress(cdbuffer, &cdbuffer_size, cdbuffer_compressed, size);
126 fprintf(stderr, "uncompress failed with %d for sector %d\n", ret, sector);
129 if (cdbuffer_size != sizeof(cdbuffer))
130 printf("%lu != %d\n", cdbuffer_size, sizeof(cdbuffer));
133 current_sector = sector;
138 static unsigned char *CDRgetBuffer(void)
140 return cdbuffer + 12;
144 // sector: byte 0 - minute; byte 1 - second; byte 2 - frame
145 // does NOT uses bcd format
146 static long CDRplay(unsigned char *time)
152 static long CDRstop(void)
157 // gets subchannel data
158 static unsigned char* CDRgetBufferSub(void)
163 static long CDRgetStatus(struct CdrStat *stat) {
164 CDR__getStatus(stat);
171 static long CDRclose(void)
173 if (cd_file != NULL) {
177 if (cd_index_table != NULL) {
178 free(cd_index_table);
179 cd_index_table = NULL;
184 static long CDRshutdown(void)
189 static long CDRinit(void)
191 return 0; // do nothing
194 // This function is invoked by the front-end when opening an ISO
196 static long CDRopen(void)
198 // a Z.table file is binary where each element represents
199 // one compressed frame.
200 // 4 bytes: the offset of the frame in the .Z file
201 // 2 bytes: the length of the compressed frame
205 } __attribute__((packed)) ztab_entry;
206 char table_fname[256];
212 return 0; // it's already open
216 if (cd_fname == NULL)
219 snprintf(table_fname, sizeof(table_fname), "%s.table", cd_fname);
220 f = fopen(table_fname, "rb");
222 fprintf(stderr, "missing file: %s: ", table_fname);
227 ret = fseek(f, 0, SEEK_END);
229 fprintf(stderr, "failed to seek\n");
232 table_size = ftell(f);
233 fseek(f, 0, SEEK_SET);
235 if (table_size > 2 * 1024 * 1024) {
236 fprintf(stderr, ".table too large\n");
240 cd_index_len = table_size / 6;
241 cd_index_table = malloc((cd_index_len + 1) * sizeof(cd_index_table[0]));
242 if (cd_index_table == NULL)
245 for (i = 0; i < cd_index_len; i++) {
246 ret = fread(&ztab_entry, 1, sizeof(ztab_entry), f);
247 if (ret != sizeof(ztab_entry)) {
248 fprintf(stderr, ".table read failed on entry %d/%d\n", i, cd_index_len);
249 goto fail_table_io_read;
251 cd_index_table[i] = ztab_entry.offset;
253 // fake entry, so that we know last compressed block size
254 cd_index_table[i] = ztab_entry.offset + ztab_entry.size;
256 cd_file = fopen(cd_fname, "rb");
257 if (cd_file == NULL) {
258 fprintf(stderr, "faied to open: %s: ", table_fname);
264 printf("Loaded compressed CD Image: %s.\n", cd_fname);
271 free(cd_index_table);
272 cd_index_table = NULL;
278 #define FUNC(n) { #n, n }
280 static const struct {
293 FUNC(CDRgetBufferSub),
299 void cdrcimg_set_fname(const char *fname)
304 void *cdrcimg_get_sym(const char *sym)
307 for (i = 0; i < sizeof(plugin_funcs) / sizeof(plugin_funcs[0]); i++)
308 if (strcmp(plugin_funcs[i].name, sym) == 0)
309 return plugin_funcs[i].func;