~ubuntu-branches/debian/experimental/mednafen/experimental

« back to all changes in this revision

Viewing changes to src/cdrom/cdromfile.cpp

  • Committer: Package Import Robot
  • Author(s): Stephen Kitt
  • Date: 2012-01-31 07:21:35 UTC
  • mfrom: (1.2.8)
  • Revision ID: package-import@ubuntu.com-20120131072135-es3dj12y00xcnrsk
Tags: 0.9.19-1
* New upstream WIP version.
* Update copyright information.
* Refresh use-system-tremor.patch and remove psx-big-endian-only.patch.
* Add spelling-fixes.patch based on Lintian's recommendations.
* Build-depend on debhelper 9 or later and remove corresponding Lintian
  override.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Mednafen - Multi-system Emulator
2
 
 *
3
 
 *  Subchannel Q CRC Code:  Copyright (C) 1998  Andreas Mueller <mueller@daneb.ping.de>
4
 
 *
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.
9
 
 *
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.
14
 
 *
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
18
 
 */
19
 
 
20
 
/*
21
 
 Notes and TODO:
22
 
 
23
 
        POSTGAP in CUE sheets may not be handled properly, should the directive automatically increment the index number?
24
 
 
25
 
        INDEX nn where 02 <= nn <= 99 is not supported in CUE sheets.
26
 
 
27
 
        TOC reading code is extremely barebones, leaving out support for more esoteric features.
28
 
 
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.
31
 
 
32
 
        Trying to read sectors at an LBA of less than 0 is not supported.  TODO: support it(at least up to -150).
33
 
*/
34
 
 
35
 
#define _CDROMFILE_INTERNAL
36
 
#include "../mednafen.h"
37
 
 
38
 
#include <sys/types.h>
39
 
#include <sys/stat.h>
40
 
 
41
 
#ifdef HAVE_LIBCDIO
42
 
#include <cdio/cdio.h>
43
 
#include <cdio/mmc.h>
44
 
#endif
45
 
 
46
 
#include <string.h>
47
 
#include <errno.h>
48
 
#include <time.h>
49
 
#include <trio/trio.h>
50
 
 
51
 
#include "../general.h"
52
 
#include "../endian.h"
53
 
 
54
 
#include "cdromif.h"
55
 
#include "cdromfile.h"
56
 
#include "dvdisaster.h"
57
 
#include "lec.h"
58
 
 
59
 
#include "audioreader.h"
60
 
 
61
 
#include <map>
62
 
 
63
 
struct CDRFILE_TRACK_INFO
64
 
{
65
 
        int32 LBA;
66
 
        
67
 
        CD_Track_Format_t Format;
68
 
        uint32 DIFormat;
69
 
 
70
 
        //track_format_t Format;        
71
 
        //bool IsData2352;
72
 
 
73
 
        int32 pregap;
74
 
        int32 pregap_dv;
75
 
 
76
 
        int32 postgap;
77
 
 
78
 
        int32 index[2];
79
 
 
80
 
        int32 sectors;  // Not including pregap sectors!
81
 
        FILE *fp;
82
 
        bool FirstFileInstance;
83
 
        bool RawAudioMSBFirst;
84
 
        long FileOffset;
85
 
        unsigned int SubchannelMode;
86
 
 
87
 
        uint32 LastSamplePos;
88
 
 
89
 
        AudioReader *AReader;
90
 
        int16 AudioBuf[588 * 2];
91
 
};
92
 
#if 0
93
 
struct Medium_Chunk
94
 
{
95
 
        int64 Offset;           // Offset in [..TODO..]
96
 
        uint32 DIFormat;
97
 
 
98
 
        FILE *fp;
99
 
        bool FirstFileInstance;
100
 
        bool RawAudioMSBFirst;
101
 
        unsigned int SubchannelMode;
102
 
 
103
 
        uint32 LastSamplePos;
104
 
        AudioReader *AReader;
105
 
};
106
 
 
107
 
struct CD_Chunk
108
 
{
109
 
        int32 LBA;
110
 
        int32 Track;
111
 
        int32 Index;
112
 
        bool DataType;
113
 
 
114
 
        Medium_Chunk Medium;
115
 
};
116
 
 
117
 
static std::vector<CD_Chunk> Chunks;
118
 
#endif
119
 
 
120
 
struct CDRFile
121
 
{
122
 
        int32 NumTracks;
123
 
        int32 FirstTrack;
124
 
        int32 total_sectors;
125
 
        CDRFILE_TRACK_INFO Tracks[100]; // Track #0(HMM?) through 99
126
 
 
127
 
        #ifdef HAVE_LIBCDIO
128
 
        CdIo *p_cdio;
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.
132
 
        #endif
133
 
};
134
 
 
135
 
 
136
 
// 1-bit per sector on the physical CD.  If set, don't read that sector.
137
 
static uint8 SkipSectorRead[65536];
138
 
 
139
 
// lookup table for crc calculation
140
 
static uint16 subq_crctab[256] = 
141
 
{
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
171
 
};
172
 
 
173
 
bool cdrfile_check_subq_checksum(uint8 *SubQBuf)
174
 
{
175
 
 uint16 crc = 0;
176
 
 uint16 stored_crc = 0;
177
 
 
178
 
 stored_crc = SubQBuf[0xA] << 8;
179
 
 stored_crc |= SubQBuf[0xB];
180
 
 
181
 
 for(int i = 0; i < 0xA; i++)
182
 
  crc = subq_crctab[(crc >> 8) ^ SubQBuf[i]] ^ (crc << 8);
183
 
 
184
 
 crc = ~crc;
185
 
 
186
 
 return(crc == stored_crc);
187
 
}
188
 
 
189
 
 
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);
192
 
 
193
 
 
194
 
void cdrfile_deinterleave_subq(const uint8 *SubPWBuf, uint8 *qbuf)
195
 
{
196
 
 memset(qbuf, 0, 0xC);
197
 
 
198
 
 for(int i = 0; i < 96; i++)
199
 
 {
200
 
  qbuf[i >> 3] |= ((SubPWBuf[i] >> 6) & 0x1) << (7 - (i & 0x7));
201
 
 }
202
 
}
203
 
 
204
 
static char *UnQuotify(char *src, char *dest)
205
 
{
206
 
 bool in_quote = 0;
207
 
 bool already_normal = 0;
208
 
 
209
 
 while(*src)
210
 
 {
211
 
  if(*src == ' ' || *src == '\t')
212
 
  {
213
 
   if(!in_quote)
214
 
   {
215
 
    if(already_normal)
216
 
     break;
217
 
    else
218
 
    {
219
 
     src++;
220
 
     continue;
221
 
    }
222
 
   }
223
 
  }
224
 
 
225
 
  if(*src == '"')
226
 
  {
227
 
   if(in_quote)
228
 
   {
229
 
    src++;
230
 
    break;
231
 
   }
232
 
   else
233
 
    in_quote = 1;
234
 
  }
235
 
  else
236
 
  {
237
 
   *dest = *src;
238
 
   already_normal = 1;
239
 
   dest++;
240
 
  }
241
 
  src++;
242
 
 }
243
 
 
244
 
 *dest = 0;
245
 
 return(src);
246
 
}
247
 
 
248
 
