diff options
Diffstat (limited to 'lib/cdreader.cpp')
-rw-r--r-- | lib/cdreader.cpp | 668 |
1 files changed, 334 insertions, 334 deletions
diff --git a/lib/cdreader.cpp b/lib/cdreader.cpp index 7777c4d..af1b419 100644 --- a/lib/cdreader.cpp +++ b/lib/cdreader.cpp @@ -1,334 +1,334 @@ -/*
- * PSX-Tools Bundle Pack
- * Copyright (C) 2002-2003 Nicolas "Pixel" Noble
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/* $Id: cdreader.cpp,v 1.20 2004-11-27 21:44:48 pixel Exp $ */
-
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include "cdreader.h"
-#include "Exceptions.h"
-#include "generic.h"
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#else
-#define _(x) x
-#endif
-#include "cdabstract.h"
-
-#define nsectorsarow 1
-#define cachesize 2048
-
-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);
- fetchsector(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;
-}
-
-void cdreader::fetchsector(void * buf, int sec) {
- if (sec >= 0)
- sector = sec;
-
- if (sectors[sector]) {
- actualize(sectors[sector]);
- memcpy(buf, sectors[sector]->sector, 2352);
- return;
- }
-
- Byte buffers[2352 * nsectorsarow];
-
- getsector(buffers, sec = sector, nsectorsarow);
-
- for (int i = nsectorsarow - 1; i >= 0; i--) {
- introduce(buffers + i * 2352, sec + i);
- }
-
- memcpy(buf, buffers, 2352);
-
- while (nsectors > cachesize) {
- removetail();
- }
-}
-
-cdreader::~cdreader() {
- while (nsectors) {
- removetail();
- }
-}
-
-void cdreader::removetail() {
- if (!tail)
- return;
-
- sectors[tail->n] = 0;
-
- if (head == tail) {
- free(tail);
- head = tail = 0;
- nsectors = 0;
- } else {
- cachedsector * p;
- (p = tail->prev)->next = 0;
- free(tail);
- tail = p;
- nsectors--;
- }
-}
-
-void cdreader::actualize(cachedsector * s) {
- if (s == head)
- return;
-
- if (s != tail) {
- s->next->prev = s->prev;
- } else {
- tail = s->prev;
- }
- s->prev->next = s->next;
-
- head->prev = s;
- s->prev = 0;
- s->next = head;
- head = s;
-}
-
-void cdreader::introduce(Byte * datas, int n) {
- cachedsector * s;
-
- s = (cachedsector *) malloc(sizeof(cachedsector));
- memcpy(s->sector, datas, 2352);
- s->n = n;
-
- if (head) {
- s->next = head;
- head->prev = s;
- head = s;
- } else {
- head = tail = s;
- s->prev = s->next = 0;
- }
- sectors[n] = s;
-
- nsectors++;
-}
-
-#ifdef __linux__
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <linux/cdrom.h>
-
-cdreader::cdreader(const String & no) throw (GeneralException) :
- Handle(open(no.to_charp(), O_RDONLY)), n(no), sector(0) {
- int i;
-
-#ifdef DEBUG
- printm(M_INFO, "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.");
- }
-
- for (i = 0; i < 400000; i++) {
- sectors[i] = 0;
- }
- head = tail = 0;
- nsectors = 0;
-}
-
-cdreader::cdreader(const cdreader & inp) : Handle(inp), n(inp.n) {
- int i;
-
- for (i = 0; i < 400000; i++) {
- sectors[i] = 0;
- }
- head = tail = 0;
- nsectors = 0;
-}
-
-void cdreader::getsector(void *buf, int sec, int nb) 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 + nb)/CD_SECS /CD_FRAMES;
- msf->cdmsf_sec1 = ((sector + nb)/CD_FRAMES)%CD_SECS;
- msf->cdmsf_frame1= (sector + nb)%CD_FRAMES;
-
- sector -= 150;
-
- if (ioctl(GetHandle(), CDROMREADRAW, buf) < 0) {
- throw GeneralException(String("unable to read cd sector ") + sector + ": " + strerror(errno));
- }
-
- sector += nb;
-}
-#endif
-
-#if defined (_MSC_VER) || defined (__MINGW32__)
-cdreader::cdreader(const String & no) throw (GeneralException) :
- Handle(-1), n(no), sector(0) {
- if (!(hFile = cdabstract::OpenIOCTLFile(no[0])))
- throw GeneralException("Error opening device " + no);
- for (int i = 0; i < 400000; i++) {
- sectors[i] = 0;
- }
- head = tail = 0;
- nsectors = 0;
-}
-
-cdreader::cdreader(const cdreader & i) : Handle(i), n(i.n) {
- hFile = i.hFile;
- for (int x = 0; x < 400000; x++) {
- sectors[x] = 0;
- }
- head = tail = 0;
- nsectors = 0;
-}
-
-void cdreader::close() throw (GeneralException) {
- CloseHandle(hFile);
-}
-
-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, int nb) 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 = nb;
- rawIOCTL.TrackMode = YellowMode2;
-
- while (!done) {
- SetLastError(0);
- bStat = DeviceIoControl(hFile, IOCTL_CDROM_RAW_READ,
- &rawIOCTL, sizeof(RAW_READ_INFO),
- buf, 2352 * nb, &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;
- }
- }
-
- sector += nb;
-}
-
-#endif
+/* + * PSX-Tools Bundle Pack + * Copyright (C) 2002-2003 Nicolas "Pixel" Noble + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* $Id: cdreader.cpp,v 1.21 2004-11-27 21:47:56 pixel Exp $ */ + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include "cdreader.h" +#include "Exceptions.h" +#include "generic.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#else +#define _(x) x +#endif +#include "cdabstract.h" + +#define nsectorsarow 1 +#define cachesize 2048 + +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); + fetchsector(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; +} + +void cdreader::fetchsector(void * buf, int sec) { + if (sec >= 0) + sector = sec; + + if (sectors[sector]) { + actualize(sectors[sector]); + memcpy(buf, sectors[sector]->sector, 2352); + return; + } + + Byte buffers[2352 * nsectorsarow]; + + getsector(buffers, sec = sector, nsectorsarow); + + for (int i = nsectorsarow - 1; i >= 0; i--) { + introduce(buffers + i * 2352, sec + i); + } + + memcpy(buf, buffers, 2352); + + while (nsectors > cachesize) { + removetail(); + } +} + +cdreader::~cdreader() { + while (nsectors) { + removetail(); + } +} + +void cdreader::removetail() { + if (!tail) + return; + + sectors[tail->n] = 0; + + if (head == tail) { + free(tail); + head = tail = 0; + nsectors = 0; + } else { + cachedsector * p; + (p = tail->prev)->next = 0; + free(tail); + tail = p; + nsectors--; + } +} + +void cdreader::actualize(cachedsector * s) { + if (s == head) + return; + + if (s != tail) { + s->next->prev = s->prev; + } else { + tail = s->prev; + } + s->prev->next = s->next; + + head->prev = s; + s->prev = 0; + s->next = head; + head = s; +} + +void cdreader::introduce(Byte * datas, int n) { + cachedsector * s; + + s = (cachedsector *) malloc(sizeof(cachedsector)); + memcpy(s->sector, datas, 2352); + s->n = n; + + if (head) { + s->next = head; + head->prev = s; + head = s; + } else { + head = tail = s; + s->prev = s->next = 0; + } + sectors[n] = s; + + nsectors++; +} + +#ifdef __linux__ +#include <unistd.h> +#include <sys/ioctl.h> +#include <linux/cdrom.h> + +cdreader::cdreader(const String & no) throw (GeneralException) : + Handle(open(no.to_charp(), O_RDONLY)), n(no), sector(0) { + int i; + +#ifdef DEBUG + printm(M_INFO, "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."); + } + + for (i = 0; i < 400000; i++) { + sectors[i] = 0; + } + head = tail = 0; + nsectors = 0; +} + +cdreader::cdreader(const cdreader & inp) : Handle(inp), n(inp.n) { + int i; + + for (i = 0; i < 400000; i++) { + sectors[i] = 0; + } + head = tail = 0; + nsectors = 0; +} + +void cdreader::getsector(void *buf, int sec, int nb) 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 + nb)/CD_SECS /CD_FRAMES; + msf->cdmsf_sec1 = ((sector + nb)/CD_FRAMES)%CD_SECS; + msf->cdmsf_frame1= (sector + nb)%CD_FRAMES; + + sector -= 150; + + if (ioctl(GetHandle(), CDROMREADRAW, buf) < 0) { + throw GeneralException(String("unable to read cd sector ") + sector + ": " + strerror(errno)); + } + + sector += nb; +} +#endif + +#if defined (_MSC_VER) || defined (__MINGW32__) +cdreader::cdreader(const String & no) throw (GeneralException) : + Handle(-1), n(no), sector(0) { + if (!(hFile = cdabstract::OpenIOCTLFile(no[0]))) + throw GeneralException("Error opening device " + no); + for (int i = 0; i < 400000; i++) { + sectors[i] = 0; + } + head = tail = 0; + nsectors = 0; +} + +cdreader::cdreader(const cdreader & i) : Handle(i), n(i.n) { + hFile = i.hFile; + for (int x = 0; x < 400000; x++) { + sectors[x] = 0; + } + head = tail = 0; + nsectors = 0; +} + +void cdreader::close() throw (GeneralException) { + CloseHandle(hFile); +} + +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, int nb) 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 = nb; + rawIOCTL.TrackMode = YellowMode2; + + while (!done) { + SetLastError(0); + bStat = DeviceIoControl(hFile, IOCTL_CDROM_RAW_READ, + &rawIOCTL, sizeof(RAW_READ_INFO), + buf, 2352 * nb, &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; + } + } + + sector += nb; +} + +#endif |