gpu_unai: basic frameskip
[pcsx_rearmed.git] / plugins / cdrcimg / cdrcimg.c
1 /*
2  * (C) GraÅžvydas "notaz" Ignotas, 2010
3  *
4  * This work is licensed under the terms of any of these licenses
5  * (at your option):
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.
9  */
10
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <zlib.h>
15
16 #include "cdrcimg.h"
17
18 #define CD_FRAMESIZE_RAW 2352
19
20 static const char *cd_fname;
21 static unsigned int *cd_index_table;
22 static unsigned int  cd_index_len;
23 static FILE *cd_file;
24
25 static unsigned char cdbuffer[CD_FRAMESIZE_RAW];
26 static unsigned char cdbuffer_compressed[CD_FRAMESIZE_RAW + 100];
27 static int current_sector;
28
29 struct CdrStat;
30 extern long CDR__getStatus(struct CdrStat *stat);
31
32 struct CdrStat
33 {
34         unsigned long Type;
35         unsigned long Status;
36         unsigned char Time[3]; // current playing time
37 };
38
39 struct trackinfo {
40         enum {DATA, CDDA} type;
41         char start[3];          // MSF-format
42         char length[3];         // MSF-format
43 };
44
45 #define MAXTRACKS 100 /* How many tracks can a CD hold? */
46
47 static int numtracks = 0;
48
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))
51
52 // return Starting and Ending Track
53 // buffer:
54 //  byte 0 - start track
55 //  byte 1 - end track
56 static long CDRgetTN(unsigned char *buffer)
57 {
58         buffer[0] = 1;
59         buffer[1] = numtracks > 0 ? numtracks : 1;
60
61         return 0;
62 }
63
64 // return Track Time
65 // buffer:
66 //  byte 0 - frame
67 //  byte 1 - second
68 //  byte 2 - minute
69 static long CDRgetTD(unsigned char track, unsigned char *buffer)
70 {
71         buffer[2] = 0;
72         buffer[1] = 2;
73         buffer[0] = 0;
74
75         return 0;
76 }
77
78 // read track
79 // time: byte 0 - minute; byte 1 - second; byte 2 - frame
80 // uses bcd format
81 static long CDRreadTrack(unsigned char *time)
82 {
83         unsigned int start_byte, size;
84         unsigned long cdbuffer_size;
85         int ret, sector;
86
87         if (cd_file == NULL)
88                 return -1;
89
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);
94                 return 0;
95         }
96
97         if (sector >= cd_index_len) {
98                 fprintf(stderr, "sector %d is past track end\n", sector);
99                 return -1;
100         }
101
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: ",
105                         sector, start_byte);
106                 perror(NULL);
107                 return -1;
108         }
109
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);
113                 return -1;
114         }
115
116         if (fread(cdbuffer_compressed, 1, size, cd_file) != size) {
117                 fprintf(stderr, "read error for sector %d at %x: ",
118                         sector, start_byte);
119                 perror(NULL);
120                 return -1;
121         }
122
123         cdbuffer_size = sizeof(cdbuffer);
124         ret = uncompress(cdbuffer, &cdbuffer_size, cdbuffer_compressed, size);
125         if (ret != 0) {
126                 fprintf(stderr, "uncompress failed with %d for sector %d\n", ret, sector);
127                 return -1;
128         }
129         if (cdbuffer_size != sizeof(cdbuffer))
130                 printf("%lu != %d\n", cdbuffer_size, sizeof(cdbuffer));
131
132         // done at last!
133         current_sector = sector;
134         return 0;
135 }
136
137 // return read track
138 static unsigned char *CDRgetBuffer(void)
139 {
140         return cdbuffer + 12;
141 }
142
143 // plays cdda audio
144 // sector: byte 0 - minute; byte 1 - second; byte 2 - frame
145 // does NOT uses bcd format
146 static long CDRplay(unsigned char *time)
147 {
148         return 0;
149 }
150
151 // stops cdda audio
152 static long CDRstop(void)
153 {
154         return 0;
155 }
156
157 // gets subchannel data
158 static unsigned char* CDRgetBufferSub(void)
159 {
160         return NULL;
161 }
162
163 static long CDRgetStatus(struct CdrStat *stat) {
164         CDR__getStatus(stat);
165
166         stat->Type = 0x01;
167
168         return 0;
169 }
170
171 static long CDRclose(void)
172 {
173         if (cd_file != NULL) {
174                 fclose(cd_file);
175                 cd_file = NULL;
176         }
177         if (cd_index_table != NULL) {
178                 free(cd_index_table);
179                 cd_index_table = NULL;
180         }
181         return 0;
182 }
183
184 static long CDRshutdown(void)
185 {
186         return CDRclose();
187 }
188
189 static long CDRinit(void)
190 {
191         return 0; // do nothing
192 }
193
194 // This function is invoked by the front-end when opening an ISO
195 // file for playback
196 static long CDRopen(void)
197 {
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
202         struct {
203                 unsigned int offset;
204                 unsigned short size;
205         } __attribute__((packed)) ztab_entry;
206         char table_fname[256];
207         long table_size;
208         int i, ret;
209         FILE *f;
210
211         if (cd_file != NULL)
212                 return 0; // it's already open
213
214         numtracks = 0;
215
216         if (cd_fname == NULL)
217                 return -1;
218
219         snprintf(table_fname, sizeof(table_fname), "%s.table", cd_fname);
220         f = fopen(table_fname, "rb");
221         if (f == NULL) {
222                 fprintf(stderr, "missing file: %s: ", table_fname);
223                 perror(NULL);
224                 return -1;
225         }
226
227         ret = fseek(f, 0, SEEK_END);
228         if (ret != 0) {
229                 fprintf(stderr, "failed to seek\n");
230                 goto fail_table_io;
231         }
232         table_size = ftell(f);
233         fseek(f, 0, SEEK_SET);
234
235         if (table_size > 2 * 1024 * 1024) {
236                 fprintf(stderr, ".table too large\n");
237                 goto fail_table_io;
238         }
239
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)
243                 goto fail_table_io;
244
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;
250                 }
251                 cd_index_table[i] = ztab_entry.offset;
252         }
253         // fake entry, so that we know last compressed block size
254         cd_index_table[i] = ztab_entry.offset + ztab_entry.size;
255
256         cd_file = fopen(cd_fname, "rb");
257         if (cd_file == NULL) {
258                 fprintf(stderr, "faied to open: %s: ", table_fname);
259                 perror(NULL);
260                 goto fail_img;
261         }
262         fclose(f);
263
264         printf("Loaded compressed CD Image: %s.\n", cd_fname);
265         current_sector = -1;
266
267         return 0;
268
269 fail_img:
270 fail_table_io_read:
271         free(cd_index_table);
272         cd_index_table = NULL;
273 fail_table_io:
274         fclose(f);
275         return -1;
276 }
277
278 #define FUNC(n) { #n, n }
279
280 static const struct {
281         const char *name;
282         void *func;
283 } plugin_funcs[] = {
284         /* CDR */
285         FUNC(CDRinit),
286         FUNC(CDRshutdown),
287         FUNC(CDRopen),
288         FUNC(CDRclose),
289         FUNC(CDRgetTN),
290         FUNC(CDRgetTD),
291         FUNC(CDRreadTrack),
292         FUNC(CDRgetBuffer),
293         FUNC(CDRgetBufferSub),
294         FUNC(CDRplay),
295         FUNC(CDRstop),
296         FUNC(CDRgetStatus),
297 };
298
299 void cdrcimg_set_fname(const char *fname)
300 {
301         cd_fname = fname;
302 }
303
304 void *cdrcimg_get_sym(const char *sym)
305 {
306         int i;
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;
310         return NULL;
311 }
312