static uint32 GetSectorCount(CDRFILE_TRACK_INFO *track)
249
 
{
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)
253
 
 {
254
 
  if(track->AReader)
255
 
   return(((track->AReader->FrameCount() * 4) - track->FileOffset) / 2352);
256
 
  else
257
 
  {
258
 
   struct stat stat_buf;
259
 
   fstat(fileno(track->fp), &stat_buf);
260
 
 
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));
264
 
   else
265
 
    return((stat_buf.st_size - track->FileOffset) / 2352);
266
 
  }
267
 
 }
268
 
 else
269
 
 {
270
 
  struct stat stat_buf;
271
 
 
272
 
  if(fstat(fileno(track->fp), &stat_buf))
273
 
  {
274
 
   ErrnoHolder ene(errno);
275
 
 
276
 
   printf("Error: %s\n", ene.StrError());
277
 
   exit(1);
278
 
  }
279
 
 
280
 
  return((stat_buf.st_size - track->FileOffset) / DI_Size_Table[track->DIFormat]);
281
 
 }
282
 
 
283
 
 return(0);
284
 
}
285
 
 
286
 
void cdrfile_destroy(CDRFile *p_cdrfile)
287
 
{
288
 
 #ifdef HAVE_LIBCDIO
289
 
 if(p_cdrfile->p_cdio)
290
 
  cdio_destroy(p_cdrfile->p_cdio);
291
 
 else
292
 
 #endif
293
 
 {
294
 
  int32 track;
295
 
  for(track = p_cdrfile->FirstTrack; track < (p_cdrfile->FirstTrack + p_cdrfile->NumTracks); track++)
296
 
  {
297
 
   CDRFILE_TRACK_INFO *this_track = &p_cdrfile->Tracks[track];
298
 
 
299
 
   if(this_track->FirstFileInstance)
300
 
   {
301
 
    if(p_cdrfile->Tracks[track].AReader)
302
 
    {
303
 
     delete p_cdrfile->Tracks[track].AReader;
304
 
     p_cdrfile->Tracks[track].AReader = NULL;
305
 
    }
306
 
    else if(this_track->fp)
307
 
     fclose(this_track->fp);
308
 
   }
309
 
  }
310
 
 }
311
 
 free(p_cdrfile);
312
 
}
313
 
 
314
 
static bool ParseTOCFileLineInfo(CDRFILE_TRACK_INFO *track, const int tracknum, const char *filename, const char *binoffset, const char *msfoffset, const char *length)
315
 
{
316
 
 long offset = 0; // In bytes!
317
 
 long tmp_long;
318
 
 int m, s, f;
319
 
 uint32 sector_mult;
320
 
 long sectors;
321
 
 
322
 
 if(!MDFN_IsFIROPSafe(filename))
323
 
 {
324
 
  MDFN_printf(_("Referenced path \"%s\" is potentially unsafe.  See \"filesys.untrusted_fip_check\" setting.\n"), filename);
325
 
  return(0);
326
 
 }
327
 
 
328
 
 std::string efn = MDFN_MakeFName(MDFNMKF_AUX, 0, filename);
329
 
 
330
 
 if(NULL == (track->fp = fopen(efn.c_str(), "rb")))
331
 
 {
332
 
  ErrnoHolder ene(errno);
333
 
 
334
 
  MDFN_printf(_("Could not open referenced file \"%s\": %s\n"), efn.c_str(), ene.StrError());
335
 
  return(0);
336
 
 }
337
 
 
338
 
 if(strlen(filename) >= 4 && !strcasecmp(filename + strlen(filename) - 4, ".wav"))
339
 
 {
340
 
  track->AReader = AR_Open(track->fp);
341
 
 
342
 
  if(!track->AReader)
343
 
   return(false);
344
 
 }
345
 
 
346
 
 sector_mult = DI_Size_Table[track->DIFormat];
347
 
 
348
 
 if(track->SubchannelMode)
349
 
  sector_mult += 96;
350
 
 
351
 
 if(binoffset && trio_sscanf(binoffset, "%ld", &tmp_long) == 1)
352
 
 {
353
 
  offset += tmp_long;
354
 
 }
355
 
 
356
 
 if(msfoffset && trio_sscanf(msfoffset, "%d:%d:%d", &m, &s, &f) == 3)
357
 
 {
358
 
  offset += ((m * 60 + s) * 75 + f) * sector_mult;
359
 
 }
360
 
 
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);
364
 
 
365
 
 if(length)
366
 
 {
367
 
  tmp_long = sectors;
368
 
 
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)
372
 
  {
373
 
   char *endptr = NULL;
374
 
 
375
 
   tmp_long = strtol(length, &endptr, 10);
376
 
 
377
 
   // Error?
378
 
   if(endptr == length)
379
 
   {
380
 
    tmp_long = sectors;
381
 
   }
382
 
   else
383
 
    tmp_long /= 588;
384
 
 
385
 
  }
386
 
 
387
 
  if(tmp_long > sectors)
388
 
  {
389
 
   MDFN_printf(_("Length specified in TOC file for track %d is too large by %ld sectors!\n"), tracknum, (long)(tmp_long - sectors));
390
 
   return(FALSE);
391
 
  }
392
 
  sectors = tmp_long;
393
 
 }
394
 
 
395
 
 track->FirstFileInstance = 1;
396
 
 track->sectors = sectors;
397
 
 
398
 
 return(TRUE);
399
 
}
400
 
 
401
 
#ifdef HAVE_LIBCDIO
402
 
static void DetermineFeatures(CDRFile *p_cdrfile)
403
 
{
404
 
 uint8 buf[256];
405
 
 uint8 *page;
406
 
 
407
 
 mmc_cdb_t cdb = {{0, }};
408
 
 
409
 
 CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_MODE_SENSE_10);
410
 
 
411
 
 memset(buf, 0, sizeof(buf));
412
 
 
413
 
 cdb.field[2] = 0x2A;
414
 
 
415
 
 cdb.field[7] = sizeof(buf) >> 8;
416
 
 cdb.field[8] = sizeof(buf) & 0xFF;
417
 
 
418
 
 p_cdrfile->CanMMC = false;
419
 
 p_cdrfile->CanRawRead = false;
420
 
 p_cdrfile->CanSubRead = false;
