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