prepare for external gpu plugins
[pcsx_rearmed.git] / plugins / cdrcimg / cdrcimg.c
CommitLineData
47bf65ab 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
20static const char *cd_fname;
21static unsigned int *cd_index_table;
22static unsigned int cd_index_len;
23static FILE *cd_file;
24
25static unsigned char cdbuffer[CD_FRAMESIZE_RAW];
26static unsigned char cdbuffer_compressed[CD_FRAMESIZE_RAW + 100];
27static int current_sector;
28
29struct CdrStat;
30extern long CDR__getStatus(struct CdrStat *stat);
31
32struct CdrStat
33{
34 unsigned long Type;
35 unsigned long Status;
36 unsigned char Time[3]; // current playing time
37};
38
39struct 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
47static 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
56static 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
69static 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
81static 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
138static 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
146static long CDRplay(unsigned char *time)
147{
148 return 0;
149}
150
151// stops cdda audio
152static long CDRstop(void)
153{
154 return 0;
155}
156
157// gets subchannel data
158static unsigned char* CDRgetBufferSub(void)
159{
160 return NULL;
161}
162
163static long CDRgetStatus(struct CdrStat *stat) {
164 CDR__getStatus(stat);
165
166 stat->Type = 0x01;
167
168 return 0;
169}
170
171static 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
184static long CDRshutdown(void)
185{
186 return CDRclose();
187}
188
189static 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
196static 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
269fail_img:
270fail_table_io_read:
271 free(cd_index_table);
272 cd_index_table = NULL;
273fail_table_io:
274 fclose(f);
275 return -1;
276}
277
278#define FUNC(n) { #n, n }
279
280static 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
299void cdrcimg_set_fname(const char *fname)
300{
301 cd_fname = fname;
302}
303
304void *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