421
 
 
422
 
 if(mmc_run_cmd (p_cdrfile->p_cdio, MMC_TIMEOUT_DEFAULT,
423
 
                    &cdb,
424
 
                    SCSI_MMC_DATA_READ,
425
 
                    sizeof(buf),
426
 
                    buf))
427
 
 {
428
 
  MDFN_printf(_("MMC [MODE SENSE 10] command failed.\n"));
429
 
 }
430
 
 else
431
 
 {
432
 
  page = &buf[8];
433
 
 
434
 
  if(page[0] != 0x2A || page[1] < 0x14)
435
 
   MDFN_printf(_("MMC [MODE SENSE 10] command returned bogus data for mode page 0x2A?\n"));
436
 
  else
437
 
  {
438
 
   //printf("%02x\n", page[5]);
439
 
   p_cdrfile->CanMMC = true;
440
 
   if(page[5] & 0x04)
441
 
    p_cdrfile->CanSubRead = true;
442
 
  }
443
 
 }
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"));
449
 
}
450
 
#endif
451
 
 
452
 
#ifdef HAVE_LIBCDIO
453
 
static CDRFile *PhysOpen(const char *path)
454
 
{
455
 
 CDRFile *ret = (CDRFile *)calloc(1, sizeof(CDRFile));
456
 
 
457
 
  CdIo *p_cdio;
458
 
  char **devices;
459
 
  char **parseit;
460
 
  cdio_init();
461
 
 
462
 
  GetFileBase("cdrom");
463
 
 
464
 
  devices = cdio_get_devices(DRIVER_DEVICE);
465
 
  parseit = devices;
466
 
  if(parseit)
467
 
  {
468
 
   MDFN_printf(_("Connected physical devices:\n"));
469
 
   MDFN_indent(1);
470
 
   while(*parseit)
471
 
   {
472
 
    MDFN_printf("%s\n", *parseit);
473
 
    parseit++;
474
 
   }
475
 
   MDFN_indent(-1);
476
 
  }
477
 
  if(!parseit || parseit == devices)
478
 
  {
479
 
   MDFN_PrintError(_("No CDROM drives detected(or no disc present)."));
480
 
   if(devices)
481
 
    cdio_free_device_list(devices);
482
 
   free(ret);
483
 
   return(NULL);
484
 
  }
485
 
 
486
 
  if(devices)
487
 
   cdio_free_device_list(devices);
488
 
 
489
 
  p_cdio = cdio_open_cd(path); //, DRIVER_UNKNOWN); //NULL, DRIVER_UNKNOWN);
490
 
 
491
 
  if(!p_cdio) 
492
 
  {
493
 
   free(ret);
494
 
   return(NULL);
495
 
  }
496
 
  ret->p_cdio = p_cdio;
497
 
 
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);
501
 
 
502
 
  if(ret->FirstTrack > 99)
503
 
  {
504
 
   MDFN_PrintError(_("Invalid first track: %d\n"), ret->FirstTrack);
505
 
   free(ret);
506
 
   cdio_destroy(p_cdio);
507
 
   return(NULL);
508
 
  }
509
 
 
510
 
  if(ret->NumTracks > 100)
511
 
  {
512
 
   MDFN_PrintError(_("Invalid track count: %d\n"), ret->NumTracks);
513
 
   free(ret);
514
 
   cdio_destroy(p_cdio);
515
 
   return(NULL);
516
 
  }
517
 
 
518
 
  for(int32 track = ret->FirstTrack; track < (ret->FirstTrack + ret->NumTracks); track++)
519
 
  {
520
 
   memset(&ret->Tracks[track], 0, sizeof(CDRFILE_TRACK_INFO));
521
 
 
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);
524
 
 
525
 
   switch(cdio_get_track_format(ret->p_cdio, track))
526
 
   {
527
 
    case TRACK_FORMAT_AUDIO:
528
 
        ret->Tracks[track].Format = CD_TRACK_FORMAT_AUDIO;
529
 
        break;
530
 
 
531
 
    default:
532
 
        ret->Tracks[track].Format = CD_TRACK_FORMAT_DATA;
533
 
        break;
534
 
   }
535
 
  }
536
 
 
537
 
 //
538
 
 // Determine how we can read this CD.
539
 
 //
540
 
 DetermineFeatures(ret);
541
 
 
542
 
 #if 1
543
 
 memset(SkipSectorRead, 0, sizeof(SkipSectorRead));
544
 
 #else
545
 
 // Determine/Calculate unreadable portions of the disc.
546
 
 {
547
 
  int32 a_to_d_skip = 0;        // In frames;
548
 
 
549
 
  memset(SkipSectorRead, 0, sizeof(SkipSectorRead));
550
 
 
551
 
  // Find track type transitions.
552
 
  for(int track = ret->FirstTrack + 1; track < (ret->FirstTrack + ret->NumTracks); track++)
553
 
  {
554
 
   bool transition = false;
555
 
 
556
 
   if(ret->Tracks[track - 1].Format != ret->Tracks[track].Format)
557
 
    transition = true;
558
 
 
559
 
   if(transition)
560
 
   {
561
 
    int32 lba = ret->Tracks[track].LBA;
562
 
    uint8 dummy_buf[2352 + 96];
563
 
    static const int test_offsets[] = { -75 * 4, -75 * 3   };
564
 
 
565
 
    for(int frame = -75 * 4; frame < 0; frame += 75)
566
 
    {
567
 
     for(int subframe = -1; subframe <= 1; subframe++)
568
 
     {
569
 
      int32 eff_offset = frame + subframe;
570
 
      int32 eff_lba = lba + eff_offset;
571
 
      if(eff_lba >= 0)
572
 
      {
573
 
       if(!cdrfile_read_raw_sector(ret, dummy_buf, eff_lba))
574
 
       {
575
 
        printf("Failure: %d\n", eff_lba);
576
 
        for(int32 il = eff_lba; il < ret->Tracks[track].LBA; il++)
577
 
        {
578
 
         printf(" Skipping: %d\n", il);
579
 
         SkipSectorRead[il >> 3] |= 1 << (il & 7);
580
 
        }
581
 
        goto EndFrameTest;
582
 
       }
583
 
       else
584
 
        printf("Success: %d\n", eff_lba);
585
 
      }
586
 
     }
587
 
    }
588
 
    EndFrameTest: ;
589
 
   }
590
 
  }
591
 
 
592
 
  //if(a_to_d_skip)
593
 
  //{
594
 
  //}
595
 
 }
596
 
 #endif
597
 
 
598
 
 return(ret);
599
 
}
600
 
#endif
601
 
 
602
 
 
603
 
static CDRFile *ImageOpen(const char *path)
604
 
