static int read_toc(const char *dev) { int first = 0, last = -1; int i; #if defined(__MINGW32__) || defined(__CYGWIN__) HANDLE drive; DWORD r; CDROM_TOC toc; char device[10]; sprintf(device, "\\\\.\\%s", dev); drive = CreateFile(device, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); if (!DeviceIoControl(drive, IOCTL_CDROM_READ_TOC, NULL, 0, &toc, sizeof(CDROM_TOC), &r, 0)) { mp_tmsg(MSGT_OPEN, MSGL_ERR, "Failed to read TOC.\n"); return 0; } first = toc.FirstTrack - 1; last = toc.LastTrack; for (i = first; i <= last; i++) { cdtoc[i].min = toc.TrackData[i].Address[1]; cdtoc[i].sec = toc.TrackData[i].Address[2]; cdtoc[i].frame = toc.TrackData[i].Address[3]; } CloseHandle(drive); #elif defined(__OS2__) UCHAR auchParamDisk[4] = {'C', 'D', '0', '1'}; struct { BYTE bFirstTrack; BYTE bLastTrack; BYTE bLeadOutF; BYTE bLeadOutS; BYTE bLeadOutM; BYTE bLeadOutReserved; } __attribute__((packed)) sDataDisk; struct { UCHAR auchSign[4]; BYTE bTrack; } __attribute__((packed)) sParamTrack = {{'C', 'D', '0', '1'},}; struct { BYTE bStartF; BYTE bStartS; BYTE bStartM; BYTE bStartReserved; BYTE bControlInfo; } __attribute__((packed)) sDataTrack; HFILE hcd; ULONG ulAction; ULONG ulParamLen; ULONG ulDataLen; ULONG rc; rc = DosOpen(dev, &hcd, &ulAction, 0, FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW, OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE | OPEN_FLAGS_DASD, NULL); if (rc) { mp_tmsg(MSGT_OPEN, MSGL_ERR, "Failed to read TOC.\n"); return -1; } rc = DosDevIOCtl(hcd, IOCTL_CDROMAUDIO, CDROMAUDIO_GETAUDIODISK, auchParamDisk, sizeof(auchParamDisk), &ulParamLen, &sDataDisk, sizeof(sDataDisk), &ulDataLen); if (!rc) { first = sDataDisk.bFirstTrack - 1; last = sDataDisk.bLastTrack; for (i = first; i <= last; i++) { if (i == last) { sDataTrack.bStartM = sDataDisk.bLeadOutM; sDataTrack.bStartS = sDataDisk.bLeadOutS; sDataTrack.bStartF = sDataDisk.bLeadOutF; } else { sParamTrack.bTrack = i + 1; rc = DosDevIOCtl(hcd, IOCTL_CDROMAUDIO, CDROMAUDIO_GETAUDIOTRACK, &sParamTrack, sizeof(sParamTrack), &ulParamLen, &sDataTrack, sizeof(sDataTrack), &ulDataLen); if (rc) break; } cdtoc[i].min = sDataTrack.bStartM; cdtoc[i].sec = sDataTrack.bStartS; cdtoc[i].frame = sDataTrack.bStartF; } } DosClose(hcd); if (rc) { mp_tmsg(MSGT_OPEN, MSGL_ERR, "Failed to read TOC.\n"); return -1; } #else int drive; drive = open(dev, O_RDONLY | O_NONBLOCK); if (drive < 0) { return drive; } #if defined(__linux__) || defined(__bsdi__) { struct cdrom_tochdr tochdr; ioctl(drive, CDROMREADTOCHDR, &tochdr); first = tochdr.cdth_trk0 - 1; last = tochdr.cdth_trk1; } for (i = first; i <= last; i++) { struct cdrom_tocentry tocentry; tocentry.cdte_track = (i == last) ? 0xAA : i + 1; tocentry.cdte_format = CDROM_MSF; ioctl(drive, CDROMREADTOCENTRY, &tocentry); cdtoc[i].min = tocentry.cdte_addr.msf.minute; cdtoc[i].sec = tocentry.cdte_addr.msf.second; cdtoc[i].frame = tocentry.cdte_addr.msf.frame; } #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) { struct ioc_toc_header tochdr; ioctl(drive, CDIOREADTOCHEADER, &tochdr); first = tochdr.starting_track - 1; last = tochdr.ending_track; } for (i = first; i <= last; i++) { struct ioc_read_toc_single_entry tocentry; tocentry.track = (i == last) ? 0xAA : i + 1; tocentry.address_format = CD_MSF_FORMAT; ioctl(drive, CDIOREADTOCENTRY, &tocentry); cdtoc[i].min = tocentry.entry.addr.msf.minute; cdtoc[i].sec = tocentry.entry.addr.msf.second; cdtoc[i].frame = tocentry.entry.addr.msf.frame; } #elif defined(__NetBSD__) || defined(__OpenBSD__) { struct ioc_toc_header tochdr; ioctl(drive, CDIOREADTOCHEADER, &tochdr); first = tochdr.starting_track - 1; last = tochdr.ending_track; } for (i = first; i <= last; i++) { struct ioc_read_toc_entry tocentry; struct cd_toc_entry toc_buffer; tocentry.starting_track = (i == last) ? 0xAA : i + 1; tocentry.address_format = CD_MSF_FORMAT; tocentry.data = &toc_buffer; tocentry.data_len = sizeof(toc_buffer); ioctl(drive, CDIOREADTOCENTRYS, &tocentry); cdtoc[i].min = toc_buffer.addr.msf.minute; cdtoc[i].sec = toc_buffer.addr.msf.second; cdtoc[i].frame = toc_buffer.addr.msf.frame; } #elif defined(__APPLE__) || defined(__DARWIN__) { dk_cd_read_toc_t tochdr; uint8_t buf[4]; uint8_t buf2[100 * sizeof(CDTOCDescriptor) + sizeof(CDTOC)]; memset(&tochdr, 0, sizeof(tochdr)); tochdr.bufferLength = sizeof(buf); tochdr.buffer = &buf; if (!ioctl(drive, DKIOCCDREADTOC, &tochdr) && tochdr.bufferLength == sizeof(buf)) { first = buf[2] - 1; last = buf[3]; } if (last >= 0) { memset(&tochdr, 0, sizeof(tochdr)); tochdr.bufferLength = sizeof(buf2); tochdr.buffer = &buf2; tochdr.format = kCDTOCFormatTOC; if (ioctl(drive, DKIOCCDREADTOC, &tochdr) || tochdr.bufferLength < sizeof(CDTOC)) last = -1; } if (last >= 0) { CDTOC *cdToc = (CDTOC *)buf2; CDTrackInfo lastTrack; dk_cd_read_track_info_t trackInfoParams; for (i = first; i < last; ++i) { CDMSF msf = CDConvertTrackNumberToMSF(i + 1, cdToc); cdtoc[i].min = msf.minute; cdtoc[i].sec = msf.second; cdtoc[i].frame = msf.frame; } memset(&trackInfoParams, 0, sizeof(trackInfoParams)); trackInfoParams.addressType = kCDTrackInfoAddressTypeTrackNumber; trackInfoParams.bufferLength = sizeof(lastTrack); trackInfoParams.address = last; trackInfoParams.buffer = &lastTrack; if (!ioctl(drive, DKIOCCDREADTRACKINFO, &trackInfoParams)) { CDMSF msf = CDConvertLBAToMSF(be2me_32(lastTrack.trackStartAddress) + be2me_32(lastTrack.trackSize)); cdtoc[last].min = msf.minute; cdtoc[last].sec = msf.second; cdtoc[last].frame = msf.frame; } } } #endif close(drive); #endif for (i = first; i <= last; i++) cdtoc[i].frame += (cdtoc[i].min * 60 + cdtoc[i].sec) * 75; return last; }
static int read_toc(const char *dev) { int first = 0, last = -1; int i; #if defined(__MINGW32__) || defined(__CYGWIN__) HANDLE drive; DWORD r; CDROM_TOC toc; char device[10]; snprintf(device, sizeof(device), "\\\\.\\%s", dev); drive = CreateFile(device, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); if (!DeviceIoControl(drive, IOCTL_CDROM_READ_TOC, NULL, 0, &toc, sizeof(CDROM_TOC), &r, 0)) { mp_tmsg(MSGT_OPEN, MSGL_ERR, "Failed to read TOC.\n"); return 0; } first = toc.FirstTrack - 1; last = toc.LastTrack; for (i = first; i <= last; i++) { cdtoc[i].min = toc.TrackData[i].Address[1]; cdtoc[i].sec = toc.TrackData[i].Address[2]; cdtoc[i].frame = toc.TrackData[i].Address[3]; } CloseHandle(drive); #else int drive; drive = open(dev, O_RDONLY | O_NONBLOCK); if (drive < 0) { return drive; } #if defined(__linux__) || defined(__bsdi__) { struct cdrom_tochdr tochdr; ioctl(drive, CDROMREADTOCHDR, &tochdr); first = tochdr.cdth_trk0 - 1; last = tochdr.cdth_trk1; } for (i = first; i <= last; i++) { struct cdrom_tocentry tocentry; tocentry.cdte_track = (i == last) ? 0xAA : i + 1; tocentry.cdte_format = CDROM_MSF; ioctl(drive, CDROMREADTOCENTRY, &tocentry); cdtoc[i].min = tocentry.cdte_addr.msf.minute; cdtoc[i].sec = tocentry.cdte_addr.msf.second; cdtoc[i].frame = tocentry.cdte_addr.msf.frame; } #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) { struct ioc_toc_header tochdr; ioctl(drive, CDIOREADTOCHEADER, &tochdr); first = tochdr.starting_track - 1; last = tochdr.ending_track; } for (i = first; i <= last; i++) { struct ioc_read_toc_single_entry tocentry; tocentry.track = (i == last) ? 0xAA : i + 1; tocentry.address_format = CD_MSF_FORMAT; ioctl(drive, CDIOREADTOCENTRY, &tocentry); cdtoc[i].min = tocentry.entry.addr.msf.minute; cdtoc[i].sec = tocentry.entry.addr.msf.second; cdtoc[i].frame = tocentry.entry.addr.msf.frame; } #elif defined(__NetBSD__) || defined(__OpenBSD__) { struct ioc_toc_header tochdr; ioctl(drive, CDIOREADTOCHEADER, &tochdr); first = tochdr.starting_track - 1; last = tochdr.ending_track; } for (i = first; i <= last; i++) { struct ioc_read_toc_entry tocentry; struct cd_toc_entry toc_buffer; tocentry.starting_track = (i == last) ? 0xAA : i + 1; tocentry.address_format = CD_MSF_FORMAT; tocentry.data = &toc_buffer; tocentry.data_len = sizeof(toc_buffer); ioctl(drive, CDIOREADTOCENTRYS, &tocentry); cdtoc[i].min = toc_buffer.addr.msf.minute; cdtoc[i].sec = toc_buffer.addr.msf.second; cdtoc[i].frame = toc_buffer.addr.msf.frame; } #elif defined(__APPLE__) || defined(__DARWIN__) { dk_cd_read_toc_t tochdr; uint8_t buf[4]; uint8_t buf2[100 * sizeof(CDTOCDescriptor) + sizeof(CDTOC)]; memset(&tochdr, 0, sizeof(tochdr)); tochdr.bufferLength = sizeof(buf); tochdr.buffer = &buf; if (!ioctl(drive, DKIOCCDREADTOC, &tochdr) && tochdr.bufferLength == sizeof(buf)) { first = buf[2] - 1; last = buf[3]; } if (last >= 0) { memset(&tochdr, 0, sizeof(tochdr)); tochdr.bufferLength = sizeof(buf2); tochdr.buffer = &buf2; tochdr.format = kCDTOCFormatTOC; if (ioctl(drive, DKIOCCDREADTOC, &tochdr) || tochdr.bufferLength < sizeof(CDTOC)) last = -1; } if (last >= 0) { CDTOC *cdToc = (CDTOC *)buf2; CDTrackInfo lastTrack; dk_cd_read_track_info_t trackInfoParams; for (i = first; i < last; ++i) { CDMSF msf = CDConvertTrackNumberToMSF(i + 1, cdToc); cdtoc[i].min = msf.minute; cdtoc[i].sec = msf.second; cdtoc[i].frame = msf.frame; } memset(&trackInfoParams, 0, sizeof(trackInfoParams)); trackInfoParams.addressType = kCDTrackInfoAddressTypeTrackNumber; trackInfoParams.bufferLength = sizeof(lastTrack); trackInfoParams.address = last; trackInfoParams.buffer = &lastTrack; if (!ioctl(drive, DKIOCCDREADTRACKINFO, &trackInfoParams)) { CDMSF msf = CDConvertLBAToMSF(be2me_32(lastTrack.trackStartAddress) + be2me_32(lastTrack.trackSize)); cdtoc[last].min = msf.minute; cdtoc[last].sec = msf.second; cdtoc[last].frame = msf.frame; } } } #endif close(drive); #endif for (i = first; i <= last; i++) cdtoc[i].frame += (cdtoc[i].min * 60 + cdtoc[i].sec) * 75; return last; }