Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/yabause/src/cdbase.c
2 views
1
/* Copyright 2004-2008 Theo Berkau
2
Copyright 2005 Joost Peters
3
Copyright 2005-2006 Guillaume Duhamel
4
5
This file is part of Yabause.
6
7
Yabause is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or
10
(at your option) any later version.
11
12
Yabause is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
16
17
You should have received a copy of the GNU General Public License
18
along with Yabause; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
*/
21
22
#include <string.h>
23
#include <stdlib.h>
24
#include <assert.h>
25
#include "cdbase.h"
26
#include "error.h"
27
#include "debug.h"
28
29
//////////////////////////////////////////////////////////////////////////////
30
31
// Contains the Dummy and ISO CD Interfaces
32
33
static int DummyCDInit(const char *);
34
static void DummyCDDeInit(void);
35
static int DummyCDGetStatus(void);
36
static s32 DummyCDReadTOC(u32 *);
37
static int DummyCDReadSectorFAD(u32, void *);
38
static void DummyCDReadAheadFAD(u32);
39
40
CDInterface DummyCD = {
41
CDCORE_DUMMY,
42
"Dummy CD Drive",
43
DummyCDInit,
44
DummyCDDeInit,
45
DummyCDGetStatus,
46
DummyCDReadTOC,
47
DummyCDReadSectorFAD,
48
DummyCDReadAheadFAD,
49
};
50
51
static int ISOCDInit(const char *);
52
static void ISOCDDeInit(void);
53
static int ISOCDGetStatus(void);
54
static s32 ISOCDReadTOC(u32 *);
55
static int ISOCDReadSectorFAD(u32, void *);
56
static void ISOCDReadAheadFAD(u32);
57
58
CDInterface ISOCD = {
59
CDCORE_ISO,
60
"ISO-File Virtual Drive",
61
ISOCDInit,
62
ISOCDDeInit,
63
ISOCDGetStatus,
64
ISOCDReadTOC,
65
ISOCDReadSectorFAD,
66
ISOCDReadAheadFAD,
67
};
68
69
//////////////////////////////////////////////////////////////////////////////
70
// Dummy Interface
71
//////////////////////////////////////////////////////////////////////////////
72
73
static int DummyCDInit(UNUSED const char *cdrom_name)
74
{
75
// Initialization function. cdrom_name can be whatever you want it to
76
// be. Obviously with some ports(e.g. the dreamcast port) you probably
77
// won't even use it.
78
return 0;
79
}
80
81
//////////////////////////////////////////////////////////////////////////////
82
83
static void DummyCDDeInit(void)
84
{
85
// Cleanup function. Enough said.
86
}
87
88
//////////////////////////////////////////////////////////////////////////////
89
90
static int DummyCDGetStatus(void)
91
{
92
// This function is called periodically to see what the status of the
93
// drive is.
94
//
95
// Should return one of the following values:
96
// 0 - CD Present, disc spinning
97
// 1 - CD Present, disc not spinning
98
// 2 - CD not present
99
// 3 - Tray open
100
//
101
// If you really don't want to bother too much with this function, just
102
// return status 0. Though it is kind of nice when the bios's cd
103
// player, etc. recognizes when you've ejected the tray and popped in
104
// another disc.
105
106
return 0;
107
}
108
109
//////////////////////////////////////////////////////////////////////////////
110
111
static s32 DummyCDReadTOC(UNUSED u32 *TOC)
112
{
113
// The format of TOC is as follows:
114
// TOC[0] - TOC[98] are meant for tracks 1-99. Each entry has the
115
// following format:
116
// bits 0 - 23: track FAD address
117
// bits 24 - 27: track addr
118
// bits 28 - 31: track ctrl
119
//
120
// Any Unused tracks should be set to 0xFFFFFFFF
121
//
122
// TOC[99] - Point A0 information
123
// Uses the following format:
124
// bits 0 - 7: PFRAME(should always be 0)
125
// bits 7 - 15: PSEC(Program area format: 0x00 - CDDA or CDROM,
126
// 0x10 - CDI, 0x20 - CDROM-XA)
127
// bits 16 - 23: PMIN(first track's number)
128
// bits 24 - 27: first track's addr
129
// bits 28 - 31: first track's ctrl
130
//
131
// TOC[100] - Point A1 information
132
// Uses the following format:
133
// bits 0 - 7: PFRAME(should always be 0)
134
// bits 7 - 15: PSEC(should always be 0)
135
// bits 16 - 23: PMIN(last track's number)
136
// bits 24 - 27: last track's addr
137
// bits 28 - 31: last track's ctrl
138
//
139
// TOC[101] - Point A2 information
140
// Uses the following format:
141
// bits 0 - 23: leadout FAD address
142
// bits 24 - 27: leadout's addr
143
// bits 28 - 31: leadout's ctrl
144
//
145
// Special Note: To convert from LBA/LSN to FAD, add 150.
146
147
return 0;
148
}
149
150
//////////////////////////////////////////////////////////////////////////////
151
152
static int DummyCDReadSectorFAD(UNUSED u32 FAD, void * buffer)
153
{
154
// This function is supposed to read exactly 1 -RAW- 2352-byte sector
155
// at the specified FAD address to buffer. Should return true if
156
// successful, false if there was an error.
157
//
158
// Special Note: To convert from FAD to LBA/LSN, minus 150.
159
//
160
// The whole process needed to be changed since I need more control
161
// over sector detection, etc. Not to mention it means less work for
162
// the porter since they only have to implement raw sector reading as
163
// opposed to implementing mode 1, mode 2 form1/form2, -and- raw
164
// sector reading.
165
166
memset(buffer, 0, 2352);
167
168
return 1;
169
}
170
171
//////////////////////////////////////////////////////////////////////////////
172
173
static void DummyCDReadAheadFAD(UNUSED u32 FAD)
174
{
175
// This function is called to tell the driver which sector (FAD
176
// address) is expected to be read next. If the driver supports
177
// read-ahead, it should start reading the given sector in the
178
// background while the emulation continues, so that when the
179
// sector is actually read with ReadSectorFAD() it'll be available
180
// immediately. (Note that there's no guarantee this sector will
181
// actually be requested--the emulated CD might be stopped before
182
// the sector is read, for example.)
183
//
184
// This function should NOT block. If the driver can't perform
185
// asynchronous reads (or you just don't want to bother handling
186
// them), make this function a no-op and just read sectors
187
// normally.
188
}
189
190
//////////////////////////////////////////////////////////////////////////////
191
// ISO Interface
192
//////////////////////////////////////////////////////////////////////////////
193
194
static const s8 syncHdr[12] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
195
static FILE *isofile=NULL;
196
static int isofilesize=0;
197
static int bytesPerSector = 0;
198
static int isbincue = 0;
199
static u32 isoTOC[102];
200
static struct
201
{
202
u32 fadstart;
203
u32 fileoffset;
204
} isooffsettbl[100];
205
206
#define MSF_TO_FAD(m,s,f) ((m * 4500) + (s * 75) + f)
207
208
//////////////////////////////////////////////////////////////////////////////
209
210
static int InitBinCue(const char *cuefilename)
211
{
212
u32 size;
213
char *tempbuffer, *tempbuffer2;
214
unsigned int tracknum;
215
unsigned int indexnum, min, sec, frame;
216
unsigned int pregap=0;
217
char *p, *p2;
218
219
fseek(isofile, 0, SEEK_END);
220
size = ftell(isofile);
221
fseek(isofile, 0, SEEK_SET);
222
223
// Allocate buffer with enough space for reading cue
224
if ((tempbuffer = (char *)calloc(size, 1)) == NULL)
225
return -1;
226
227
// Skip image filename
228
if (fscanf(isofile, "FILE \"%*[^\"]\" %*s\r\n") == EOF)
229
{
230
free(tempbuffer);
231
return -1;
232
}
233
234
// Time to generate TOC
235
for (;;)
236
{
237
// Retrieve a line in cue
238
if (fscanf(isofile, "%s", tempbuffer) == EOF)
239
break;
240
241
// Figure out what it is
242
if (strncmp(tempbuffer, "TRACK", 5) == 0)
243
{
244
// Handle accordingly
245
if (fscanf(isofile, "%d %[^\r\n]\r\n", &tracknum, tempbuffer) == EOF)
246
break;
247
248
if (strncmp(tempbuffer, "MODE1", 5) == 0 ||
249
strncmp(tempbuffer, "MODE2", 5) == 0)
250
{
251
// Figure out the track sector size
252
bytesPerSector = atoi(tempbuffer + 6);
253
254
// Update toc entry
255
isoTOC[tracknum-1] = 0x41000000;
256
}
257
else if (strncmp(tempbuffer, "AUDIO", 5) == 0)
258
{
259
// fix me
260
// Update toc entry
261
isoTOC[tracknum-1] = 0x01000000;
262
}
263
}
264
else if (strncmp(tempbuffer, "INDEX", 5) == 0)
265
{
266
// Handle accordingly
267
268
if (fscanf(isofile, "%d %d:%d:%d\r\n", &indexnum, &min, &sec, &frame) == EOF)
269
break;
270
271
if (indexnum == 1)
272
{
273
// Update toc entry
274
isoTOC[tracknum-1] = (isoTOC[tracknum-1] & 0xFF000000) | (MSF_TO_FAD(min, sec, frame) + pregap + 150);
275
276
isooffsettbl[tracknum-1].fadstart = MSF_TO_FAD(min, sec, frame) + pregap + 150;
277
isooffsettbl[tracknum-1].fileoffset = pregap + 150;
278
}
279
}
280
else if (strncmp(tempbuffer, "PREGAP", 5) == 0)
281
{
282
if (fscanf(isofile, "%d:%d:%d\r\n", &min, &sec, &frame) == EOF)
283
break;
284
285
pregap += MSF_TO_FAD(min, sec, frame);
286
}
287
else if (strncmp(tempbuffer, "POSTGAP", 5) == 0)
288
{
289
if (fscanf(isofile, "%d:%d:%d\r\n", &min, &sec, &frame) == EOF)
290
break;
291
}
292
}
293
294
// Go back, retrieve image filename
295
fseek(isofile, 0, SEEK_SET);
296
fscanf(isofile, "FILE \"%[^\"]\" %*s\r\n", tempbuffer);
297
fclose(isofile);
298
299
// Now go and open up the image file, figure out its size, etc.
300
if ((isofile = fopen(tempbuffer, "rb")) == NULL)
301
{
302
// Ok, exact path didn't work. Let's trim the path and try opening the
303
// file from the same directory as the cue.
304
305
// find the start of filename
306
p = tempbuffer;
307
308
for (;;)
309
{
310
if (strcspn(p, "/\\") == strlen(p))
311
break;
312
313
p += strcspn(p, "/\\") + 1;
314
}
315
316
// append directory of cue file with bin filename
317
if ((tempbuffer2 = (char *)calloc(strlen(cuefilename) + strlen(p) + 1, 1)) == NULL)
318
{
319
free(tempbuffer);
320
return -1;
321
}
322
323
// find end of path
324
p2 = (char *)cuefilename;
325
326
for (;;)
327
{
328
if (strcspn(p2, "/\\") == strlen(p2))
329
break;
330
p2 += strcspn(p2, "/\\") + 1;
331
}
332
333
// Make sure there was at least some kind of path, otherwise our
334
// second check is pretty useless
335
if (cuefilename == p2 && tempbuffer == p)
336
{
337
free(tempbuffer);
338
free(tempbuffer2);
339
return -1;
340
}
341
342
strncpy(tempbuffer2, cuefilename, p2 - cuefilename);
343
strcat(tempbuffer2, p);
344
345
// Let's give it another try
346
isofile = fopen(tempbuffer2, "rb");
347
free(tempbuffer2);
348
349
if (isofile == NULL)
350
{
351
YabSetError(YAB_ERR_FILENOTFOUND, tempbuffer);
352
free(tempbuffer);
353
return -1;
354
}
355
}
356
357
// buffer is no longer needed
358
free(tempbuffer);
359
360
fseek(isofile, 0, SEEK_END);
361
isofilesize = ftell(isofile);
362
fseek(isofile, 0, SEEK_SET);
363
364
// Now then, generate rest of TOC
365
isoTOC[99] = (isoTOC[0] & 0xFF000000) | 0x010000;
366
isoTOC[100] = (isoTOC[tracknum - 1] & 0xFF000000) | (tracknum << 16);
367
isoTOC[101] = (isoTOC[tracknum - 1] & 0xFF000000) | ((isofilesize / bytesPerSector) + pregap + 150);
368
369
isooffsettbl[tracknum].fileoffset = 0;
370
isooffsettbl[tracknum].fadstart = 0xFFFFFFFF;
371
372
return 0;
373
}
374
375
//////////////////////////////////////////////////////////////////////////////
376
377
static int ISOCDInit(const char * iso) {
378
char header[6];
379
380
memset(isoTOC, 0xFF, 0xCC * 2);
381
382
if (!iso)
383
return -1;
384
385
if (!(isofile = fopen(iso, "rb")))
386
{
387
YabSetError(YAB_ERR_FILENOTFOUND, (char *)iso);
388
return -1;
389
}
390
391
fread((void *)header, 1, 6, isofile);
392
393
// Figure out what kind of image format we're dealing with
394
if (strncmp(header, "FILE \"", 6) == 0)
395
{
396
// It's a BIN/CUE
397
isbincue = 1;
398
399
// Generate TOC for bin file
400
if (InitBinCue(iso) != 0)
401
{
402
if (isofile)
403
free(isofile);
404
return -1;
405
}
406
}
407
else
408
{
409
// Assume it's an ISO file
410
isbincue = 0;
411
412
fseek(isofile, 0, SEEK_END);
413
isofilesize = ftell(isofile);
414
415
if (0 == (isofilesize % 2048))
416
bytesPerSector = 2048;
417
else if (0 == (isofilesize % 2352))
418
bytesPerSector = 2352;
419
else
420
{
421
YabSetError(YAB_ERR_OTHER, "Unsupported CD image!\n");
422
423
return -1;
424
}
425
426
// Generate TOC
427
isoTOC[0] = 0x41000096;
428
isoTOC[99] = 0x41010000;
429
isoTOC[100] = 0x41010000;
430
isoTOC[101] = (0x41 << 24) | (isofilesize / bytesPerSector); //this isn't fully correct, but it does the job for now.
431
432
isooffsettbl[0].fileoffset = 150;
433
isooffsettbl[0].fadstart = 150;
434
isooffsettbl[1].fileoffset = 0;
435
isooffsettbl[1].fadstart = 0xFFFFFFFF;
436
}
437
438
return 0;
439
}
440
441
//////////////////////////////////////////////////////////////////////////////
442
443
static void ISOCDDeInit(void) {
444
if (isofile)
445
{
446
fclose(isofile);
447
}
448
}
449
450
//////////////////////////////////////////////////////////////////////////////
451
452
static int ISOCDGetStatus(void) {
453
return isofile != NULL ? 0 : 2;
454
}
455
456
//////////////////////////////////////////////////////////////////////////////
457
458
static s32 ISOCDReadTOC(u32 * TOC) {
459
memcpy(TOC, isoTOC, 0xCC * 2);
460
461
return (0xCC * 2);
462
}
463
464
//////////////////////////////////////////////////////////////////////////////
465
466
static int ISOCDReadSectorFAD(u32 FAD, void *buffer) {
467
int sector;
468
int i;
469
470
assert(isofile);
471
472
memset(buffer, 0, 2352);
473
474
for (i = 1; i < 100; i++)
475
{
476
if (FAD < isooffsettbl[i].fadstart)
477
{
478
sector = FAD - isooffsettbl[i-1].fileoffset;
479
break;
480
}
481
}
482
if (i == 100) {
483
CDLOG("Warning: Sector not found in track list");
484
return 0;
485
}
486
487
if ((sector * bytesPerSector) >= isofilesize) {
488
CDLOG("Warning: Trying to read beyond end of CD image! (sector: %d)\n", sector);
489
return 0;
490
}
491
492
fseek(isofile, sector * bytesPerSector, SEEK_SET);
493
494
if (2048 == bytesPerSector) {
495
memcpy(buffer, syncHdr, 12);
496
fread((char *)buffer + 0x10, bytesPerSector, 1, isofile);
497
} else { //2352
498
fread(buffer, bytesPerSector, 1, isofile);
499
}
500
501
return 1;
502
}
503
504
//////////////////////////////////////////////////////////////////////////////
505
506
static void ISOCDReadAheadFAD(UNUSED u32 FAD)
507
{
508
// No-op
509
}
510
511
//////////////////////////////////////////////////////////////////////////////
512
513
514