{
605
 
 CDRFile *ret = (CDRFile *)calloc(1, sizeof(CDRFile));
606
 
 FILE *fp = NULL;
607
 
 bool IsTOC = FALSE;
608
 
 
609
 
  // Assign opposite maximum values so our tests will work!
610
 
  int FirstTrack = 99;
611
 
  int LastTrack = 0;
612
 
 
613
 
  if(!(fp = fopen(path, "rb")))
614
 
  {
615
 
   ErrnoHolder ene(errno);
616
 
 
617
 
   MDFN_PrintError(_("Error opening CUE sheet/TOC \"%s\": %s\n"), path, ene.StrError());
618
 
   free(ret);
619
 
   return(NULL);
620
 
  }
621
 
  GetFileBase(path);
622
 
 
623
 
  char linebuf[512];
624
 
  int32 active_track = -1;
625
 
  int32 AutoTrackInc = 1; // For TOC
626
 
  CDRFILE_TRACK_INFO TmpTrack;
627
 
  memset(&TmpTrack, 0, sizeof(TmpTrack));
628
 
 
629
 
  while(fgets(linebuf, 512, fp) > 0)
630
 
  {
631
 
   char cmdbuf[512], raw_args[512], args[4][512];
632
 
   int argcount = 0;
633
 
 
634
 
   raw_args[0] = 0;
635
 
   cmdbuf[0] = 0;
636
 
 
637
 
   args[0][0] = args[1][0] = args[2][0] = args[3][0] = 0;
638
 
 
639
 
   if(!strncasecmp(linebuf, "CD_ROM", 6) || !strncasecmp(linebuf, "CD_DA", 5) || !strncasecmp(linebuf, "CD_ROM_XA", 9))
640
 
   {
641
 
    IsTOC = TRUE;
642
 
    puts("TOC file detected.");
643
 
   }
644
 
 
645
 
   if(IsTOC)
646
 
   {
647
 
    char *ss_loc = strstr(linebuf, "//");
648
 
    if(ss_loc)
649
 
    {
650
 
     ss_loc[0] = '\n'; // For consistency!
651
 
     ss_loc[1] = 0;
652
 
    }
653
 
   }
654
 
 
655
 
   trio_sscanf(linebuf, "%s %[^\r\n]", cmdbuf, raw_args);
656
 
   
657
 
   if(!strcasecmp(cmdbuf, "CD_ROM") || !strcasecmp(cmdbuf, "CD_DA"))
658
 
    IsTOC = TRUE;
659
 
 
660
 
   UnQuotify(UnQuotify(UnQuotify(UnQuotify(raw_args, args[0]), args[1]), args[2]), args[3]);
661
 
   if(args[0][0])
662
 
   {
663
 
    argcount++;
664
 
    if(args[1][0])
665
 
    {
666
 
     argcount++;
667
 
     if(args[2][0])
668
 
     {
669
 
      argcount++;
670
 
      if(args[3][0])
671
 
      {
672
 
       argcount++;
673
 
      }
674
 
     }
675
 
    } 
676
 
   }
677
 
 
678
 
   if(IsTOC)
679
 
   {
680
 
    if(!strcasecmp(cmdbuf, "TRACK"))
681
 
    {
682
 
     if(active_track >= 0)
683
 
     {
684
 
      memcpy(&ret->Tracks[active_track], &TmpTrack, sizeof(TmpTrack));
685
 
      memset(&TmpTrack, 0, sizeof(TmpTrack));
686
 
      active_track = -1;
687
 
     }
688
 
 
689
 
     if(AutoTrackInc > 99)
690
 
     {
691
 
      MDFN_printf(_("Invalid track number: %d\n"), AutoTrackInc);
692
 
      free(ret);
693
 
      return(NULL);
694
 
     }
695
 
 
696
 
     active_track = AutoTrackInc++;
697
 
     if(active_track < FirstTrack)
698
 
      FirstTrack = active_track;
699
 
     if(active_track > LastTrack)
700
 
      LastTrack = active_track;
701
 
 
702
 
     int format_lookup;
703
 
     for(format_lookup = 0; format_lookup < _DI_FORMAT_COUNT; format_lookup++)
704
 
     {
705
 
      if(!strcasecmp(args[0], DI_CDRDAO_Strings[format_lookup]))
706
 
      {
707
 
       TmpTrack.DIFormat = format_lookup;
708
 
       break;
709
 
      }
710
 
     }
711
 
 
712
 
     if(format_lookup == _DI_FORMAT_COUNT)
713
 
     {
714
 
      MDFN_printf(_("Invalid track format: %s\n"), args[0]);
715
 
      free(ret);
716
 
      return(0);
717
 
     }
718
 
 
719
 
     if(TmpTrack.DIFormat == DI_FORMAT_AUDIO)
720
 
      TmpTrack.RawAudioMSBFirst = TRUE; // Silly cdrdao...
721
 
 
722
 
     if(!strcasecmp(args[1], "RW"))
723
 
     {
724
 
      TmpTrack.SubchannelMode = CDRF_SUBM_RW;
725
 
      MDFN_printf(_("\"RW\" format subchannel data not supported, only \"RW_RAW\" is!\n"));
726
 
      free(ret);
727
 
      return(0);
728
 
     }
729
 
     else if(!strcasecmp(args[1], "RW_RAW"))
730
 
      TmpTrack.SubchannelMode = CDRF_SUBM_RW_RAW;
731
 
 
732
 
    } // end to TRACK
733
 
    else if(!strcasecmp(cmdbuf, "SILENCE"))
734
 
    {
735
 
 
736
 
    }
737
 
    else if(!strcasecmp(cmdbuf, "ZERO"))
738
 
    {
739
 
 
740
 
    }
741
 
    else if(!strcasecmp(cmdbuf, "FILE") || !strcasecmp(cmdbuf, "AUDIOFILE"))
742
 
    {
743
 
     const char *binoffset = NULL;
744
 
     const char *msfoffset = NULL;
745
 
     const char *length = NULL;
746
 
 
747
 
     if(args[1][0] == '#')
748
 
     {
749
 
      binoffset = args[1] + 1;
750
 
      msfoffset = args[2];
751
 
      length = args[3];
752
 
     }
753
 
     else
754
 
     {
755
 
      msfoffset = args[1];
756
 
      length = args[2];
757
 
     }
758
 
     //printf("%s, %s, %s, %s\n", args[0], binoffset, msfoffset, length);
759
 
     if(!ParseTOCFileLineInfo(&TmpTrack, active_track, args[0], binoffset, msfoffset, length))
760
 
     {
761
 
      free(ret);
762
 
      return(0);
763
 
     }
764
 
    }
765
 
    else if(!strcasecmp(cmdbuf, "DATAFILE"))
766
 
    {
767
 
     const char *binoffset = NULL;
768
 
     const char *length = NULL;
769
 
  
770
 
     if(args[1][0] == '#') 
771
 
     {
772
 
      binoffset = args[1] + 1;
773
 
      length = args[2];
774
 
     }
775
 
     else
776
 
      length = args[1];
777
 
 
778
 
     if(!ParseTOCFileLineInfo(&TmpTrack, active_track, args[0], binoffset, NULL, length))
779
 
     {
780
 
      free(ret);
781
 
      return(0);
782
 
     }
783
 
    }
784
 
    else if(!strcasecmp(cmdbuf, "INDEX"))
785
 
    {
786
 
 
787
 
    }
788
 
    else if(!strcasecmp(cmdbuf, "PREGAP"))
789
 
    {
790
 
     if(active_track < 0)
791
 
     {
792
 
      MDFN_printf(_("Command %s is outside of a TRACK definition!\n"), cmdbuf);
793
 
      free(ret);
794
 
      return(NULL);
795
 
     }
796
 
     int m,s,f;
797
 
     trio_sscanf(args[0], "%d:%d:%d", &m, &s, &f);
798
 
     TmpTrack.pregap = (m * 60 + s) * 75 + f;
799
 
    } // end to PREGAP
800
 
    else if(!strcasecmp(cmdbuf, "START"))
801
 
    {
802
 
     if(active_track < 0)
803
 
     {
804
 
      MDFN_printf(_("Command %s is outside of a TRACK definition!\n"), cmdbuf);
805
 
      free(ret);
806
 
      return(NULL);
807
 
     }
808
 
     int m,s,f;
809
 
     trio_sscanf(args[0], "%d:%d:%d", &m, &s, &f);
810
 
     TmpTrack.pregap = (m * 60 + s) * 75 + f;
811
 
    }
812
 
   } /*********** END TOC HANDLING ************/
813
 
   else // now for CUE sheet handling
814
 
   {
815
 
    if(!strcasecmp(cmdbuf, "FILE"))
816
 
    {
817
 
     if(active_track >= 0)
818
 
     {
819
 
      memcpy(&ret->Tracks[active_track], &TmpTrack, sizeof(TmpTrack));
820
 
      memset(&TmpTrack, 0, sizeof(TmpTrack));
821
 
      active_track = -1;
822
 
     }
823
 
 
824
 
     if(!MDFN_IsFIROPSafe(args[0]))
825
 
     {
826
 
      MDFN_printf(_("Referenced path \"%s\" is potentially unsafe.  See \"filesys.untrusted_fip_check\" setting.\n"), args[0]);
827
 
      return(0);
828
 
     }
829
 
 
830
 
     std::string efn = MDFN_MakeFName(MDFNMKF_AUX, 0, args[0]);
831
 
 
832
 
     if(NULL == (TmpTrack.fp = fopen(efn.c_str(), "rb")))
833
 
     {
834
 
      ErrnoHolder ene(errno);
835
 
 
836
 
      MDFN_printf(_("Could not open referenced file \"%s\": %s\n"), efn.c_str(), ene.StrError());
837
 
      free(ret);
838
 
      return(0);
839
 
     }
840
 
     TmpTrack.FirstFileInstance = 1;
841
 
     if(!strcasecmp(args[1], "BINARY"))
842
 
     {
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;
847
 
     }
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+"))
850
 
     {
851
 
      TmpTrack.AReader = AR_Open(TmpTrack.fp);
852
 
      if(!TmpTrack.AReader)
853
 
      {
854
 
       MDFN_printf(_("Unsupported audio track file format: %s\n"), args[0]);
855
 
       free(ret);
856
 
       return(0);
857
 
      }     
858
 
     }
859
 
     else
860
 
     {
861
 
      MDFN_printf(_("Unsupported track format: %s\n"), args[1]);
862
 
      free(ret);
863
 
      return(0);
864
 
     }
865
 
    }
866
 
    else if(!strcasecmp(cmdbuf, "TRACK"))
867
 
    {
868
 
     if(active_track >= 0)
869
 
     {
870
 
      memcpy(&ret->Tracks[active_track], &TmpTrack, sizeof(TmpTrack));
871
 
      TmpTrack.FirstFileInstance = 0;
872
 
      TmpTrack.pregap = 0;
873
 
      TmpTrack.pregap_dv = 0;
874
 
      TmpTrack.postgap = 0;
875
 
      TmpTrack.index[0] = -1;
876
 
      TmpTrack.index[1] = 0;
877
 
     }
878
 
     active_track = atoi(args[0]);
879
 
 
880
 
     if(active_track < FirstTrack)
881
 
      FirstTrack = active_track;
882
 
     if(active_track > LastTrack)
883
 
      LastTrack = active_track;
884
 
 
885
 
     int format_lookup;
886
 
     for(format_lookup = 0; format_lookup < _DI_FORMAT_COUNT; format_lookup++)
887
 
     {
888
 
      if(!strcasecmp(args[1], DI_CUE_Strings[format_lookup]))
889
 
      {
890
 
       TmpTrack.DIFormat = format_lookup;
891
 
       break;
892
 
      }
893
 
     }
894
 
 
895
 
     if(format_lookup == _DI_FORMAT_COUNT)
896
 
     {
897
 
      MDFN_printf(_("Invalid track format: %s\n"), args[0]);
898
 
      return(0);
899
 
     }
900
 
 
901
 
 
902
 
     TmpTrack.sectors = GetSectorCount(&TmpTrack);
903
 
     if(active_track < 0 || active_track > 99)
904
 
     {
905
 
      MDFN_printf(_("Invalid track number: %d\n"), active_track);
906
 
      return(0);
907
 
     }
908
 
    }
909
 
    else if(!strcasecmp(cmdbuf, "INDEX"))
910
 
    {
911
 
     if(active_track >= 0)
912
 
     {
913
 
      int m,s,f;
914
 
      trio_sscanf(args[1], "%d:%d:%d", &m, &s, &f);
915
 
 
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;
920
 
     }
921
 
    }
922
 
    else if(!strcasecmp(cmdbuf, "PREGAP"))
923
 
    {
924
 
     if(active_track >= 0)
925
 
     {
926
 
      int m,s,f;
927
 
      trio_sscanf(args[0], "%d:%d:%d", &m, &s, &f);
928
 
      TmpTrack.pregap = (m * 60 + s) * 75 + f;
929
 
     }
930
 
    }
931
 
    else if(!strcasecmp(cmdbuf, "POSTGAP"))
932
 
    {
933
 
     if(active_track >= 0)
934
 
     {
935
 
      int m,s,f;
936
 
      trio_sscanf(args[0], "%d:%d:%d", &m, &s, &f);
937
 
      TmpTrack.postgap = (m * 60 + s) * 75 + f;
938
 
     }
939
 
    }
940
 
    else
941
 
    {
942
 
     MDFN_printf(_("Unknown CUE sheet directive \"%s\".\n"), cmdbuf);
943
 
    }
944
 
   } // end of CUE sheet handling
945
 
  } // end of fgets() loop
946
 
 
947
 
 if(ferror(fp))
948
 
 {
949
 
  ErrnoHolder ene(errno);       // Is errno valid here?
950
 
 
951
 
  if(IsTOC)
952
 
   MDFN_printf(_("Error reading TOC file: %s\n"), ene.StrError());
953
 
  else
954
 
   MDFN_printf(_("Error reading CUE sheet: %s\n"), ene.StrError());
955
 
 
956
 
  return(0);
957
 
 }
958
 
 
959
 
 if(active_track >= 0)
960
 
  memcpy(&ret->Tracks[active_track], &TmpTrack, sizeof(TmpTrack));
961
 
 
962
 
 if(FirstTrack > LastTrack)
963
 
 {
964
 
  MDFN_printf(_("No tracks found!\n"));
965
 
  return(0);
966
 
 }
967
 
 
968
 
 ret->FirstTrack = FirstTrack;
969
 
 ret->NumTracks = 1 + LastTrack - FirstTrack;
970
 
 
971
 
 int32 RunningLBA = 0;
972
 
 int32 LastIndex = 0;
973
 
 long FileOffset = 0;
974
 
 
975
 
 for(int x = ret->FirstTrack; x < (ret->FirstTrack + ret->NumTracks); x++)
976
 
 {
977
 
  if(ret->Tracks[x].DIFormat == DI_FORMAT_AUDIO)
978
 
   ret->Tracks[x].Format = CD_TRACK_FORMAT_AUDIO;
979
 
  else
980
 
   ret->Tracks[x].Format = CD_TRACK_FORMAT_DATA;
981
 
 
982
 
  if(IsTOC)
983
 
  {
984
 
   RunningLBA += ret->Tracks[x].pregap;
985
 
   ret->Tracks[x].LBA = RunningLBA;
986
 
   RunningLBA += ret->Tracks[x].sectors;
987
 
   RunningLBA += ret->Tracks[x].postgap;
988
 
  }
989
 
  else // else handle CUE sheet...
990
 
  {
991
 
   if(ret->Tracks[x].FirstFileInstance) 
992
 
   {
993
 
    LastIndex = 0;
994
 
    FileOffset = 0;
995
 
   }
996
 
 
997
 
   RunningLBA += ret->Tracks[x].pregap;
998
 
 
999
 
   ret->Tracks[x].pregap_dv = 0;
1000
 
 
1001
 
   if(ret->Tracks[x].index[0] != -1)
1002
 
    ret->Tracks[x].pregap_dv = ret->Tracks[x].index[1] - ret->Tracks[x].index[0];
1003
 
 
1004
 
   FileOffset += ret->Tracks[x].pregap_dv * DI_Size_Table[ret->Tracks[x].DIFormat];
1005
 
 
1006
 
   RunningLBA += ret->Tracks[x].pregap_dv;
1007
 
 
1008
 
   ret->Tracks[x].LBA = RunningLBA;
1009
 
 
1010
 
   // Make sure this is set before the call to GetSectorCount() for the last track sector count fix.
1011
 
   ret->Tracks[x].FileOffset = FileOffset;
1012
 
 
1013
 
   if((x + 1) >= (ret->FirstTrack + ret->NumTracks))
1014
 
   {
1015
 
    if(!(ret->Tracks[x].FirstFileInstance))
1016
 
    {
1017
 
     // This will fix the last sector count for CUE+BIN
1018
 
     ret->Tracks[x].sectors = GetSectorCount(&ret->Tracks[x]);
1019
 
    }
1020
 
   }
1021
 
   else if(ret->Tracks[x+1].FirstFileInstance)
1022
 
   {
1023
 
    //RunningLBA += ret->Tracks[x].sectors;
1024
 
   }
1025
 
   else
1026
 
   { 
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];
1030
 
    else
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;
1032
 
   }
1033
 
 
1034
 
   //printf("Poo: %d %d\n", x, ret->Tracks[x].sectors);
1035
 
   RunningLBA += ret->Tracks[x].sectors;
1036
 
   RunningLBA += ret->Tracks[x].postgap;
1037
 
 
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);
1039
 
 
1040
 
   FileOffset += ret->Tracks[x].sectors * DI_Size_Table[ret->Tracks[x].DIFormat];
1041
 
  } // end to cue sheet handling
