#include #include #include #include #include #include #include "cdreader.h" #include "Exceptions.h" #include "generic.h" #ifdef HAVE_CONFIG_H #include "config.h" #else #define _(x) x #endif #include "cdabstract.h" bool cdreader::CanWrite() const { return 0; } bool cdreader::CanRead() const { return 1; } bool cdreader::CanSeek() const { return 1; } String cdreader::GetName() const { return n + " raw reading"; } ssize_t cdreader::GetSize() const { return -1; } off_t cdreader::seek(off_t offset, int whence) throw (GeneralException) { switch (whence) { case SEEK_SET: itell = offset; break; case SEEK_CUR: itell += offset; break; case SEEK_END: throw GeneralException("Can not yet seek from the end of a CD."); } return itell; } ssize_t cdreader::read(void *buf, size_t count) throw (GeneralException) { char sector[2352]; size_t r = count; size_t remain = itell % 2352; sectorseek(itell / 2352); while (count > 0) { size_t n = MIN(2352 - remain, count); getsector(sector); bcopy(sector + remain, buf, n); buf = ((char *) buf) + n; itell += n; count -= n; remain = 0; } return r; } void cdreader::sectorseek(int sec) { sector = sec; } #ifdef __linux__ #include #include #include cdreader::cdreader(const String & no) throw (GeneralException) : Handle(open(no.to_charp(), O_RDONLY)), n(no), sector(0) { #ifdef DEBUG printm(M_ERROR, "Opening cdrom device " + no + "\n"); #endif if (GetHandle() < 0) { throw IOGeneral(String(_("Error opening file ")) + no + _(" for reading: ") + strerror(errno)); } struct stat s; fstat(GetHandle(), &s); if (!S_ISBLK(s.st_mode)) { throw GeneralException(no + " is not a block device."); } } cdreader::cdreader(const cdreader & i) : Handle(i), n(i.n) { } void cdreader::getsector(void *buf, int sec) throw (GeneralException) { struct cdrom_msf * msf = (struct cdrom_msf *) buf; if (sec >= 0) sector = sec; sector += 150; msf->cdmsf_min0 = sector /CD_SECS /CD_FRAMES; msf->cdmsf_sec0 = (sector /CD_FRAMES)%CD_SECS; msf->cdmsf_frame0= sector %CD_FRAMES; msf->cdmsf_min1 = (sector+1)/CD_SECS /CD_FRAMES; msf->cdmsf_sec1 = ((sector+1)/CD_FRAMES)%CD_SECS; msf->cdmsf_frame1= (sector+1)%CD_FRAMES; sector -= 150; if (ioctl(GetHandle(), CDROMREADRAW, buf) < 0) { throw GeneralException(String("unable to read cd sector ") + sector + ": " + strerror(errno)); } sector++; } #endif #if defined (_MSC_VER) || defined (__MINGW32__) cdreader::cdreader(const String & no) throw (GeneralException) : Handle(-1), n(no), sector(0) { if (!(hF = cdabstract::OpenIOCTLFile(no[0]))) throw GeneralException("Error opening device " + no); } cdreader::cdreader(const cdreader & i) : Handle(i), n(i.n), hF(i.hF) { } void cdreader::close() throw (GeneralException) { CloseHandle(hF); } typedef enum _TRACK_MODE_TYPE { YellowMode2, XAForm2, CDDA } TRACK_MODE_TYPE, *PTRACK_MODE_TYPE; typedef struct _RAW_READ_INFO { LARGE_INTEGER DiskOffset; ULONG SectorCount; TRACK_MODE_TYPE TrackMode; } RAW_READ_INFO, *PRAW_READ_INFO; void cdreader::getsector(void *buf, int sec) throw (GeneralException) { RAW_READ_INFO rawIOCTL; DWORD dwRet; BOOL bStat; bool done = false; if (sec >= 0) sector = sec; rawIOCTL.DiskOffset.QuadPart = sector * 2048; rawIOCTL.SectorCount = 1; rawIOCTL.TrackMode = YellowMode2; while (!done) { SetLastError(0); bStat = DeviceIoControl(hF, IOCTL_CDROM_RAW_READ, &rawIOCTL, sizeof(RAW_READ_INFO), buf, 2352, &dwRet, NULL); if (!bStat) { DWORD dwErrCode = GetLastError(); if (dwErrCode == ERROR_INVALID_FUNCTION) { if (rawIOCTL.TrackMode == YellowMode2) { rawIOCTL.TrackMode = XAForm2; continue; } } if (dwErrCode != ERROR_IO_PENDING) { LPVOID lpMsgBuf; if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL )) throw GeneralException("Gave up on reading CD: unknown error"); String errmsg = (LPCTSTR) lpMsgBuf; LocalFree(lpMsgBuf); throw GeneralException("Gave up on reading CD: " + errmsg); } } else { done = true; } } } #endif