File indexing completed on 2025-04-27 07:40:57
0001 /* 0002 SPDX-FileCopyrightText: 2010 Michal Malek <michalm@jabster.pl> 0003 SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include <config-k3b.h> 0009 0010 #include "k3bcdparanoialib.h" 0011 0012 #include "k3bdevice.h" 0013 #include "k3btoc.h" 0014 #include "k3bmsf.h" 0015 0016 #include <QDebug> 0017 #include <QFile> 0018 #include <QGlobalStatic> 0019 #include <QLibrary> 0020 #include <QMutex> 0021 #include <QMutexLocker> 0022 0023 #ifdef Q_OS_WIN32 0024 typedef short int int16_t; 0025 #endif 0026 0027 static bool s_haveLibCdio = false; 0028 0029 0030 0031 #define CDDA_IDENTIFY s_haveLibCdio ? "cdio_cddap_identify" : "cdda_identify" 0032 #define CDDA_CLOSE s_haveLibCdio ? "cdio_cddap_close" : "cdda_close" 0033 #define CDDA_OPEN s_haveLibCdio ? "cdio_cddap_open" : "cdda_open" 0034 #define CDDA_TRACK_FIRSTSECTOR s_haveLibCdio ? "cdio_cddap_track_firstsector" : "cdda_track_firstsector" 0035 #define CDDA_TRACK_LASTSECTOR s_haveLibCdio ? "cdio_cddap_track_lastsector" : "cdda_track_lastsector" 0036 #define CDDA_VERBOSE_SET s_haveLibCdio ? "cdio_cddap_verbose_set" : "cdda_verbose_set" 0037 #define CDDA_DISC_FIRSTSECTOR s_haveLibCdio ? "cdio_cddap_disc_firstsector" : "cdda_disc_firstsector" 0038 0039 #define PARANOIA_INIT s_haveLibCdio ? "cdio_paranoia_init" : "paranoia_init" 0040 #define PARANOIA_FREE s_haveLibCdio ? "cdio_paranoia_free" : "paranoia_free" 0041 #define PARANOIA_MODESET s_haveLibCdio ? "cdio_paranoia_modeset" : "paranoia_modeset" 0042 #define PARANOIA_SEEK s_haveLibCdio ? "cdio_paranoia_seek" : "paranoia_seek" 0043 #define PARANOIA_READ_LIMITED s_haveLibCdio ? "cdio_paranoia_read_limited" : "paranoia_read_limited" 0044 0045 0046 // from cdda_paranoia.h 0047 #define PARANOIA_CB_READ 0 0048 #define PARANOIA_CB_VERIFY 1 0049 #define PARANOIA_CB_FIXUP_EDGE 2 0050 #define PARANOIA_CB_FIXUP_ATOM 3 0051 #define PARANOIA_CB_SCRATCH 4 0052 #define PARANOIA_CB_REPAIR 5 0053 #define PARANOIA_CB_SKIP 6 0054 #define PARANOIA_CB_DRIFT 7 0055 #define PARANOIA_CB_BACKOFF 8 0056 #define PARANOIA_CB_OVERLAP 9 0057 #define PARANOIA_CB_FIXUP_DROPPED 10 0058 #define PARANOIA_CB_FIXUP_DUPED 11 0059 #define PARANOIA_CB_READERR 12 0060 0061 0062 Q_GLOBAL_STATIC(QLibrary, s_libInterface) 0063 Q_GLOBAL_STATIC(QLibrary, s_libParanoia) 0064 0065 0066 0067 static void paranoiaCallback( long, int status ) 0068 { 0069 // do nothing so far.... 0070 return; 0071 0072 switch( status ) { 0073 case -1: 0074 break; 0075 case -2: 0076 break; 0077 case PARANOIA_CB_READ: 0078 // no problem 0079 // does only this mean that the sector has been read? 0080 // m_lastReadSector = sector; // this seems to be rather useless 0081 // m_readSectors++; 0082 break; 0083 case PARANOIA_CB_VERIFY: 0084 break; 0085 case PARANOIA_CB_FIXUP_EDGE: 0086 break; 0087 case PARANOIA_CB_FIXUP_ATOM: 0088 break; 0089 case PARANOIA_CB_SCRATCH: 0090 // scratch detected 0091 break; 0092 case PARANOIA_CB_REPAIR: 0093 break; 0094 case PARANOIA_CB_SKIP: 0095 // skipped sector 0096 break; 0097 case PARANOIA_CB_DRIFT: 0098 break; 0099 case PARANOIA_CB_BACKOFF: 0100 break; 0101 case PARANOIA_CB_OVERLAP: 0102 // sector does not seem to contain the current 0103 // sector but the amount of overlapped data 0104 // m_overlap = sector; 0105 break; 0106 case PARANOIA_CB_FIXUP_DROPPED: 0107 break; 0108 case PARANOIA_CB_FIXUP_DUPED: 0109 break; 0110 case PARANOIA_CB_READERR: 0111 break; 0112 } 0113 } 0114 0115 0116 0117 extern "C" { 0118 struct cdrom_drive; 0119 struct cdrom_paranoia; 0120 0121 // HINT: these pointers must NOT have the same name like the actual methods! 0122 // I added "cdda_" as prefix 0123 // Before doing that K3b crashed in cdda_open! 0124 // Can anyone please explain that to me? 0125 0126 // cdda_interface 0127 cdrom_drive* (*cdda_cdda_identify)(const char*, int, char**); 0128 int (*cdda_cdda_open)(cdrom_drive *d); 0129 int (*cdda_cdda_close)(cdrom_drive *d); 0130 long (*cdda_cdda_track_firstsector)( cdrom_drive*, int ); 0131 long (*cdda_cdda_track_lastsector)( cdrom_drive*, int ); 0132 long (*cdda_cdda_disc_firstsector)(cdrom_drive *d); 0133 void (*cdda_cdda_verbose_set)(cdrom_drive *d,int err_action, int mes_action); 0134 0135 // cdda_paranoia 0136 cdrom_paranoia* (*cdda_paranoia_init)(cdrom_drive*); 0137 void (*cdda_paranoia_free)(cdrom_paranoia *p); 0138 void (*cdda_paranoia_modeset)(cdrom_paranoia *p, int mode); 0139 int16_t* (*cdda_paranoia_read_limited)(cdrom_paranoia *p, void(*callback)(long,int), int); 0140 long (*cdda_paranoia_seek)(cdrom_paranoia *p,long seek,int mode); 0141 } 0142 0143 // from cdda_paranoia.h 0144 #define PARANOIA_MODE_FULL 0xff 0145 #define PARANOIA_MODE_DISABLE 0 0146 0147 #define PARANOIA_MODE_VERIFY 1 0148 #define PARANOIA_MODE_FRAGMENT 2 0149 #define PARANOIA_MODE_OVERLAP 4 0150 #define PARANOIA_MODE_SCRATCH 8 0151 #define PARANOIA_MODE_REPAIR 16 0152 #define PARANOIA_MODE_NEVERSKIP 32 0153 0154 0155 0156 namespace K3b { 0157 /** 0158 * Internal class used by CdparanoiaLib 0159 */ 0160 class CdparanoiaLibData 0161 { 0162 public: 0163 ~CdparanoiaLibData() 0164 { 0165 paranoiaFree(); 0166 } 0167 0168 Device::Device* device() const { return m_device; } 0169 void paranoiaModeSet( int ); 0170 bool paranoiaInit(); 0171 void paranoiaFree(); 0172 int16_t* paranoiaRead( void(*callback)(long,int), int maxRetries ); 0173 long paranoiaSeek( long, int ); 0174 long firstSector( int ); 0175 long lastSector( int ); 0176 long sector() const { return m_currentSector; } 0177 0178 static CdparanoiaLibData* data( Device::Device* dev ) 0179 { 0180 QMap<Device::Device*, CdparanoiaLibData*>::const_iterator it = s_dataMap.constFind( dev ); 0181 if( it == s_dataMap.constEnd() ) { 0182 CdparanoiaLibData* data = new CdparanoiaLibData( dev ); 0183 s_dataMap.insert( dev, data ); 0184 return data; 0185 } 0186 else 0187 return *it; 0188 } 0189 0190 static void freeAll() 0191 { 0192 // clean up all CdparanoiaLibData instances 0193 qDeleteAll( s_dataMap ); 0194 s_dataMap.clear(); 0195 } 0196 0197 private: 0198 CdparanoiaLibData( Device::Device* dev ) 0199 : m_device(dev), 0200 m_drive(0), 0201 m_paranoia(0), 0202 m_currentSector(0) 0203 { 0204 } 0205 0206 // 0207 // We have exactly one instance of CdparanoiaLibData per device 0208 // 0209 static QMap<Device::Device*, CdparanoiaLibData*> s_dataMap; 0210 0211 Device::Device* m_device; 0212 0213 cdrom_drive* m_drive; 0214 cdrom_paranoia* m_paranoia; 0215 0216 long m_currentSector; 0217 0218 QMutex m_mutex; 0219 }; 0220 } 0221 0222 QMap<K3b::Device::Device*, K3b::CdparanoiaLibData*> K3b::CdparanoiaLibData::s_dataMap; 0223 0224 bool K3b::CdparanoiaLibData::paranoiaInit() 0225 { 0226 if( m_drive ) 0227 paranoiaFree(); 0228 0229 QMutexLocker locker( &m_mutex ); 0230 0231 // since we use cdparanoia to open the device it is important to close 0232 // the device here 0233 m_device->close(); 0234 0235 m_drive = cdda_cdda_identify( QFile::encodeName(m_device->blockDeviceName()), 0, 0 ); 0236 if( m_drive == 0 ) { 0237 return false; 0238 } 0239 0240 // cdda_cdda_verbose_set( m_drive, 1, 1 ); 0241 0242 cdda_cdda_open( m_drive ); 0243 m_paranoia = cdda_paranoia_init( m_drive ); 0244 if( m_paranoia == 0 ) { 0245 paranoiaFree(); 0246 return false; 0247 } 0248 0249 m_currentSector = 0; 0250 0251 return true; 0252 } 0253 0254 0255 void K3b::CdparanoiaLibData::paranoiaFree() 0256 { 0257 QMutexLocker locker( &m_mutex ); 0258 0259 if( m_paranoia ) { 0260 cdda_paranoia_free( m_paranoia ); 0261 m_paranoia = 0; 0262 } 0263 if( m_drive ) { 0264 cdda_cdda_close( m_drive ); 0265 m_drive = 0; 0266 } 0267 } 0268 0269 0270 void K3b::CdparanoiaLibData::paranoiaModeSet( int mode ) 0271 { 0272 QMutexLocker locker( &m_mutex ); 0273 cdda_paranoia_modeset( m_paranoia, mode ); 0274 } 0275 0276 0277 int16_t* K3b::CdparanoiaLibData::paranoiaRead( void(*callback)(long,int), int maxRetries ) 0278 { 0279 if( m_paranoia ) { 0280 QMutexLocker locker( &m_mutex ); 0281 int16_t* data = cdda_paranoia_read_limited( m_paranoia, callback, maxRetries ); 0282 if( data ) 0283 m_currentSector++; 0284 return data; 0285 } 0286 else 0287 return 0; 0288 } 0289 0290 0291 long K3b::CdparanoiaLibData::firstSector( int track ) 0292 { 0293 if( m_drive ) { 0294 QMutexLocker locker( &m_mutex ); 0295 long sector = cdda_cdda_track_firstsector( m_drive, track ); 0296 return sector; 0297 } 0298 else 0299 return -1; 0300 } 0301 0302 long K3b::CdparanoiaLibData::lastSector( int track ) 0303 { 0304 if( m_drive ) { 0305 QMutexLocker locker( &m_mutex ); 0306 long sector = cdda_cdda_track_lastsector(m_drive, track ); 0307 return sector; 0308 } 0309 else 0310 return -1; 0311 } 0312 0313 0314 long K3b::CdparanoiaLibData::paranoiaSeek( long sector, int mode ) 0315 { 0316 if( m_paranoia ) { 0317 QMutexLocker locker( &m_mutex ); 0318 m_currentSector = cdda_paranoia_seek( m_paranoia, sector, mode ); 0319 return m_currentSector; 0320 } 0321 else 0322 return -1; 0323 } 0324 0325 0326 0327 class K3b::CdparanoiaLib::Private 0328 { 0329 public: 0330 Private() 0331 : device(0), 0332 currentSector(0), 0333 startSector(0), 0334 lastSector(0), 0335 status(S_OK), 0336 paranoiaLevel(0), 0337 neverSkip(true), 0338 maxRetries(5), 0339 data(0) { 0340 } 0341 0342 ~Private() { 0343 } 0344 0345 void updateParanoiaMode() { 0346 // from cdrdao 1.1.7 0347 int paranoiaMode = PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP; 0348 0349 switch( paranoiaLevel ) { 0350 case 0: 0351 paranoiaMode = PARANOIA_MODE_DISABLE; 0352 break; 0353 0354 case 1: 0355 paranoiaMode |= PARANOIA_MODE_OVERLAP; 0356 paranoiaMode &= ~PARANOIA_MODE_VERIFY; 0357 break; 0358 0359 case 2: 0360 paranoiaMode &= ~(PARANOIA_MODE_SCRATCH|PARANOIA_MODE_REPAIR); 0361 break; 0362 } 0363 0364 if( neverSkip ) 0365 paranoiaMode |= PARANOIA_MODE_NEVERSKIP; 0366 0367 data->paranoiaModeSet( paranoiaMode ); 0368 } 0369 0370 // high-level api 0371 K3b::Device::Device* device; 0372 K3b::Device::Toc toc; 0373 long currentSector; 0374 long startSector; 0375 long lastSector; 0376 int status; 0377 unsigned int currentTrack; 0378 int paranoiaLevel; 0379 bool neverSkip; 0380 int maxRetries; 0381 0382 K3b::CdparanoiaLibData* data; 0383 }; 0384 0385 0386 K3b::CdparanoiaLib::CdparanoiaLib() 0387 { 0388 d = new Private(); 0389 } 0390 0391 0392 K3b::CdparanoiaLib::~CdparanoiaLib() 0393 { 0394 delete d; 0395 } 0396 0397 0398 bool K3b::CdparanoiaLib::load() 0399 { 0400 cdda_cdda_identify = (cdrom_drive* (*) (const char*, int, char**))s_libInterface->resolve( CDDA_IDENTIFY ); 0401 cdda_cdda_open = (int (*) (cdrom_drive*))s_libInterface->resolve( CDDA_OPEN ); 0402 cdda_cdda_close = (int (*) (cdrom_drive*))s_libInterface->resolve( CDDA_CLOSE ); 0403 cdda_cdda_track_firstsector = (long (*)(cdrom_drive*, int))s_libInterface->resolve( CDDA_TRACK_FIRSTSECTOR ); 0404 cdda_cdda_track_lastsector = (long (*)(cdrom_drive*, int))s_libInterface->resolve( CDDA_TRACK_LASTSECTOR ); 0405 cdda_cdda_verbose_set = (void (*)(cdrom_drive *d,int err_action, int mes_action))s_libInterface->resolve( CDDA_VERBOSE_SET ); 0406 cdda_cdda_disc_firstsector = (long (*)(cdrom_drive *d))s_libInterface->resolve( CDDA_DISC_FIRSTSECTOR ); 0407 0408 cdda_paranoia_init = (cdrom_paranoia* (*)(cdrom_drive*))s_libParanoia->resolve( PARANOIA_INIT ); 0409 cdda_paranoia_free = (void (*)(cdrom_paranoia *p))s_libParanoia->resolve( PARANOIA_FREE ); 0410 cdda_paranoia_modeset = (void (*)(cdrom_paranoia *p, int mode))s_libParanoia->resolve( PARANOIA_MODESET ); 0411 cdda_paranoia_read_limited = (int16_t* (*)(cdrom_paranoia *p, void(*callback)(long,int), int))s_libParanoia->resolve( PARANOIA_READ_LIMITED ); 0412 cdda_paranoia_seek = (long (*)(cdrom_paranoia *p,long seek,int mode))s_libParanoia->resolve( PARANOIA_SEEK ); 0413 0414 // check if all symbols could be resoled 0415 if( cdda_cdda_identify == 0 ) { 0416 qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'cdda_identify'"; 0417 return false; 0418 } 0419 if( cdda_cdda_open == 0 ) { 0420 qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'cdda_open'"; 0421 return false; 0422 } 0423 if( cdda_cdda_close == 0 ) { 0424 qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'cdda_close'"; 0425 return false; 0426 } 0427 if( cdda_cdda_track_firstsector == 0 ) { 0428 qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'cdda_track_firstsector'"; 0429 return false; 0430 } 0431 if( cdda_cdda_track_lastsector == 0 ) { 0432 qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'cdda_track_lastsector'"; 0433 return false; 0434 } 0435 if( cdda_cdda_disc_firstsector == 0 ) { 0436 qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'cdda_disc_firstsector'"; 0437 return false; 0438 } 0439 if( cdda_cdda_verbose_set == 0 ) { 0440 qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'cdda_verbose_set'"; 0441 return false; 0442 } 0443 0444 if( cdda_paranoia_init == 0 ) { 0445 qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'paranoia_init'"; 0446 return false; 0447 } 0448 if( cdda_paranoia_free == 0 ) { 0449 qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'paranoia_free'"; 0450 return false; 0451 } 0452 if( cdda_paranoia_modeset == 0 ) { 0453 qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'paranoia_modeset'"; 0454 return false; 0455 } 0456 if( cdda_paranoia_read_limited == 0 ) { 0457 qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'paranoia_read_limited'"; 0458 return false; 0459 } 0460 if( cdda_paranoia_seek == 0 ) { 0461 qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'paranoia_seek'"; 0462 return false; 0463 } 0464 0465 return true; 0466 } 0467 0468 0469 0470 K3b::CdparanoiaLib* K3b::CdparanoiaLib::create() 0471 { 0472 // check if libcdda_interface is available 0473 if( !s_libInterface->isLoaded() ) { 0474 s_haveLibCdio = true; 0475 0476 // Windows ignores version: 0477 // https://doc.qt.io/qt-5/qlibrary.html#setFileNameAndVersion 0478 s_libInterface->setFileNameAndVersion( "cdio_cdda", 2 ); 0479 s_libInterface->setLoadHints( QLibrary::ResolveAllSymbolsHint | QLibrary::ExportExternalSymbolsHint ); 0480 #ifndef Q_OS_WIN32 0481 if( !s_libInterface->load() ) { 0482 s_libInterface->setFileNameAndVersion( "cdio_cdda", 1 ); 0483 if( !s_libInterface->load() ) { 0484 s_libInterface->setFileNameAndVersion( "cdio_cdda", 0 ); 0485 if( !s_libInterface->load() ) { 0486 s_libInterface->setFileNameAndVersion( "cdio_cdda", "" ); 0487 if( !s_libInterface->load() ) { 0488 s_haveLibCdio = false; 0489 s_libInterface->setFileNameAndVersion( "cdda_interface", 1 ); 0490 if( !s_libInterface->load() ) { 0491 s_libInterface->setFileNameAndVersion( "cdda_interface", 0 ); 0492 #endif 0493 if( !s_libInterface->load() ) { 0494 s_libInterface->setFileNameAndVersion( "cdda_interface", "" ); 0495 if( !s_libInterface->load() ) { 0496 qDebug() << "(K3b::CdparanoiaLib) Error while loading libcdda_interface."; 0497 return 0; 0498 } 0499 } 0500 #ifndef Q_OS_WIN32 0501 } 0502 } 0503 } 0504 } 0505 } 0506 #endif 0507 0508 0509 s_libParanoia->setLoadHints( QLibrary::ResolveAllSymbolsHint | QLibrary::ExportExternalSymbolsHint ); 0510 if( s_haveLibCdio ) { 0511 s_libParanoia->setFileNameAndVersion( "cdio_paranoia", 2 ); 0512 #ifndef Q_OS_WIN32 0513 if( !s_libParanoia->load() ) { 0514 s_libParanoia->setFileNameAndVersion( "cdio_paranoia", 1 ); 0515 if( !s_libParanoia->load() ) { 0516 s_libParanoia->setFileNameAndVersion( "cdio_paranoia", 0 ); 0517 if( !s_libParanoia->load() ) { 0518 s_libParanoia->setFileNameAndVersion( "cdio_paranoia", "" ); 0519 #endif 0520 s_libParanoia->load(); 0521 #ifndef Q_OS_WIN32 0522 } 0523 } 0524 } 0525 #endif 0526 } 0527 0528 if( !s_libParanoia->isLoaded() ) { 0529 s_libParanoia->setFileNameAndVersion( "cdda_paranoia", 1 ); 0530 #ifndef Q_OS_WIN32 0531 if( !s_libParanoia->load() ) { 0532 s_libParanoia->setFileNameAndVersion( "cdda_paranoia", 0 ); 0533 if( !s_libParanoia->load() ) { 0534 s_libParanoia->setFileNameAndVersion( "cdda_paranoia", "" ); 0535 #endif 0536 if( !s_libParanoia->load() ) { 0537 qDebug() << "(K3b::CdparanoiaLib) Error while loading libcdda_paranoia."; 0538 s_libInterface->unload(); 0539 return 0; 0540 } 0541 #ifndef Q_OS_WIN32 0542 } 0543 } 0544 #endif 0545 } 0546 } 0547 0548 K3b::CdparanoiaLib* lib = new K3b::CdparanoiaLib(); 0549 if( !lib->load() ) { 0550 qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve all symbols!"; 0551 s_libInterface->unload(); 0552 s_libParanoia->unload(); 0553 delete lib; 0554 return 0; 0555 } 0556 return lib; 0557 } 0558 0559 0560 bool K3b::CdparanoiaLib::initParanoia( K3b::Device::Device* dev, const K3b::Device::Toc& toc ) 0561 { 0562 if( !dev ) { 0563 qCritical() << "(K3b::CdparanoiaLib::initParanoia) dev = 0!" << Qt::endl; 0564 return false; 0565 } 0566 0567 close(); 0568 0569 d->device = dev; 0570 d->toc = toc; 0571 if( d->toc.isEmpty() ) { 0572 qDebug() << "(K3b::CdparanoiaLib) empty toc."; 0573 cleanup(); 0574 return false; 0575 } 0576 0577 if( d->toc.contentType() == K3b::Device::DATA ) { 0578 qDebug() << "(K3b::CdparanoiaLib) No audio tracks found."; 0579 cleanup(); 0580 return false; 0581 } 0582 0583 // 0584 // Get the appropriate data instance for this device 0585 // 0586 d->data = K3b::CdparanoiaLibData::data( dev ); 0587 0588 if( d->data->paranoiaInit() ) { 0589 d->startSector = d->currentSector = d->lastSector = 0; 0590 0591 return true; 0592 } 0593 else { 0594 cleanup(); 0595 return false; 0596 } 0597 } 0598 0599 0600 bool K3b::CdparanoiaLib::initParanoia( K3b::Device::Device* dev ) 0601 { 0602 return initParanoia( dev, dev->readToc() ); 0603 } 0604 0605 0606 void K3b::CdparanoiaLib::close() 0607 { 0608 cleanup(); 0609 } 0610 0611 0612 void K3b::CdparanoiaLib::cleanup() 0613 { 0614 if( d->data ) 0615 d->data->paranoiaFree(); 0616 d->device = 0; 0617 d->currentSector = 0; 0618 } 0619 0620 0621 bool K3b::CdparanoiaLib::initReading() 0622 { 0623 if( d->device ) { 0624 // find first audio track 0625 K3b::Device::Toc::const_iterator trackIt = d->toc.constBegin(); 0626 while( (*trackIt).type() != K3b::Device::Track::TYPE_AUDIO ) { 0627 ++trackIt; 0628 } 0629 0630 long start = (*trackIt).firstSector().lba(); 0631 0632 // find last audio track 0633 while( trackIt != d->toc.constEnd() && (*trackIt).type() == K3b::Device::Track::TYPE_AUDIO ) 0634 ++trackIt; 0635 --trackIt; 0636 0637 long end = (*trackIt).lastSector().lba(); 0638 0639 return initReading( start, end ); 0640 } 0641 else { 0642 qDebug() << "(K3b::CdparanoiaLib) initReading without initParanoia."; 0643 return false; 0644 } 0645 } 0646 0647 0648 bool K3b::CdparanoiaLib::initReading( int track ) 0649 { 0650 if( d->device ) { 0651 if( track <= d->toc.count() ) { 0652 const K3b::Device::Track& k3bTrack = d->toc[track-1]; 0653 if( k3bTrack.type() == K3b::Device::Track::TYPE_AUDIO ) { 0654 return initReading( k3bTrack.firstSector().lba(), k3bTrack.lastSector().lba() ); 0655 } 0656 else { 0657 qDebug() << "(K3b::CdparanoiaLib) Track " << track << " no audio track."; 0658 return false; 0659 } 0660 } 0661 else { 0662 qDebug() << "(K3b::CdparanoiaLib) Track " << track << " too high."; 0663 return false; 0664 } 0665 } 0666 else { 0667 qDebug() << "(K3b::CdparanoiaLib) initReading without initParanoia."; 0668 return false; 0669 } 0670 } 0671 0672 0673 bool K3b::CdparanoiaLib::initReading( long start, long end ) 0674 { 0675 qDebug() << "(K3b::CdparanoiaLib) initReading( " << start << ", " << end << " )"; 0676 0677 if( d->device ) { 0678 if( d->toc.firstSector().lba() <= start && 0679 d->toc.lastSector().lba() >= end ) { 0680 d->startSector = d->currentSector = start; 0681 d->lastSector = end; 0682 0683 // determine track number 0684 d->currentTrack = 1; 0685 while( d->toc[d->currentTrack-1].lastSector() < start ) 0686 d->currentTrack++; 0687 0688 // let the paranoia stuff point to the startSector 0689 d->data->paranoiaSeek( start, SEEK_SET ); 0690 return true; 0691 } 0692 else { 0693 qDebug() << "(K3b::CdparanoiaLib) " << start << " and " << end << " out of range."; 0694 return false; 0695 } 0696 } 0697 else { 0698 qDebug() << "(K3b::CdparanoiaLib) initReading without initParanoia."; 0699 return false; 0700 } 0701 } 0702 0703 0704 char* K3b::CdparanoiaLib::read( int* statusCode, unsigned int* track, bool littleEndian ) 0705 { 0706 if( d->currentSector > d->lastSector ) { 0707 qDebug() << "(K3b::CdparanoiaLib) finished ripping. read " 0708 << (d->currentSector - d->startSector) << " sectors." << Qt::endl 0709 << " current sector: " << d->currentSector << Qt::endl; 0710 d->status = S_OK; 0711 if( statusCode ) 0712 *statusCode = d->status; 0713 return 0; 0714 } 0715 0716 if( d->currentSector != d->data->sector() ) { 0717 qDebug() << "(K3b::CdparanoiaLib) need to seek before read. Looks as if we are reusing the paranoia instance."; 0718 if( d->data->paranoiaSeek( d->currentSector, SEEK_SET ) == -1 ) 0719 return 0; 0720 } 0721 0722 // 0723 // The paranoia data could have been used by someone else before 0724 // and setting the paranoia mode is fast 0725 // 0726 d->updateParanoiaMode(); 0727 0728 qint16* data = d->data->paranoiaRead( paranoiaCallback, d->maxRetries ); 0729 0730 char* charData = reinterpret_cast<char*>(data); 0731 0732 if( 0733 #ifndef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN 0734 ! 0735 #endif 0736 littleEndian ) { 0737 for( int i = 0; i < CD_FRAMESIZE_RAW-1; i+=2 ) { 0738 char b = charData[i]; 0739 charData[i] = charData[i+1]; 0740 charData[i+1] = b; 0741 } 0742 } 0743 0744 0745 if( data ) 0746 d->status = S_OK; 0747 else 0748 d->status = S_ERROR; // We may skip this sector if we'd like... 0749 0750 if( statusCode ) 0751 *statusCode = d->status; 0752 0753 if( track ) 0754 *track = d->currentTrack; 0755 0756 d->currentSector++; 0757 0758 if( d->toc[d->currentTrack-1].lastSector() < d->currentSector ) 0759 d->currentTrack++; 0760 0761 return charData; 0762 } 0763 0764 0765 int K3b::CdparanoiaLib::status() const 0766 { 0767 return d->status; 0768 } 0769 0770 0771 const K3b::Device::Toc& K3b::CdparanoiaLib::toc() const 0772 { 0773 return d->toc; 0774 } 0775 0776 0777 long K3b::CdparanoiaLib::rippedDataLength() const 0778 { 0779 return d->lastSector - d->startSector + 1; 0780 } 0781 0782 0783 void K3b::CdparanoiaLib::setParanoiaMode( int m ) 0784 { 0785 d->paranoiaLevel = m; 0786 } 0787 0788 0789 void K3b::CdparanoiaLib::setNeverSkip( bool b ) 0790 { 0791 d->neverSkip = b; 0792 } 0793 0794 0795 void K3b::CdparanoiaLib::setMaxRetries( int r ) 0796 { 0797 d->maxRetries = r; 0798 }