1042
 
 } // end to track loop
1043
 
 
1044
 
 ret->total_sectors = RunningLBA;
1045
 
 
1046
 
 return(ret);
1047
 
}
1048
 
 
1049
 
 
1050
 
CDRFile *cdrfile_open(const char *path)
1051
 
{
1052
 
 struct stat stat_buf;
1053
 
 CDRFile *ret;
1054
 
 
1055
 
#ifdef HAVE_LIBCDIO
1056
 
 if(path == NULL || stat(path, &stat_buf) || !S_ISREG(stat_buf.st_mode))
1057
 
  ret = PhysOpen(path);
1058
 
 else
1059
 
#endif
1060
 
  ret = ImageOpen(path);
1061
 
 
1062
 
 return(ret);
1063
 
}
1064
 
 
1065
 
int32 cdrfile_get_track_lba(const CDRFile *p_cdrfile, int32 i_track)
1066
 
{
1067
 
 return(p_cdrfile->Tracks[i_track].LBA);
1068
 
}
1069
 
 
1070
 
int cdrfile_read_raw_sector(CDRFile *p_cdrfile, uint8 *buf, int32 lba)
1071
 
{
1072
 
 uint8 SimuQ[0xC];
1073
 
 uint8 qbuf[0xC];
1074
 
 
1075
 
 memset(buf + 2352, 0, 96);
1076
 
 
1077
 
 MakeSubPQ(p_cdrfile, lba, buf + 2352);
1078
 
 
1079
 
 cdrfile_deinterleave_subq(buf + 2352, SimuQ);
1080
 
 
1081
 
#ifdef HAVE_LIBCDIO
1082
 
 if(p_cdrfile->p_cdio)
1083
 
 {
1084
 
  if(SkipSectorRead[lba >> 3] & 1 << (lba & 7))
1085
 
  {
1086
 
   printf("Read(skipped): %d\n", lba);
1087
 
   memset(buf, 0, 2352);
1088
 
  }
1089
 
  else if(p_cdrfile->CanMMC)
1090
 
  {
1091
 
   mmc_cdb_t cdb = {{0, }};
1092
 
 
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);
1097
 
 
1098
 
   cdb.field[9] = 0xF8;
1099
 
 
1100
 
 
1101
 
   cdb.field[10] = p_cdrfile->CanSubRead ? 0x1 : 0x0;
1102
 
 
1103
 
   if(mmc_run_cmd (p_cdrfile->p_cdio, MMC_TIMEOUT_DEFAULT,
1104
 
                      &cdb,
1105
 
                      SCSI_MMC_DATA_READ,
1106
 
                      (p_cdrfile->CanSubRead ? (2352 + 96) : 2352),
1107
 
                      buf))
1108
 
   {
1109
 
    printf("MMC read error, sector %d\n", lba);
1110
 
    memset(buf, 0, 2352);
1111
 
    return(0);
1112
 
   }
1113
 
  }
1114
 
  else // else to if(p_cdrfile->CanMMC)
1115
 
  {
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
1118
 
   {
1119
 
    int64 end_time = MDFND_GetTime() + MMC_TIMEOUT_DEFAULT;
1120
 
    bool read_success = false;
1121
 
 
1122
 
    do
1123
 
    {
1124
 
     if(cdio_read_mode1_sectors(p_cdrfile->p_cdio, buf + 12 + 3 + 1, lba, 0, 1) >= 0)
1125
 
     {
1126
 
      read_success = true;
1127
 
      break;
1128
 
     }
1129
 
     if(MDFND_ExitBlockingLoop())
1130
 
      break;
1131
 
    } while(MDFND_GetTime() < end_time);
1132
 
 
1133
 
    if(!read_success)
1134
 
     return(0);
1135
 
 
1136
 
    lec_encode_mode1_sector(lba + 150, buf);
1137
 
   }
1138
 
   else // Audio sector
1139
 
   {
1140
 
    if(cdio_read_audio_sector(p_cdrfile->p_cdio, buf, lba) < 0)
1141
 
    {
1142
 
     printf("Audio read error, sector %d\n", lba);
1143
 
     memset(buf, 0, 2352);
1144
 
     return(0);
1145
 
    }
1146
 
   }
1147
 
  }
1148
 
 }
