1
/* Mednafen - Multi-system Emulator
3
* Subchannel Q CRC Code: Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.de>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
POSTGAP in CUE sheets may not be handled properly, should the directive automatically increment the index number?
25
INDEX nn where 02 <= nn <= 99 is not supported in CUE sheets.
27
TOC reading code is extremely barebones, leaving out support for more esoteric features.
29
A PREGAP statement in the first track definition in a CUE sheet may not work properly(depends on what is proper);
30
it will be added onto the implicit default 00:02:00 of pregap.
32
Trying to read sectors at an LBA of less than 0 is not supported. TODO: support it(at least up to -150).
35
#define _CDROMFILE_INTERNAL
36
#include "../mednafen.h"
38
#include <sys/types.h>
42
#include <cdio/cdio.h>
49
#include <trio/trio.h>
51
#include "../general.h"
52
#include "../endian.h"
55
#include "cdromfile.h"
56
#include "dvdisaster.h"
59
#include "audioreader.h"
63
struct CDRFILE_TRACK_INFO
67
CD_Track_Format_t Format;
70
//track_format_t Format;
80
int32 sectors; // Not including pregap sectors!
82
bool FirstFileInstance;
83
bool RawAudioMSBFirst;
85
unsigned int SubchannelMode;
90
int16 AudioBuf[588 * 2];
95
int64 Offset; // Offset in [..TODO..]
99
bool FirstFileInstance;
100
bool RawAudioMSBFirst;
101
unsigned int SubchannelMode;
103
uint32 LastSamplePos;
104
AudioReader *AReader;
117
static std::vector<CD_Chunk> Chunks;
125
CDRFILE_TRACK_INFO Tracks[100]; // Track #0(HMM?) through 99
129
bool CanMMC; // TODO: Can run MMC commands directly.
130
bool CanRawRead; // TODO: Can do raw reads of data sectors(of parity and headers etc, 2352 bytes total)
131
bool CanSubRead; // TODO: Can read subchannel data.
136
// 1-bit per sector on the physical CD. If set, don't read that sector.
137
static uint8 SkipSectorRead[65536];
139
// lookup table for crc calculation
140
static uint16 subq_crctab[256] =
142
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
143
0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
144
0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
145
0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
146
0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
147
0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
148
0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
149
0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
150
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
151
0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
152
0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
153
0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
154
0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
155
0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
156
0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
157
0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
158
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
159
0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
160
0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
161
0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
162
0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
163
0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
164
0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
165
0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
166
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
167
0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
168
0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
169
0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
170
0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
173
bool cdrfile_check_subq_checksum(uint8 *SubQBuf)
176
uint16 stored_crc = 0;
178
stored_crc = SubQBuf[0xA] << 8;
179
stored_crc |= SubQBuf[0xB];
181
for(int i = 0; i < 0xA; i++)
182
crc = subq_crctab[(crc >> 8) ^ SubQBuf[i]] ^ (crc << 8);
186
return(crc == stored_crc);
190
// MakeSubPQ will OR the simulated P and Q subchannel data into SubPWBuf.
191
static void MakeSubPQ(const CDRFile *p_cdrfile, uint32 lba, uint8 *SubPWBuf);
194
void cdrfile_deinterleave_subq(const uint8 *SubPWBuf, uint8 *qbuf)
196
memset(qbuf, 0, 0xC);
198
for(int i = 0; i < 96; i++)
200
qbuf[i >> 3] |= ((SubPWBuf[i] >> 6) & 0x1) << (7 - (i & 0x7));
204
static char *UnQuotify(char *src, char *dest)
207
bool already_normal = 0;
211
if(*src == ' ' || *src == '\t')
248
static uint32 GetSectorCount(CDRFILE_TRACK_INFO *track)
250
// - track->FileOffset is really only meaningful for TOC files
251
// ...and the last track for CUE/BIN
252
if(track->DIFormat == DI_FORMAT_AUDIO)
255
return(((track->AReader->FrameCount() * 4) - track->FileOffset) / 2352);
258
struct stat stat_buf;
259
fstat(fileno(track->fp), &stat_buf);
261
//printf("%d %d %d\n", (int)stat_buf.st_size, (int)track->FileOffset, (int)stat_buf.st_size - (int)track->FileOffset);
262
if(track->SubchannelMode)
263
return((stat_buf.st_size - track->FileOffset) / (2352 + 96));
265
return((stat_buf.st_size - track->FileOffset) / 2352);
270
struct stat stat_buf;
272
if(fstat(fileno(track->fp), &stat_buf))
274
ErrnoHolder ene(errno);
276
printf("Error: %s\n", ene.StrError());
280
return((stat_buf.st_size - track->FileOffset) / DI_Size_Table[track->DIFormat]);
286
void cdrfile_destroy(CDRFile *p_cdrfile)
289
if(p_cdrfile->p_cdio)
290
cdio_destroy(p_cdrfile->p_cdio);
295
for(track = p_cdrfile->FirstTrack; track < (p_cdrfile->FirstTrack + p_cdrfile->NumTracks); track++)
297
CDRFILE_TRACK_INFO *this_track = &p_cdrfile->Tracks[track];
299
if(this_track->FirstFileInstance)
301
if(p_cdrfile->Tracks[track].AReader)
303
delete p_cdrfile->Tracks[track].AReader;
304
p_cdrfile->Tracks[track].AReader = NULL;
306
else if(this_track->fp)
307
fclose(this_track->fp);
314
static bool ParseTOCFileLineInfo(CDRFILE_TRACK_INFO *track, const int tracknum, const char *filename, const char *binoffset, const char *msfoffset, const char *length)
316
long offset = 0; // In bytes!
322
if(!MDFN_IsFIROPSafe(filename))
324
MDFN_printf(_("Referenced path \"%s\" is potentially unsafe. See \"filesys.untrusted_fip_check\" setting.\n"), filename);
328
std::string efn = MDFN_MakeFName(MDFNMKF_AUX, 0, filename);
330
if(NULL == (track->fp = fopen(efn.c_str(), "rb")))
332
ErrnoHolder ene(errno);
334
MDFN_printf(_("Could not open referenced file \"%s\": %s\n"), efn.c_str(), ene.StrError());
338
if(strlen(filename) >= 4 && !strcasecmp(filename + strlen(filename) - 4, ".wav"))
340
track->AReader = AR_Open(track->fp);
346
sector_mult = DI_Size_Table[track->DIFormat];
348
if(track->SubchannelMode)
351
if(binoffset && trio_sscanf(binoffset, "%ld", &tmp_long) == 1)
356
if(msfoffset && trio_sscanf(msfoffset, "%d:%d:%d", &m, &s, &f) == 3)
358
offset += ((m * 60 + s) * 75 + f) * sector_mult;
361
track->FileOffset = offset; // Make sure this is set before calling GetSectorCount()!
362
sectors = GetSectorCount(track);
363
//printf("Track: %d, offset: %ld, %ld\n", tracknum, offset, sectors);
369
if(trio_sscanf(length, "%d:%d:%d", &m, &s, &f) == 3)
370
tmp_long = (m * 60 + s) * 75 + f;
371
else if(track->DIFormat == DI_FORMAT_AUDIO)
375
tmp_long = strtol(length, &endptr, 10);
387
if(tmp_long > sectors)
389
MDFN_printf(_("Length specified in TOC file for track %d is too large by %ld sectors!\n"), tracknum, (long)(tmp_long - sectors));
395
track->FirstFileInstance = 1;
396
track->sectors = sectors;
402
static void DetermineFeatures(CDRFile *p_cdrfile)
407
mmc_cdb_t cdb = {{0, }};
409
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_MODE_SENSE_10);
411
memset(buf, 0, sizeof(buf));
415
cdb.field[7] = sizeof(buf) >> 8;
416
cdb.field[8] = sizeof(buf) & 0xFF;
418
p_cdrfile->CanMMC = false;
419
p_cdrfile->CanRawRead = false;
420
p_cdrfile->CanSubRead = false;
422
if(mmc_run_cmd (p_cdrfile->p_cdio, MMC_TIMEOUT_DEFAULT,
428
MDFN_printf(_("MMC [MODE SENSE 10] command failed.\n"));
434
if(page[0] != 0x2A || page[1] < 0x14)
435
MDFN_printf(_("MMC [MODE SENSE 10] command returned bogus data for mode page 0x2A?\n"));
438
//printf("%02x\n", page[5]);
439
p_cdrfile->CanMMC = true;
441
p_cdrfile->CanSubRead = true;
444
//for(int i = 0; i < 256; i++)
445
// printf("%02x\n", buf[i]);
446
// p_cdrfile->CanMMC = false;
447
MDFN_printf("Using MMC commands directly: %s\n", p_cdrfile->CanMMC ? _("Yes") : _("No"));
448
MDFN_printf("Performing subchannel R-W Reading: %s\n", p_cdrfile->CanSubRead ? _("Yes") : _("No"));
453
static CDRFile *PhysOpen(const char *path)
455
CDRFile *ret = (CDRFile *)calloc(1, sizeof(CDRFile));
462
GetFileBase("cdrom");
464
devices = cdio_get_devices(DRIVER_DEVICE);
468
MDFN_printf(_("Connected physical devices:\n"));
472
MDFN_printf("%s\n", *parseit);
477
if(!parseit || parseit == devices)
479
MDFN_PrintError(_("No CDROM drives detected(or no disc present)."));
481
cdio_free_device_list(devices);
487
cdio_free_device_list(devices);
489
p_cdio = cdio_open_cd(path); //, DRIVER_UNKNOWN); //NULL, DRIVER_UNKNOWN);
496
ret->p_cdio = p_cdio;
498
ret->FirstTrack = cdio_get_first_track_num(ret->p_cdio);
499
ret->NumTracks = cdio_get_num_tracks(ret->p_cdio);
500
ret->total_sectors = cdio_stat_size(ret->p_cdio);
502
if(ret->FirstTrack > 99)
504
MDFN_PrintError(_("Invalid first track: %d\n"), ret->FirstTrack);
506
cdio_destroy(p_cdio);
510
if(ret->NumTracks > 100)
512
MDFN_PrintError(_("Invalid track count: %d\n"), ret->NumTracks);
514
cdio_destroy(p_cdio);
518
for(int32 track = ret->FirstTrack; track < (ret->FirstTrack + ret->NumTracks); track++)
520
memset(&ret->Tracks[track], 0, sizeof(CDRFILE_TRACK_INFO));
522
ret->Tracks[track].sectors = cdio_get_track_sec_count(ret->p_cdio, track);
523
ret->Tracks[track].LBA = cdio_get_track_lsn(ret->p_cdio, track);
525
switch(cdio_get_track_format(ret->p_cdio, track))
527
case TRACK_FORMAT_AUDIO:
528
ret->Tracks[track].Format = CD_TRACK_FORMAT_AUDIO;
532
ret->Tracks[track].Format = CD_TRACK_FORMAT_DATA;
538
// Determine how we can read this CD.
540
DetermineFeatures(ret);
543
memset(SkipSectorRead, 0, sizeof(SkipSectorRead));
545
// Determine/Calculate unreadable portions of the disc.
547
int32 a_to_d_skip = 0; // In frames;
549
memset(SkipSectorRead, 0, sizeof(SkipSectorRead));
551
// Find track type transitions.
552
for(int track = ret->FirstTrack + 1; track < (ret->FirstTrack + ret->NumTracks); track++)
554
bool transition = false;
556
if(ret->Tracks[track - 1].Format != ret->Tracks[track].Format)
561
int32 lba = ret->Tracks[track].LBA;
562
uint8 dummy_buf[2352 + 96];
563
static const int test_offsets[] = { -75 * 4, -75 * 3 };
565
for(int frame = -75 * 4; frame < 0; frame += 75)
567
for(int subframe = -1; subframe <= 1; subframe++)
569
int32 eff_offset = frame + subframe;
570
int32 eff_lba = lba + eff_offset;
573
if(!cdrfile_read_raw_sector(ret, dummy_buf, eff_lba))
575
printf("Failure: %d\n", eff_lba);
576
for(int32 il = eff_lba; il < ret->Tracks[track].LBA; il++)
578
printf(" Skipping: %d\n", il);
579
SkipSectorRead[il >> 3] |= 1 << (il & 7);
584
printf("Success: %d\n", eff_lba);
603
static CDRFile *ImageOpen(const char *path)
605
CDRFile *ret = (CDRFile *)calloc(1, sizeof(CDRFile));
609
// Assign opposite maximum values so our tests will work!
613
if(!(fp = fopen(path, "rb")))
615
ErrnoHolder ene(errno);
617
MDFN_PrintError(_("Error opening CUE sheet/TOC \"%s\": %s\n"), path, ene.StrError());
624
int32 active_track = -1;
625
int32 AutoTrackInc = 1; // For TOC
626
CDRFILE_TRACK_INFO TmpTrack;
627
memset(&TmpTrack, 0, sizeof(TmpTrack));
629
while(fgets(linebuf, 512, fp) > 0)
631
char cmdbuf[512], raw_args[512], args[4][512];
637
args[0][0] = args[1][0] = args[2][0] = args[3][0] = 0;
639
if(!strncasecmp(linebuf, "CD_ROM", 6) || !strncasecmp(linebuf, "CD_DA", 5) || !strncasecmp(linebuf, "CD_ROM_XA", 9))
642
puts("TOC file detected.");
647
char *ss_loc = strstr(linebuf, "//");
650
ss_loc[0] = '\n'; // For consistency!
655
trio_sscanf(linebuf, "%s %[^\r\n]", cmdbuf, raw_args);
657
if(!strcasecmp(cmdbuf, "CD_ROM") || !strcasecmp(cmdbuf, "CD_DA"))
660
UnQuotify(UnQuotify(UnQuotify(UnQuotify(raw_args, args[0]), args[1]), args[2]), args[3]);
680
if(!strcasecmp(cmdbuf, "TRACK"))
682
if(active_track >= 0)
684
memcpy(&ret->Tracks[active_track], &TmpTrack, sizeof(TmpTrack));
685
memset(&TmpTrack, 0, sizeof(TmpTrack));
689
if(AutoTrackInc > 99)
691
MDFN_printf(_("Invalid track number: %d\n"), AutoTrackInc);
696
active_track = AutoTrackInc++;
697
if(active_track < FirstTrack)
698
FirstTrack = active_track;
699
if(active_track > LastTrack)
700
LastTrack = active_track;
703
for(format_lookup = 0; format_lookup < _DI_FORMAT_COUNT; format_lookup++)
705
if(!strcasecmp(args[0], DI_CDRDAO_Strings[format_lookup]))
707
TmpTrack.DIFormat = format_lookup;
712
if(format_lookup == _DI_FORMAT_COUNT)
714
MDFN_printf(_("Invalid track format: %s\n"), args[0]);
719
if(TmpTrack.DIFormat == DI_FORMAT_AUDIO)
720
TmpTrack.RawAudioMSBFirst = TRUE; // Silly cdrdao...
722
if(!strcasecmp(args[1], "RW"))
724
TmpTrack.SubchannelMode = CDRF_SUBM_RW;
725
MDFN_printf(_("\"RW\" format subchannel data not supported, only \"RW_RAW\" is!\n"));
729
else if(!strcasecmp(args[1], "RW_RAW"))
730
TmpTrack.SubchannelMode = CDRF_SUBM_RW_RAW;
733
else if(!strcasecmp(cmdbuf, "SILENCE"))
737
else if(!strcasecmp(cmdbuf, "ZERO"))
741
else if(!strcasecmp(cmdbuf, "FILE") || !strcasecmp(cmdbuf, "AUDIOFILE"))
743
const char *binoffset = NULL;
744
const char *msfoffset = NULL;
745
const char *length = NULL;
747
if(args[1][0] == '#')
749
binoffset = args[1] + 1;
758
//printf("%s, %s, %s, %s\n", args[0], binoffset, msfoffset, length);
759
if(!ParseTOCFileLineInfo(&TmpTrack, active_track, args[0], binoffset, msfoffset, length))
765
else if(!strcasecmp(cmdbuf, "DATAFILE"))
767
const char *binoffset = NULL;
768
const char *length = NULL;
770
if(args[1][0] == '#')
772
binoffset = args[1] + 1;
778
if(!ParseTOCFileLineInfo(&TmpTrack, active_track, args[0], binoffset, NULL, length))
784
else if(!strcasecmp(cmdbuf, "INDEX"))
788
else if(!strcasecmp(cmdbuf, "PREGAP"))
792
MDFN_printf(_("Command %s is outside of a TRACK definition!\n"), cmdbuf);
797
trio_sscanf(args[0], "%d:%d:%d", &m, &s, &f);
798
TmpTrack.pregap = (m * 60 + s) * 75 + f;
800
else if(!strcasecmp(cmdbuf, "START"))
804
MDFN_printf(_("Command %s is outside of a TRACK definition!\n"), cmdbuf);
809
trio_sscanf(args[0], "%d:%d:%d", &m, &s, &f);
810
TmpTrack.pregap = (m * 60 + s) * 75 + f;
812
} /*********** END TOC HANDLING ************/
813
else // now for CUE sheet handling
815
if(!strcasecmp(cmdbuf, "FILE"))
817
if(active_track >= 0)
819
memcpy(&ret->Tracks[active_track], &TmpTrack, sizeof(TmpTrack));
820
memset(&TmpTrack, 0, sizeof(TmpTrack));
824
if(!MDFN_IsFIROPSafe(args[0]))
826
MDFN_printf(_("Referenced path \"%s\" is potentially unsafe. See \"filesys.untrusted_fip_check\" setting.\n"), args[0]);
830
std::string efn = MDFN_MakeFName(MDFNMKF_AUX, 0, args[0]);
832
if(NULL == (TmpTrack.fp = fopen(efn.c_str(), "rb")))
834
ErrnoHolder ene(errno);
836
MDFN_printf(_("Could not open referenced file \"%s\": %s\n"), efn.c_str(), ene.StrError());
840
TmpTrack.FirstFileInstance = 1;
841
if(!strcasecmp(args[1], "BINARY"))
843
//TmpTrack.Format = TRACK_FORMAT_DATA;
844
//struct stat stat_buf;
845
//fstat(fileno(TmpTrack.fp), &stat_buf);
846
//TmpTrack.sectors = stat_buf.st_size; // / 2048;
848
else if(!strcasecmp(args[1], "OGG") || !strcasecmp(args[1], "VORBIS") || !strcasecmp(args[1], "WAVE") || !strcasecmp(args[1], "WAV") || !strcasecmp(args[1], "PCM")
849
|| !strcasecmp(args[1], "MPC") || !strcasecmp(args[1], "MP+"))
851
TmpTrack.AReader = AR_Open(TmpTrack.fp);
852
if(!TmpTrack.AReader)
854
MDFN_printf(_("Unsupported audio track file format: %s\n"), args[0]);
861
MDFN_printf(_("Unsupported track format: %s\n"), args[1]);
866
else if(!strcasecmp(cmdbuf, "TRACK"))
868
if(active_track >= 0)
870
memcpy(&ret->Tracks[active_track], &TmpTrack, sizeof(TmpTrack));
871
TmpTrack.FirstFileInstance = 0;
873
TmpTrack.pregap_dv = 0;
874
TmpTrack.postgap = 0;
875
TmpTrack.index[0] = -1;
876
TmpTrack.index[1] = 0;
878
active_track = atoi(args[0]);
880
if(active_track < FirstTrack)
881
FirstTrack = active_track;
882
if(active_track > LastTrack)
883
LastTrack = active_track;
886
for(format_lookup = 0; format_lookup < _DI_FORMAT_COUNT; format_lookup++)
888
if(!strcasecmp(args[1], DI_CUE_Strings[format_lookup]))
890
TmpTrack.DIFormat = format_lookup;
895
if(format_lookup == _DI_FORMAT_COUNT)
897
MDFN_printf(_("Invalid track format: %s\n"), args[0]);
902
TmpTrack.sectors = GetSectorCount(&TmpTrack);
903
if(active_track < 0 || active_track > 99)
905
MDFN_printf(_("Invalid track number: %d\n"), active_track);
909
else if(!strcasecmp(cmdbuf, "INDEX"))
911
if(active_track >= 0)
914
trio_sscanf(args[1], "%d:%d:%d", &m, &s, &f);
916
if(!strcasecmp(args[0], "01") || !strcasecmp(args[0], "1"))
917
TmpTrack.index[1] = (m * 60 + s) * 75 + f;
918
else if(!strcasecmp(args[0], "00") || !strcasecmp(args[0], "0"))
919
TmpTrack.index[0] = (m * 60 + s) * 75 + f;
922
else if(!strcasecmp(cmdbuf, "PREGAP"))
924
if(active_track >= 0)
927
trio_sscanf(args[0], "%d:%d:%d", &m, &s, &f);
928
TmpTrack.pregap = (m * 60 + s) * 75 + f;
931
else if(!strcasecmp(cmdbuf, "POSTGAP"))
933
if(active_track >= 0)
936
trio_sscanf(args[0], "%d:%d:%d", &m, &s, &f);
937
TmpTrack.postgap = (m * 60 + s) * 75 + f;
942
MDFN_printf(_("Unknown CUE sheet directive \"%s\".\n"), cmdbuf);
944
} // end of CUE sheet handling
945
} // end of fgets() loop
949
ErrnoHolder ene(errno); // Is errno valid here?
952
MDFN_printf(_("Error reading TOC file: %s\n"), ene.StrError());
954
MDFN_printf(_("Error reading CUE sheet: %s\n"), ene.StrError());
959
if(active_track >= 0)
960
memcpy(&ret->Tracks[active_track], &TmpTrack, sizeof(TmpTrack));
962
if(FirstTrack > LastTrack)
964
MDFN_printf(_("No tracks found!\n"));
968
ret->FirstTrack = FirstTrack;
969
ret->NumTracks = 1 + LastTrack - FirstTrack;
971
int32 RunningLBA = 0;
975
for(int x = ret->FirstTrack; x < (ret->FirstTrack + ret->NumTracks); x++)
977
if(ret->Tracks[x].DIFormat == DI_FORMAT_AUDIO)
978
ret->Tracks[x].Format = CD_TRACK_FORMAT_AUDIO;
980
ret->Tracks[x].Format = CD_TRACK_FORMAT_DATA;
984
RunningLBA += ret->Tracks[x].pregap;
985
ret->Tracks[x].LBA = RunningLBA;
986
RunningLBA += ret->Tracks[x].sectors;
987
RunningLBA += ret->Tracks[x].postgap;
989
else // else handle CUE sheet...
991
if(ret->Tracks[x].FirstFileInstance)
997
RunningLBA += ret->Tracks[x].pregap;
999
ret->Tracks[x].pregap_dv = 0;
1001
if(ret->Tracks[x].index[0] != -1)
1002
ret->Tracks[x].pregap_dv = ret->Tracks[x].index[1] - ret->Tracks[x].index[0];
1004
FileOffset += ret->Tracks[x].pregap_dv * DI_Size_Table[ret->Tracks[x].DIFormat];
1006
RunningLBA += ret->Tracks[x].pregap_dv;
1008
ret->Tracks[x].LBA = RunningLBA;
1010
// Make sure this is set before the call to GetSectorCount() for the last track sector count fix.
1011
ret->Tracks[x].FileOffset = FileOffset;
1013
if((x + 1) >= (ret->FirstTrack + ret->NumTracks))
1015
if(!(ret->Tracks[x].FirstFileInstance))
1017
// This will fix the last sector count for CUE+BIN
1018
ret->Tracks[x].sectors = GetSectorCount(&ret->Tracks[x]);
1021
else if(ret->Tracks[x+1].FirstFileInstance)
1023
//RunningLBA += ret->Tracks[x].sectors;
1027
// Fix the sector count if we're CUE+BIN
1028
if(ret->Tracks[x + 1].index[0] == -1)
1029
ret->Tracks[x].sectors = ret->Tracks[x + 1].index[1] - ret->Tracks[x].index[1];
1031
ret->Tracks[x].sectors = ret->Tracks[x + 1].index[0] - ret->Tracks[x].index[1]; //ret->Tracks[x + 1].index - ret->Tracks[x].index;
1034
//printf("Poo: %d %d\n", x, ret->Tracks[x].sectors);
1035
RunningLBA += ret->Tracks[x].sectors;
1036
RunningLBA += ret->Tracks[x].postgap;
1038
//printf("%d, %ld %d %d %d %d\n", x, FileOffset, ret->Tracks[x].index, ret->Tracks[x].pregap, ret->Tracks[x].sectors, ret->Tracks[x].LBA);
1040
FileOffset += ret->Tracks[x].sectors * DI_Size_Table[ret->Tracks[x].DIFormat];
1041
} // end to cue sheet handling
1042
} // end to track loop
1044
ret->total_sectors = RunningLBA;
1050
CDRFile *cdrfile_open(const char *path)
1052
struct stat stat_buf;
1056
if(path == NULL || stat(path, &stat_buf) || !S_ISREG(stat_buf.st_mode))
1057
ret = PhysOpen(path);
1060
ret = ImageOpen(path);
1065
int32 cdrfile_get_track_lba(const CDRFile *p_cdrfile, int32 i_track)
1067
return(p_cdrfile->Tracks[i_track].LBA);
1070
int cdrfile_read_raw_sector(CDRFile *p_cdrfile, uint8 *buf, int32 lba)
1075
memset(buf + 2352, 0, 96);
1077
MakeSubPQ(p_cdrfile, lba, buf + 2352);
1079
cdrfile_deinterleave_subq(buf + 2352, SimuQ);
1082
if(p_cdrfile->p_cdio)
1084
if(SkipSectorRead[lba >> 3] & 1 << (lba & 7))
1086
printf("Read(skipped): %d\n", lba);
1087
memset(buf, 0, 2352);
1089
else if(p_cdrfile->CanMMC)
1091
mmc_cdb_t cdb = {{0, }};
1093
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_CD);
1094
CDIO_MMC_SET_READ_TYPE (cdb.field, CDIO_MMC_READ_TYPE_ANY);
1095
CDIO_MMC_SET_READ_LBA (cdb.field, lba);
1096
CDIO_MMC_SET_READ_LENGTH24(cdb.field, 1);
1098
cdb.field[9] = 0xF8;
1101
cdb.field[10] = p_cdrfile->CanSubRead ? 0x1 : 0x0;
1103
if(mmc_run_cmd (p_cdrfile->p_cdio, MMC_TIMEOUT_DEFAULT,
1106
(p_cdrfile->CanSubRead ? (2352 + 96) : 2352),
1109
printf("MMC read error, sector %d\n", lba);
1110
memset(buf, 0, 2352);
1114
else // else to if(p_cdrfile->CanMMC)
1116
// using the subq data calculated in MakeSubPQ() makes more sense than figuring out which track we're on again.
1117
if(SimuQ[0] & 0x40) // Data sector
1119
int64 end_time = MDFND_GetTime() + MMC_TIMEOUT_DEFAULT;
1120
bool read_success = false;
1124
if(cdio_read_mode1_sectors(p_cdrfile->p_cdio, buf + 12 + 3 + 1, lba, 0, 1) >= 0)
1126
read_success = true;
1129
if(MDFND_ExitBlockingLoop())
1131
} while(MDFND_GetTime() < end_time);
1136
lec_encode_mode1_sector(lba + 150, buf);
1138
else // Audio sector
1140
if(cdio_read_audio_sector(p_cdrfile->p_cdio, buf, lba) < 0)
1142
printf("Audio read error, sector %d\n", lba);
1143
memset(buf, 0, 2352);
1152
bool TrackFound = FALSE;
1154
for(int32 track = p_cdrfile->FirstTrack; track < (p_cdrfile->FirstTrack + p_cdrfile->NumTracks); track++)
1156
CDRFILE_TRACK_INFO *ct = &p_cdrfile->Tracks[track];
1158
if(lba >= (ct->LBA - ct->pregap_dv - ct->pregap) && lba < (ct->LBA + ct->sectors + ct->postgap))
1162
// Handle pregap and postgap reading
1163
if(lba < (ct->LBA - ct->pregap_dv) || lba >= (ct->LBA + ct->sectors))
1165
//printf("Pre/post-gap read, LBA=%d(LBA-track_start_LBA=%d)\n", lba, lba - ct->LBA);
1166
memset(buf, 0, 2352); // Null sector data, per spec
1172
int frames_read = ct->AReader->Read((ct->FileOffset / 4) + (lba - ct->LBA) * 588, ct->AudioBuf, 588);
1174
ct->LastSamplePos += frames_read;
1176
if(frames_read < 0 || frames_read > 588) // This shouldn't happen.
1178
printf("Error: frames_read out of range: %d\n", frames_read);
1182
if(frames_read < 588)
1183
memset((uint8 *)ct->AudioBuf + frames_read * 2 * sizeof(int16), 0, (588 - frames_read) * 2 * sizeof(int16));
1185
for(int i = 0; i < 588 * 2; i++)
1186
MDFN_en16lsb(buf + i * 2, ct->AudioBuf[i]);
1188
else // Binary, woo.
1190
long SeekPos = ct->FileOffset;
1191
long LBARelPos = lba - ct->LBA;
1193
SeekPos += LBARelPos * DI_Size_Table[ct->DIFormat];
1195
if(ct->SubchannelMode)
1196
SeekPos += 96 * (lba - ct->LBA);
1198
fseek(ct->fp, SeekPos, SEEK_SET);
1200
switch(ct->DIFormat)
1202
case DI_FORMAT_AUDIO:
1203
fread(buf, 1, 2352, ct->fp);
1205
if(ct->RawAudioMSBFirst)
1206
Endian_A16_Swap(buf, 588 * 2);
1209
case DI_FORMAT_MODE1:
1210
fread(buf + 12 + 3 + 1, 1, 2048, ct->fp);
1211
lec_encode_mode1_sector(lba + 150, buf);
1214
case DI_FORMAT_MODE1_RAW:
1215
case DI_FORMAT_MODE2_RAW:
1216
fread(buf, 1, 2352, ct->fp);
1219
case DI_FORMAT_MODE2:
1220
fread(buf + 16, 1, 2336, ct->fp);
1221
lec_encode_mode2_sector(lba + 150, buf);
1225
// FIXME: M2F1, M2F2, does sub-header come before or after user data(standards say before, but I wonder
1226
// about cdrdao...).
1227
case DI_FORMAT_MODE2_FORM1:
1228
fread(buf + 24, 1, 2048, ct->fp);
1229
//lec_encode_mode2_form1_sector(lba + 150, buf);
1232
case DI_FORMAT_MODE2_FORM2:
1233
fread(buf + 24, 1, 2324, ct->fp);
1234
//lec_encode_mode2_form2_sector(lba + 150, buf);
1239
if(ct->SubchannelMode)
1240
fread(buf + 2352, 1, 96, ct->fp);
1242
} // end if audible part of audio track read.
1244
} // End if LBA is in range
1245
} // end track search loop
1250
memset(buf, 0, 2352);
1258
uint8 dummy_buf[2352 + 96];
1259
bool any_mismatch = FALSE;
1261
memcpy(dummy_buf + 16, buf + 16, 2048);
1262
memset(dummy_buf + 2352, 0, 96);
1264
MakeSubPQ(p_cdrfile, lba, dummy_buf + 2352);
1265
lec_encode_mode1_sector(lba + 150, dummy_buf);
1267
for(int i = 0; i < 2352 + 96; i++)
1269
if(dummy_buf[i] != buf[i])
1271
printf("Mismatch at %d, %d: %02x:%02x; ", lba, i, dummy_buf[i], buf[i]);
1272
any_mismatch = TRUE;
1280
cdrfile_deinterleave_subq(buf + 2352, qbuf);
1282
//printf("%02x\n", qbuf[0]);
1283
//printf("%02x\n", buf[12 + 3]);
1288
int32 cdrfile_get_num_tracks (const CDRFile *p_cdrfile)
1290
return(p_cdrfile->NumTracks);
1293
CD_Track_Format_t cdrfile_get_track_format(const CDRFile *p_cdrfile, int32 i_track)
1295
return(p_cdrfile->Tracks[i_track].Format);
1298
int32 cdrfile_get_first_track_num(const CDRFile *p_cdrfile)
1300
return(p_cdrfile->FirstTrack);
1303
static void MakeSubPQ(const CDRFile *p_cdrfile, uint32 lba, uint8 *SubPWBuf)
1307
uint32 lba_relative;
1310
uint8 pause_or = 0x00;
1311
bool track_found = FALSE;
1313
for(track = p_cdrfile->FirstTrack; track < (p_cdrfile->FirstTrack + p_cdrfile->NumTracks); track++)
1315
if(lba >= (p_cdrfile->Tracks[track].LBA - p_cdrfile->Tracks[track].pregap_dv - p_cdrfile->Tracks[track].pregap) && lba < (p_cdrfile->Tracks[track].LBA + p_cdrfile->Tracks[track].sectors + p_cdrfile->Tracks[track].postgap))
1322
//printf("%d %d\n", p_cdrfile->Tracks[1].LBA, p_cdrfile->Tracks[1].sectors);
1326
printf("MakeSubPQ error for sector %u!", lba);
1327
track = p_cdrfile->FirstTrack;
1330
lba_relative = abs((int32)lba - p_cdrfile->Tracks[track].LBA);
1332
f = (lba_relative % 75);
1333
s = ((lba_relative / 75) % 60);
1334
m = (lba_relative / 75 / 60);
1336
fa = (lba + 150) % 75;
1337
sa = ((lba + 150) / 75) % 60;
1338
ma = ((lba + 150) / 75 / 60);
1340
uint8 adr = 0x1; // Q channel data encodes position
1341
uint8 control = (p_cdrfile->Tracks[track].Format == CD_TRACK_FORMAT_AUDIO) ? 0x00 : 0x04;
1343
// Handle pause(D7 of interleaved subchannel byte) bit, should be set to 1 when in pregap or postgap.
1344
if((lba < p_cdrfile->Tracks[track].LBA) || (lba >= p_cdrfile->Tracks[track].LBA + p_cdrfile->Tracks[track].sectors))
1346
//printf("pause_or = 0x80 --- %d\n", lba);
1350
// Handle pregap between audio->data track
1352
int32 pg_offset = (int32)lba - p_cdrfile->Tracks[track].LBA;
1354
// If we're more than 2 seconds(150 sectors) from the real "start" of the track/INDEX 01, and the track is a data track,
1355
// and the preceding track is an audio track, encode it as audio.
1356
if(pg_offset < -150)
1358
if(p_cdrfile->Tracks[track].Format == CD_TRACK_FORMAT_DATA && (p_cdrfile->FirstTrack < track) &&
1359
p_cdrfile->Tracks[track - 1].Format == CD_TRACK_FORMAT_AUDIO)
1361
//printf("Pregap part 1 audio->data: lba=%d track_lba=%d\n", lba, p_cdrfile->Tracks[track].LBA);
1368
memset(buf, 0, 0xC);
1369
buf[0] = (adr << 0) | (control << 4);
1370
buf[1] = INT_TO_BCD(track);
1372
if(lba < p_cdrfile->Tracks[track].LBA) // Index is 00 in pregap
1373
buf[2] = INT_TO_BCD(0x00);
1375
buf[2] = INT_TO_BCD(0x01);
1377
// Track relative MSF address
1378
buf[3] = INT_TO_BCD(m);
1379
buf[4] = INT_TO_BCD(s);
1380
buf[5] = INT_TO_BCD(f);
1382
buf[6] = 0; // Zerroooo
1384
// Absolute MSF address
1385
buf[7] = INT_TO_BCD(ma);
1386
buf[8] = INT_TO_BCD(sa);
1387
buf[9] = INT_TO_BCD(fa);
1391
for(int i = 0; i < 0xA; i++)
1392
crc = subq_crctab[(crc >> 8) ^ buf[i]] ^ (crc << 8);
1395
buf[0xa] = ~(crc >> 8);
1398
for(int i = 0; i < 96; i++)
1399
SubPWBuf[i] |= (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | pause_or;
1402
bool cdrfile_read_toc(const CDRFile *p_cdrfile, CD_TOC *toc)
1404
toc->first_track = p_cdrfile->FirstTrack;
1405
toc->last_track = p_cdrfile->FirstTrack + p_cdrfile->NumTracks - 1;
1406
toc->disc_type = DISC_TYPE_CDDA_OR_M1; // FIXME
1408
for(int i = toc->first_track; i <= toc->last_track; i++)
1410
toc->tracks[i].lba = p_cdrfile->Tracks[i].LBA;
1411
toc->tracks[i].adr = ADR_CURPOS;
1412
toc->tracks[i].control = 0x0;
1414
if(p_cdrfile->Tracks[i].Format != CD_TRACK_FORMAT_AUDIO)
1415
toc->tracks[i].control |= 0x4;
1419
toc->tracks[100].lba = p_cdrfile->total_sectors;
1420
toc->tracks[100].adr = ADR_CURPOS;
1421
toc->tracks[100].control = 0x00; // Audio...
1423
// Convenience leadout track duplication.
1424
if(toc->last_track < 99)
1425
toc->tracks[toc->last_track + 1] = toc->tracks[100];
1430
bool cdrfile_is_physical(const CDRFile *p_cdrfile)
1433
if(p_cdrfile->p_cdio)