File indexing completed on 2024-06-16 07:42:24

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 }