1149
 
 else
1150
 
#endif
1151
 
 {
1152
 
  bool TrackFound = FALSE;
1153
 
 
1154
 
  for(int32 track = p_cdrfile->FirstTrack; track < (p_cdrfile->FirstTrack + p_cdrfile->NumTracks); track++)
1155
 
  {
1156
 
   CDRFILE_TRACK_INFO *ct = &p_cdrfile->Tracks[track];
1157
 
 
1158
 
   if(lba >= (ct->LBA - ct->pregap_dv - ct->pregap) && lba < (ct->LBA + ct->sectors + ct->postgap))
1159
 
   {
1160
 
    TrackFound = TRUE;
1161
 
 
1162
 
    // Handle pregap and postgap reading
1163
 
    if(lba < (ct->LBA - ct->pregap_dv) || lba >= (ct->LBA + ct->sectors))
1164
 
    {
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
1167
 
    }
1168
 
    else
1169
 
    {
1170
 
     if(ct->AReader)
1171
 
     {
1172
 
      int frames_read = ct->AReader->Read((ct->FileOffset / 4) + (lba - ct->LBA) * 588, ct->AudioBuf, 588);
1173
 
 
1174
 
      ct->LastSamplePos += frames_read;
1175
 
 
1176
 
      if(frames_read < 0 || frames_read > 588)  // This shouldn't happen.
1177
 
      {
1178
 
       printf("Error: frames_read out of range: %d\n", frames_read);
1179
 
       frames_read = 0;
1180
 
      }
1181
 
 
1182
 
      if(frames_read < 588)
1183
 
       memset((uint8 *)ct->AudioBuf + frames_read * 2 * sizeof(int16), 0, (588 - frames_read) * 2 * sizeof(int16));
1184
 
 
1185
 
      for(int i = 0; i < 588 * 2; i++)
1186
 
       MDFN_en16lsb(buf + i * 2, ct->AudioBuf[i]);
1187
 
     }
1188
 
     else       // Binary, woo.
1189
 
     {
1190
 
      long SeekPos = ct->FileOffset;
1191
 
      long LBARelPos = lba - ct->LBA;
1192
 
 
1193
 
      SeekPos += LBARelPos * DI_Size_Table[ct->DIFormat];
1194
 
 
1195
 
      if(ct->SubchannelMode)
1196
 
       SeekPos += 96 * (lba - ct->LBA);
1197
 
 
1198
 
      fseek(ct->fp, SeekPos, SEEK_SET);
1199
 
 
1200
 
      switch(ct->DIFormat)
1201
 
      {
1202
 
        case DI_FORMAT_AUDIO:
1203
 
                fread(buf, 1, 2352, ct->fp);
1204
 
 
1205
 
                if(ct->RawAudioMSBFirst)
1206
 
                 Endian_A16_Swap(buf, 588 * 2);
1207
 
                break;
1208
 
 
1209
 
        case DI_FORMAT_MODE1:
1210
 
                fread(buf + 12 + 3 + 1, 1, 2048, ct->fp);
1211
 
                lec_encode_mode1_sector(lba + 150, buf);
1212
 
                break;
1213
 
 
1214
 
        case DI_FORMAT_MODE1_RAW:
1215
 
        case DI_FORMAT_MODE2_RAW:
1216
 
                fread(buf, 1, 2352, ct->fp);
1217
 
                break;
1218
 
 
1219
 
        case DI_FORMAT_MODE2:
1220
 
                fread(buf + 16, 1, 2336, ct->fp);
1221
 
                lec_encode_mode2_sector(lba + 150, buf);
1222
 
                break;
1223
 
 
1224
 
 
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);
1230
 
                break;
1231
 
 
1232
 
        case DI_FORMAT_MODE2_FORM2:
1233
 
                fread(buf + 24, 1, 2324, ct->fp);
1234
 
                //lec_encode_mode2_form2_sector(lba + 150, buf);
1235
 
                break;
1236
 
 
1237
 
      }
1238
 
 
1239
 
      if(ct->SubchannelMode)
1240
 
       fread(buf + 2352, 1, 96, ct->fp);
1241
 
     }
1242
 
    } // end if audible part of audio track read.
1243
 
    break;
1244
 
   } // End if LBA is in range
1245
 
  } // end track search loop
