1 /*
2     SPDX-FileCopyrightText: 2010 Michal Malek <michalm@jabster.pl>
3     SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org>
4 
5     SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 
8 #include <config-k3b.h>
9 
10 #include "k3bcdparanoialib.h"
11 
12 #include "k3bdevice.h"
13 #include "k3btoc.h"
14 #include "k3bmsf.h"
15 
16 #include <QDebug>
17 #include <QFile>
18 #include <QGlobalStatic>
19 #include <QLibrary>
20 #include <QMutex>
21 #include <QMutexLocker>
22 
23 #ifdef Q_OS_WIN32
24 typedef short int int16_t;
25 #endif
26 
27 static bool s_haveLibCdio = false;
28 
29 
30 
31 #define CDDA_IDENTIFY          s_haveLibCdio ? "cdio_cddap_identify" : "cdda_identify"
32 #define CDDA_CLOSE             s_haveLibCdio ? "cdio_cddap_close" : "cdda_close"
33 #define CDDA_OPEN              s_haveLibCdio ? "cdio_cddap_open" : "cdda_open"
34 #define CDDA_TRACK_FIRSTSECTOR s_haveLibCdio ? "cdio_cddap_track_firstsector" : "cdda_track_firstsector"
35 #define CDDA_TRACK_LASTSECTOR  s_haveLibCdio ? "cdio_cddap_track_lastsector" : "cdda_track_lastsector"
36 #define CDDA_VERBOSE_SET       s_haveLibCdio ? "cdio_cddap_verbose_set" : "cdda_verbose_set"
37 #define CDDA_DISC_FIRSTSECTOR  s_haveLibCdio ? "cdio_cddap_disc_firstsector" : "cdda_disc_firstsector"
38 
39 #define PARANOIA_INIT          s_haveLibCdio ? "cdio_paranoia_init" : "paranoia_init"
40 #define PARANOIA_FREE          s_haveLibCdio ? "cdio_paranoia_free" : "paranoia_free"
41 #define PARANOIA_MODESET       s_haveLibCdio ? "cdio_paranoia_modeset" : "paranoia_modeset"
42 #define PARANOIA_SEEK          s_haveLibCdio ? "cdio_paranoia_seek" : "paranoia_seek"
43 #define PARANOIA_READ_LIMITED  s_haveLibCdio ? "cdio_paranoia_read_limited" : "paranoia_read_limited"
44 
45 
46 // from cdda_paranoia.h
47 #define PARANOIA_CB_READ           0
48 #define PARANOIA_CB_VERIFY         1
49 #define PARANOIA_CB_FIXUP_EDGE     2
50 #define PARANOIA_CB_FIXUP_ATOM     3
51 #define PARANOIA_CB_SCRATCH        4
52 #define PARANOIA_CB_REPAIR         5
53 #define PARANOIA_CB_SKIP           6
54 #define PARANOIA_CB_DRIFT          7
55 #define PARANOIA_CB_BACKOFF        8
56 #define PARANOIA_CB_OVERLAP        9
57 #define PARANOIA_CB_FIXUP_DROPPED 10
58 #define PARANOIA_CB_FIXUP_DUPED   11
59 #define PARANOIA_CB_READERR       12
60 
61 
Q_GLOBAL_STATIC(QLibrary,s_libInterface)62 Q_GLOBAL_STATIC(QLibrary, s_libInterface)
63 Q_GLOBAL_STATIC(QLibrary, s_libParanoia)
64 
65 
66 
67 static void paranoiaCallback( long, int status )
68 {
69     // do nothing so far....
70     return;
71 
72     switch( status ) {
73     case -1:
74         break;
75     case -2:
76         break;
77     case PARANOIA_CB_READ:
78         // no problem
79         // does only this mean that the sector has been read?
80 //     m_lastReadSector = sector;  // this seems to be rather useless
81 //     m_readSectors++;
82         break;
83     case PARANOIA_CB_VERIFY:
84         break;
85     case PARANOIA_CB_FIXUP_EDGE:
86         break;
87     case PARANOIA_CB_FIXUP_ATOM:
88         break;
89     case PARANOIA_CB_SCRATCH:
90         // scratch detected
91         break;
92     case PARANOIA_CB_REPAIR:
93         break;
94     case PARANOIA_CB_SKIP:
95         // skipped sector
96         break;
97     case PARANOIA_CB_DRIFT:
98         break;
99     case PARANOIA_CB_BACKOFF:
100         break;
101     case PARANOIA_CB_OVERLAP:
102         // sector does not seem to contain the current
103         // sector but the amount of overlapped data
104         //    m_overlap = sector;
105         break;
106     case PARANOIA_CB_FIXUP_DROPPED:
107         break;
108     case PARANOIA_CB_FIXUP_DUPED:
109         break;
110     case PARANOIA_CB_READERR:
111         break;
112     }
113 }
114 
115 
116 
117 extern "C" {
118     struct cdrom_drive;
119     struct cdrom_paranoia;
120 
121     // HINT: these pointers must NOT have the same name like the actual methods!
122     //       I added "cdda_" as prefix
123     //       Before doing that K3b crashed in cdda_open!
124     //       Can anyone please explain that to me?
125 
126     // cdda_interface
127     cdrom_drive* (*cdda_cdda_identify)(const char*, int, char**);
128     int (*cdda_cdda_open)(cdrom_drive *d);
129     int (*cdda_cdda_close)(cdrom_drive *d);
130     long (*cdda_cdda_track_firstsector)( cdrom_drive*, int );
131     long (*cdda_cdda_track_lastsector)( cdrom_drive*, int );
132     long (*cdda_cdda_disc_firstsector)(cdrom_drive *d);
133     void (*cdda_cdda_verbose_set)(cdrom_drive *d,int err_action, int mes_action);
134 
135     // cdda_paranoia
136     cdrom_paranoia* (*cdda_paranoia_init)(cdrom_drive*);
137     void (*cdda_paranoia_free)(cdrom_paranoia *p);
138     void (*cdda_paranoia_modeset)(cdrom_paranoia *p, int mode);
139     int16_t* (*cdda_paranoia_read_limited)(cdrom_paranoia *p, void(*callback)(long,int), int);
140     long (*cdda_paranoia_seek)(cdrom_paranoia *p,long seek,int mode);
141 }
142 
143 // from cdda_paranoia.h
144 #define PARANOIA_MODE_FULL        0xff
145 #define PARANOIA_MODE_DISABLE     0
146 
147 #define PARANOIA_MODE_VERIFY      1
148 #define PARANOIA_MODE_FRAGMENT    2
149 #define PARANOIA_MODE_OVERLAP     4
150 #define PARANOIA_MODE_SCRATCH     8
151 #define PARANOIA_MODE_REPAIR      16
152 #define PARANOIA_MODE_NEVERSKIP   32
153 
154 
155 
156 namespace K3b {
157     /**
158      * Internal class used by CdparanoiaLib
159      */
160     class CdparanoiaLibData
161     {
162     public:
~CdparanoiaLibData()163         ~CdparanoiaLibData()
164         {
165             paranoiaFree();
166         }
167 
device() const168         Device::Device* device() const { return m_device; }
169         void paranoiaModeSet( int );
170         bool paranoiaInit();
171         void paranoiaFree();
172         int16_t* paranoiaRead( void(*callback)(long,int), int maxRetries );
173         long paranoiaSeek( long, int );
174         long firstSector( int );
175         long lastSector( int );
sector() const176         long sector() const { return m_currentSector; }
177 
data(Device::Device * dev)178         static CdparanoiaLibData* data( Device::Device* dev )
179         {
180             QMap<Device::Device*, CdparanoiaLibData*>::const_iterator it = s_dataMap.constFind( dev );
181             if( it == s_dataMap.constEnd() ) {
182                 CdparanoiaLibData* data = new CdparanoiaLibData( dev );
183                 s_dataMap.insert( dev, data );
184                 return data;
185             }
186             else
187                 return *it;
188         }
189 
freeAll()190         static void freeAll()
191         {
192             // clean up all CdparanoiaLibData instances
193             qDeleteAll( s_dataMap );
194             s_dataMap.clear();
195         }
196 
197     private:
CdparanoiaLibData(Device::Device * dev)198         CdparanoiaLibData( Device::Device* dev )
199             : m_device(dev),
200               m_drive(0),
201               m_paranoia(0),
202               m_currentSector(0)
203         {
204         }
205 
206         //
207         // We have exactly one instance of CdparanoiaLibData per device
208         //
209         static QMap<Device::Device*, CdparanoiaLibData*> s_dataMap;
210 
211         Device::Device* m_device;
212 
213         cdrom_drive* m_drive;
214         cdrom_paranoia* m_paranoia;
215 
216         long m_currentSector;
217 
218         QMutex m_mutex;
219     };
220 }
221 
222 QMap<K3b::Device::Device*, K3b::CdparanoiaLibData*> K3b::CdparanoiaLibData::s_dataMap;
223 
paranoiaInit()224 bool K3b::CdparanoiaLibData::paranoiaInit()
225 {
226     if( m_drive )
227         paranoiaFree();
228 
229     QMutexLocker locker( &m_mutex );
230 
231     // since we use cdparanoia to open the device it is important to close
232     // the device here
233     m_device->close();
234 
235     m_drive = cdda_cdda_identify( QFile::encodeName(m_device->blockDeviceName()), 0, 0 );
236     if( m_drive == 0 ) {
237         return false;
238     }
239 
240     //  cdda_cdda_verbose_set( m_drive, 1, 1 );
241 
242     cdda_cdda_open( m_drive );
243     m_paranoia = cdda_paranoia_init( m_drive );
244     if( m_paranoia == 0 ) {
245         paranoiaFree();
246         return false;
247     }
248 
249     m_currentSector = 0;
250 
251     return true;
252 }
253 
254 
paranoiaFree()255 void K3b::CdparanoiaLibData::paranoiaFree()
256 {
257     QMutexLocker locker( &m_mutex );
258 
259     if( m_paranoia ) {
260         cdda_paranoia_free( m_paranoia );
261         m_paranoia = 0;
262     }
263     if( m_drive ) {
264         cdda_cdda_close( m_drive );
265         m_drive = 0;
266     }
267 }
268 
269 
paranoiaModeSet(int mode)270 void K3b::CdparanoiaLibData::paranoiaModeSet( int mode )
271 {
272     QMutexLocker locker( &m_mutex );
273     cdda_paranoia_modeset( m_paranoia, mode );
274 }
275 
276 
paranoiaRead(void (* callback)(long,int),int maxRetries)277 int16_t* K3b::CdparanoiaLibData::paranoiaRead( void(*callback)(long,int), int maxRetries )
278 {
279     if( m_paranoia ) {
280         QMutexLocker locker( &m_mutex );
281         int16_t* data = cdda_paranoia_read_limited( m_paranoia, callback, maxRetries );
282         if( data )
283             m_currentSector++;
284         return data;
285     }
286     else
287         return 0;
288 }
289 
290 
firstSector(int track)291 long K3b::CdparanoiaLibData::firstSector( int track )
292 {
293     if( m_drive ) {
294         QMutexLocker locker( &m_mutex );
295         long sector = cdda_cdda_track_firstsector( m_drive, track );
296         return sector;
297     }
298     else
299         return -1;
300 }
301 
lastSector(int track)302 long K3b::CdparanoiaLibData::lastSector( int track )
303 {
304     if( m_drive ) {
305         QMutexLocker locker( &m_mutex );
306         long sector = cdda_cdda_track_lastsector(m_drive, track );
307         return sector;
308     }
309     else
310         return -1;
311 }
312 
313 
paranoiaSeek(long sector,int mode)314 long K3b::CdparanoiaLibData::paranoiaSeek( long sector, int mode )
315 {
316     if( m_paranoia ) {
317         QMutexLocker locker( &m_mutex );
318         m_currentSector = cdda_paranoia_seek( m_paranoia, sector, mode );
319         return m_currentSector;
320     }
321     else
322         return -1;
323 }
324 
325 
326 
327 class K3b::CdparanoiaLib::Private
328 {
329 public:
Private()330     Private()
331         : device(0),
332           currentSector(0),
333           startSector(0),
334           lastSector(0),
335           status(S_OK),
336           paranoiaLevel(0),
337           neverSkip(true),
338           maxRetries(5),
339           data(0) {
340     }
341 
~Private()342     ~Private() {
343     }
344 
updateParanoiaMode()345     void updateParanoiaMode() {
346         // from cdrdao 1.1.7
347         int paranoiaMode = PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP;
348 
349         switch( paranoiaLevel ) {
350         case 0:
351             paranoiaMode = PARANOIA_MODE_DISABLE;
352             break;
353 
354         case 1:
355             paranoiaMode |= PARANOIA_MODE_OVERLAP;
356             paranoiaMode &= ~PARANOIA_MODE_VERIFY;
357             break;
358 
359         case 2:
360             paranoiaMode &= ~(PARANOIA_MODE_SCRATCH|PARANOIA_MODE_REPAIR);
361             break;
362         }
363 
364         if( neverSkip )
365             paranoiaMode |= PARANOIA_MODE_NEVERSKIP;
366 
367         data->paranoiaModeSet( paranoiaMode );
368     }
369 
370     // high-level api
371     K3b::Device::Device* device;
372     K3b::Device::Toc toc;
373     long currentSector;
374     long startSector;
375     long lastSector;
376     int status;
377     unsigned int currentTrack;
378     int paranoiaLevel;
379     bool neverSkip;
380     int maxRetries;
381 
382     K3b::CdparanoiaLibData* data;
383 };
384 
385 
CdparanoiaLib()386 K3b::CdparanoiaLib::CdparanoiaLib()
387 {
388     d = new Private();
389 }
390 
391 
~CdparanoiaLib()392 K3b::CdparanoiaLib::~CdparanoiaLib()
393 {
394     delete d;
395 }
396 
397 
load()398 bool K3b::CdparanoiaLib::load()
399 {
400     cdda_cdda_identify = (cdrom_drive* (*) (const char*, int, char**))s_libInterface->resolve( CDDA_IDENTIFY );
401     cdda_cdda_open = (int (*) (cdrom_drive*))s_libInterface->resolve( CDDA_OPEN );
402     cdda_cdda_close = (int (*) (cdrom_drive*))s_libInterface->resolve( CDDA_CLOSE );
403     cdda_cdda_track_firstsector = (long (*)(cdrom_drive*, int))s_libInterface->resolve( CDDA_TRACK_FIRSTSECTOR );
404     cdda_cdda_track_lastsector = (long (*)(cdrom_drive*, int))s_libInterface->resolve( CDDA_TRACK_LASTSECTOR );
405     cdda_cdda_verbose_set = (void (*)(cdrom_drive *d,int err_action, int mes_action))s_libInterface->resolve( CDDA_VERBOSE_SET );
406     cdda_cdda_disc_firstsector = (long (*)(cdrom_drive *d))s_libInterface->resolve( CDDA_DISC_FIRSTSECTOR );
407 
408     cdda_paranoia_init = (cdrom_paranoia* (*)(cdrom_drive*))s_libParanoia->resolve( PARANOIA_INIT );
409     cdda_paranoia_free = (void (*)(cdrom_paranoia *p))s_libParanoia->resolve( PARANOIA_FREE );
410     cdda_paranoia_modeset = (void (*)(cdrom_paranoia *p, int mode))s_libParanoia->resolve( PARANOIA_MODESET );
411     cdda_paranoia_read_limited = (int16_t* (*)(cdrom_paranoia *p, void(*callback)(long,int), int))s_libParanoia->resolve( PARANOIA_READ_LIMITED );
412     cdda_paranoia_seek = (long (*)(cdrom_paranoia *p,long seek,int mode))s_libParanoia->resolve( PARANOIA_SEEK );
413 
414     // check if all symbols could be resoled
415     if( cdda_cdda_identify == 0 ) {
416         qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'cdda_identify'";
417         return false;
418     }
419     if( cdda_cdda_open == 0 ) {
420         qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'cdda_open'";
421         return false;
422     }
423     if( cdda_cdda_close == 0 ) {
424         qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'cdda_close'";
425         return false;
426     }
427     if( cdda_cdda_track_firstsector == 0 ) {
428         qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'cdda_track_firstsector'";
429         return false;
430     }
431     if( cdda_cdda_track_lastsector == 0 ) {
432         qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'cdda_track_lastsector'";
433         return false;
434     }
435     if( cdda_cdda_disc_firstsector == 0 ) {
436         qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'cdda_disc_firstsector'";
437         return false;
438     }
439     if( cdda_cdda_verbose_set == 0 ) {
440         qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'cdda_verbose_set'";
441         return false;
442     }
443 
444     if( cdda_paranoia_init == 0 ) {
445         qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'paranoia_init'";
446         return false;
447     }
448     if( cdda_paranoia_free == 0 ) {
449         qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'paranoia_free'";
450         return false;
451     }
452     if( cdda_paranoia_modeset == 0 ) {
453         qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'paranoia_modeset'";
454         return false;
455     }
456     if( cdda_paranoia_read_limited == 0 ) {
457         qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'paranoia_read_limited'";
458         return false;
459     }
460     if( cdda_paranoia_seek == 0 ) {
461         qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve 'paranoia_seek'";
462         return false;
463     }
464 
465     return true;
466 }
467 
468 
469 
create()470 K3b::CdparanoiaLib* K3b::CdparanoiaLib::create()
471 {
472     // check if libcdda_interface is available
473     if( !s_libInterface->isLoaded() ) {
474         s_haveLibCdio = true;
475 
476         // Windows ignores version:
477         // https://doc.qt.io/qt-5/qlibrary.html#setFileNameAndVersion
478         s_libInterface->setFileNameAndVersion( "cdio_cdda", 2 );
479         s_libInterface->setLoadHints( QLibrary::ResolveAllSymbolsHint | QLibrary::ExportExternalSymbolsHint );
480 #ifndef Q_OS_WIN32
481         if( !s_libInterface->load() ) {
482             s_libInterface->setFileNameAndVersion( "cdio_cdda", 1 );
483             if( !s_libInterface->load() ) {
484                 s_libInterface->setFileNameAndVersion( "cdio_cdda", 0 );
485                 if( !s_libInterface->load() ) {
486                     s_libInterface->setFileNameAndVersion( "cdio_cdda", "" );
487                     if( !s_libInterface->load() ) {
488                         s_haveLibCdio = false;
489                         s_libInterface->setFileNameAndVersion( "cdda_interface", 1 );
490                         if( !s_libInterface->load() ) {
491                             s_libInterface->setFileNameAndVersion( "cdda_interface", 0 );
492 #endif
493                             if( !s_libInterface->load() ) {
494                                 s_libInterface->setFileNameAndVersion( "cdda_interface", "" );
495                                 if( !s_libInterface->load() ) {
496                                     qDebug() << "(K3b::CdparanoiaLib) Error while loading libcdda_interface.";
497                                     return 0;
498                                 }
499                             }
500 #ifndef Q_OS_WIN32
501                         }
502                     }
503                 }
504             }
505         }
506 #endif
507 
508 
509 	s_libParanoia->setLoadHints( QLibrary::ResolveAllSymbolsHint | QLibrary::ExportExternalSymbolsHint );
510         if( s_haveLibCdio ) {
511             s_libParanoia->setFileNameAndVersion( "cdio_paranoia", 2 );
512 #ifndef Q_OS_WIN32
513             if( !s_libParanoia->load() ) {
514                 s_libParanoia->setFileNameAndVersion( "cdio_paranoia", 1 );
515                 if( !s_libParanoia->load() ) {
516                     s_libParanoia->setFileNameAndVersion( "cdio_paranoia", 0 );
517                     if( !s_libParanoia->load() ) {
518                         s_libParanoia->setFileNameAndVersion( "cdio_paranoia", "" );
519 #endif
520                         s_libParanoia->load();
521 #ifndef Q_OS_WIN32
522                     }
523                 }
524             }
525 #endif
526         }
527 
528         if( !s_libParanoia->isLoaded() ) {
529             s_libParanoia->setFileNameAndVersion( "cdda_paranoia", 1 );
530 #ifndef Q_OS_WIN32
531             if( !s_libParanoia->load() ) {
532                 s_libParanoia->setFileNameAndVersion( "cdda_paranoia", 0 );
533                 if( !s_libParanoia->load() ) {
534                     s_libParanoia->setFileNameAndVersion( "cdda_paranoia", "" );
535 #endif
536                     if( !s_libParanoia->load() ) {
537                         qDebug() << "(K3b::CdparanoiaLib) Error while loading libcdda_paranoia.";
538                         s_libInterface->unload();
539                         return 0;
540                     }
541 #ifndef Q_OS_WIN32
542                 }
543             }
544 #endif
545         }
546     }
547 
548     K3b::CdparanoiaLib* lib = new K3b::CdparanoiaLib();
549     if( !lib->load() ) {
550         qDebug() << "(K3b::CdparanoiaLib) Error: could not resolve all symbols!";
551         s_libInterface->unload();
552         s_libParanoia->unload();
553         delete lib;
554         return 0;
555     }
556     return lib;
557 }
558 
559 
initParanoia(K3b::Device::Device * dev,const K3b::Device::Toc & toc)560 bool K3b::CdparanoiaLib::initParanoia( K3b::Device::Device* dev, const K3b::Device::Toc& toc )
561 {
562     if( !dev ) {
563         qCritical() << "(K3b::CdparanoiaLib::initParanoia) dev = 0!" << endl;
564         return false;
565     }
566 
567     close();
568 
569     d->device = dev;
570     d->toc = toc;
571     if( d->toc.isEmpty() ) {
572         qDebug() << "(K3b::CdparanoiaLib) empty toc.";
573         cleanup();
574         return false;
575     }
576 
577     if( d->toc.contentType() == K3b::Device::DATA ) {
578         qDebug() << "(K3b::CdparanoiaLib) No audio tracks found.";
579         cleanup();
580         return false;
581     }
582 
583     //
584     // Get the appropriate data instance for this device
585     //
586     d->data = K3b::CdparanoiaLibData::data( dev );
587 
588     if( d->data->paranoiaInit() ) {
589         d->startSector = d->currentSector = d->lastSector = 0;
590 
591         return true;
592     }
593     else {
594         cleanup();
595         return false;
596     }
597 }
598 
599 
initParanoia(K3b::Device::Device * dev)600 bool K3b::CdparanoiaLib::initParanoia( K3b::Device::Device* dev )
601 {
602     return initParanoia( dev, dev->readToc() );
603 }
604 
605 
close()606 void K3b::CdparanoiaLib::close()
607 {
608     cleanup();
609 }
610 
611 
cleanup()612 void K3b::CdparanoiaLib::cleanup()
613 {
614     if( d->data )
615         d->data->paranoiaFree();
616     d->device = 0;
617     d->currentSector = 0;
618 }
619 
620 
initReading()621 bool K3b::CdparanoiaLib::initReading()
622 {
623     if( d->device ) {
624         // find first audio track
625         K3b::Device::Toc::const_iterator trackIt = d->toc.constBegin();
626         while( (*trackIt).type() != K3b::Device::Track::TYPE_AUDIO ) {
627             ++trackIt;
628         }
629 
630         long start = (*trackIt).firstSector().lba();
631 
632         // find last audio track
633         while( trackIt != d->toc.constEnd() && (*trackIt).type() == K3b::Device::Track::TYPE_AUDIO )
634             ++trackIt;
635         --trackIt;
636 
637         long end = (*trackIt).lastSector().lba();
638 
639         return initReading( start, end );
640     }
641     else {
642         qDebug() << "(K3b::CdparanoiaLib) initReading without initParanoia.";
643         return false;
644     }
645 }
646 
647 
initReading(int track)648 bool K3b::CdparanoiaLib::initReading( int track )
649 {
650     if( d->device ) {
651         if( track <= d->toc.count() ) {
652             const K3b::Device::Track& k3bTrack = d->toc[track-1];
653             if( k3bTrack.type() == K3b::Device::Track::TYPE_AUDIO ) {
654                 return initReading( k3bTrack.firstSector().lba(), k3bTrack.lastSector().lba() );
655             }
656             else {
657                 qDebug() << "(K3b::CdparanoiaLib) Track " << track << " no audio track.";
658                 return false;
659             }
660         }
661         else {
662             qDebug() << "(K3b::CdparanoiaLib) Track " << track << " too high.";
663             return false;
664         }
665     }
666     else {
667         qDebug() << "(K3b::CdparanoiaLib) initReading without initParanoia.";
668         return false;
669     }
670 }
671 
672 
initReading(long start,long end)673 bool K3b::CdparanoiaLib::initReading( long start, long end )
674 {
675     qDebug() << "(K3b::CdparanoiaLib) initReading( " << start << ", " << end << " )";
676 
677     if( d->device ) {
678         if( d->toc.firstSector().lba() <= start &&
679             d->toc.lastSector().lba() >= end ) {
680             d->startSector = d->currentSector = start;
681             d->lastSector = end;
682 
683             // determine track number
684             d->currentTrack = 1;
685             while( d->toc[d->currentTrack-1].lastSector() < start )
686                 d->currentTrack++;
687 
688             // let the paranoia stuff point to the startSector
689             d->data->paranoiaSeek( start, SEEK_SET );
690             return true;
691         }
692         else {
693             qDebug() << "(K3b::CdparanoiaLib) " << start << " and " << end << " out of range.";
694             return false;
695         }
696     }
697     else {
698         qDebug() << "(K3b::CdparanoiaLib) initReading without initParanoia.";
699         return false;
700     }
701 }
702 
703 
read(int * statusCode,unsigned int * track,bool littleEndian)704 char* K3b::CdparanoiaLib::read( int* statusCode, unsigned int* track, bool littleEndian )
705 {
706     if( d->currentSector > d->lastSector ) {
707         qDebug() << "(K3b::CdparanoiaLib) finished ripping. read "
708                  << (d->currentSector - d->startSector) << " sectors." << endl
709                  << "                   current sector: " << d->currentSector << endl;
710         d->status = S_OK;
711         if( statusCode )
712             *statusCode = d->status;
713         return 0;
714     }
715 
716     if( d->currentSector != d->data->sector() ) {
717         qDebug() << "(K3b::CdparanoiaLib) need to seek before read. Looks as if we are reusing the paranoia instance.";
718         if( d->data->paranoiaSeek( d->currentSector, SEEK_SET ) == -1 )
719             return 0;
720     }
721 
722     //
723     // The paranoia data could have been used by someone else before
724     // and setting the paranoia mode is fast
725     //
726     d->updateParanoiaMode();
727 
728     qint16* data = d->data->paranoiaRead( paranoiaCallback, d->maxRetries );
729 
730     char* charData = reinterpret_cast<char*>(data);
731 
732     if(
733 #ifndef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN
734         !
735 #endif
736         littleEndian ) {
737         for( int i = 0; i < CD_FRAMESIZE_RAW-1; i+=2 ) {
738             char b = charData[i];
739             charData[i] = charData[i+1];
740             charData[i+1] = b;
741         }
742     }
743 
744 
745     if( data )
746         d->status = S_OK;
747     else
748         d->status = S_ERROR; // We may skip this sector if we'd like...
749 
750     if( statusCode )
751         *statusCode = d->status;
752 
753     if( track )
754         *track = d->currentTrack;
755 
756     d->currentSector++;
757 
758     if( d->toc[d->currentTrack-1].lastSector() < d->currentSector )
759         d->currentTrack++;
760 
761     return charData;
762 }
763 
764 
status() const765 int K3b::CdparanoiaLib::status() const
766 {
767     return d->status;
768 }
769 
770 
toc() const771 const K3b::Device::Toc& K3b::CdparanoiaLib::toc() const
772 {
773     return d->toc;
774 }
775 
776 
rippedDataLength() const777 long K3b::CdparanoiaLib::rippedDataLength() const
778 {
779     return d->lastSector - d->startSector + 1;
780 }
781 
782 
setParanoiaMode(int m)783 void K3b::CdparanoiaLib::setParanoiaMode( int m )
784 {
785     d->paranoiaLevel = m;
786 }
787 
788 
setNeverSkip(bool b)789 void K3b::CdparanoiaLib::setNeverSkip( bool b )
790 {
791     d->neverSkip = b;
792 }
793 
794 
setMaxRetries(int r)795 void K3b::CdparanoiaLib::setMaxRetries( int r )
796 {
797     d->maxRetries = r;
798 }
799