1246
 
 
1247
 
  if(!TrackFound)
1248
 
  {
1249
 
   puts("MOOOO");
1250
 
   memset(buf, 0, 2352);
1251
 
   return(0);
1252
 
  }
1253
 
 }
1254
 
 
1255
 
#if 0
1256
 
 if(qbuf[0] & 0x40)
1257
 
 {
1258
 
  uint8 dummy_buf[2352 + 96];
1259
 
  bool any_mismatch = FALSE;
1260
 
 
1261
 
  memcpy(dummy_buf + 16, buf + 16, 2048); 
1262
 
  memset(dummy_buf + 2352, 0, 96);
1263
 
 
1264
 
  MakeSubPQ(p_cdrfile, lba, dummy_buf + 2352);
1265
 
  lec_encode_mode1_sector(lba + 150, dummy_buf);
1266
 
 
1267
 
  for(int i = 0; i < 2352 + 96; i++)
1268
 
  {
1269
 
   if(dummy_buf[i] != buf[i])
1270
 
   {
1271
 
    printf("Mismatch at %d, %d: %02x:%02x; ", lba, i, dummy_buf[i], buf[i]);
1272
 
    any_mismatch = TRUE;
1273
 
   }
1274
 
  }
1275
 
  if(any_mismatch)
1276
 
   puts("\n");
1277
 
 }
1278
 
#endif
1279
 
 
1280
 
 cdrfile_deinterleave_subq(buf + 2352, qbuf);
1281
 
 
1282
 
 //printf("%02x\n", qbuf[0]);
1283
 
 //printf("%02x\n", buf[12 + 3]);
1284
 
 
1285
 
 return(true);
1286
 
}
1287
 
 
1288
 
int32 cdrfile_get_num_tracks (const CDRFile *p_cdrfile)
1289
 
{
1290
 
 return(p_cdrfile->NumTracks);
1291
 
}
1292
 
 
1293
 
CD_Track_Format_t cdrfile_get_track_format(const CDRFile *p_cdrfile, int32 i_track)
1294
 
{
1295
 
 return(p_cdrfile->Tracks[i_track].Format);
1296
 
}
1297
 
 
1298
 
int32 cdrfile_get_first_track_num(const CDRFile *p_cdrfile)
1299
 
{
1300
 
 return(p_cdrfile->FirstTrack);
1301
 
}
1302
 
 
1303
 
static void MakeSubPQ(const CDRFile *p_cdrfile, uint32 lba, uint8 *SubPWBuf)
1304
 
{
1305
 
 uint8 buf[0xC];
1306
 
 int32 track;
1307
 
 uint32 lba_relative;
1308
 
 uint32 ma, sa, fa;
1309
 
 uint32 m, s, f;
1310
 
 uint8 pause_or = 0x00;
1311
 
 bool track_found = FALSE;
1312
 
 
1313
 
 for(track = p_cdrfile->FirstTrack; track < (p_cdrfile->FirstTrack + p_cdrfile->NumTracks); track++)
1314
 
 {
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))
1316
 
  {
1317
 
   track_found = TRUE;
1318
 
   break;
1319
 
  }
1320
 
 }
1321
 
 
1322
 
 //printf("%d %d\n", p_cdrfile->Tracks[1].LBA, p_cdrfile->Tracks[1].sectors);
1323
 
 
1324
 
 if(!track_found)
1325
 
 {
1326
 
  printf("MakeSubPQ error for sector %u!", lba);
1327
 
  track = p_cdrfile->FirstTrack;
1328
 
 }
1329
 
 
1330
 
 lba_relative = abs((int32)lba - p_cdrfile->Tracks[track].LBA);
1331
 
 
1332
 
 f = (lba_relative % 75);
1333
 
 s = ((lba_relative / 75) % 60);
1334
 
 m = (lba_relative / 75 / 60);
1335
 
 
1336
 
 fa = (lba + 150) % 75;
1337
 
 sa = ((lba + 150) / 75) % 60;
1338
 
 ma = ((lba + 150) / 75 / 60);
1339
 
 
1340
 
 uint8 adr = 0x1; // Q channel data encodes position
1341
 
 uint8 control = (p_cdrfile->Tracks[track].Format == CD_TRACK_FORMAT_AUDIO) ? 0x00 : 0x04;
1342
 
 
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))
1345
 
 {
1346
 
  //printf("pause_or = 0x80 --- %d\n", lba);
1347
 
  pause_or = 0x80;
1348
 
 }
1349
 
 
1350
 
 // Handle pregap between audio->data track
1351
 
 {
1352
 
  int32 pg_offset = (int32)lba - p_cdrfile->Tracks[track].LBA;
1353
 
 
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)
1357
 
  {
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)
1360
 
   {
1361
 
    //printf("Pregap part 1 audio->data: lba=%d track_lba=%d\n", lba, p_cdrfile->Tracks[track].LBA);
1362
 
    control = 0x00;
1363
 
   }
1364
 
  }
1365
 
 }
1366
 
 
1367
 
 
1368
 
 memset(buf, 0, 0xC);
1369
 
 buf[0] = (adr << 0) | (control << 4);
1370
 
 buf[1] = INT_TO_BCD(track);
1371
 
 
1372
 
 if(lba < p_cdrfile->Tracks[track].LBA) // Index is 00 in pregap
1373
 
  buf[2] = INT_TO_BCD(0x00);
1374
 
 else
1375
 
  buf[2] = INT_TO_BCD(0x01);
1376
 
 
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);
1381
 
 
1382
 
 buf[6] = 0; // Zerroooo
1383
 
 
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);
1388
 
 
1389
 
 uint16 crc = 0;
1390
 
 
1391
 
 for(int i = 0; i < 0xA; i++)
1392
 
  crc = subq_crctab[(crc >> 8) ^ buf[i]] ^ (crc << 8);
1393
 
 
1394
 
 // Checksum
1395
 
 buf[0xa] = ~(crc >> 8);
1396
 
 buf[0xb] = ~(crc);
1397
 
 
1398
 
 for(int i = 0; i < 96; i++)
1399
 
  SubPWBuf[i] |= (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | pause_or;
1400
 
}
1401
 
 
1402
 
bool cdrfile_read_toc(const CDRFile *p_cdrfile, CD_TOC *toc)
1403
 
{
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
1407
 
 
1408
 
 for(int i = toc->first_track; i <= toc->last_track; i++)
1409
 
 {
1410
 
  toc->tracks[i].lba = p_cdrfile->Tracks[i].LBA;
1411
 
  toc->tracks[i].adr = ADR_CURPOS;
1412
 
  toc->tracks[i].control = 0x0;
1413
 
 
1414
 
  if(p_cdrfile->Tracks[i].Format != CD_TRACK_FORMAT_AUDIO)
1415
 
   toc->tracks[i].control |= 0x4;
1416
 
 }
1417
 
 
1418
 
 
1419
 
 toc->tracks[100].lba = p_cdrfile->total_sectors;
1420
 
 toc->tracks[100].adr = ADR_CURPOS;
1421
 
 toc->tracks[100].control = 0x00;       // Audio...
1422
 
 
1423
 
 // Convenience leadout track duplication.
1424
 
 if(toc->last_track < 99)
1425
 
  toc->tracks[toc->last_track + 1] = toc->tracks[100];
1426
 
 
1427
 
 return(true);
1428
 
}
1429
 
 
1430
 
bool cdrfile_is_physical(const CDRFile *p_cdrfile)
1431
 
{
1432
 
 #ifdef HAVE_LIBCDIO
1433
 
 if(p_cdrfile->p_cdio)
1434
 
  return(true);
1435
 
 #endif
1436
 
 
1437
 
 return(false);
1438
 
}