[paranoia-dev] Paranoia IV

Mikko Nummelin mnummeli at cc.hut.fi
Sat Apr 12 15:33:33 PDT 2003



On Sat, 12 Apr 2003, Laurent Pinchart wrote:

> Hi everybody,
>
> I'm currently trying to extract audio tracks from a protected audio disc.
>
> The disc contains a corrupted TOC, and some sectors contain errors.
>
> The TOC can be read properly by my Hitachi DVD drive, but not by my Plextor
> CD-RW driver. I modified CD Paranoia III 9.8 to get the TOC correctly on the
> CD-RW drive (using the READ TOC command, format Full TOC), and this works
> fine.
>
> I'm now trying to fix the erroneous sectors problem. The CD can be played on
> an audio CD player, so the data are not corrupted. I suspect the CIRC and/or
> Q sub-channel data to be corrupted, so that a 'smart' CD drive will fail to
> read the data.
>
> I'm thinking about setting the TB (Transfer Block) byte in the Error Recovery
> Parameters page to 1, so that the data will be transfered to the host even
> when an unrecoverable read error occured.
>
> I have several questions:
>
> 1) Is CD Paranoia still maintained ? If so, has anyone worked on the problems
> I described ? I don't want to fix things that are already fixed in CD
> Paranoia IV.
>
> 2) Does anyone know why some drives are able to read the TOC properly while
> other are not ? I suppose that's because the drives use different methods to
> read the TOC, but I'd appreciate a more detailed explaination.
>
> 3) Is there a way lower-level read command than READ CD ? Is there a way to
> read the 588 bits of the CD small frames ? Or a way to read the CIRC codes ?
>
> 4) A friend of mine has been able to read the audio tracks using Clone CD on a
> TEAC DW-224E drive, running Windows XP. Why are some drives able to read the
> sectors, while others are not ? Is there a difference in the CIRC
> implementation, with some drives being better at correcting errors than
> others ? Or does it mean that only the sub-channels information are corrupted
> and the CIRC is correct ? I'm really puzzled by that.
>
> Thanks for any information you can provide.

A Finnish hacker (whose name I don't provide without permission) sent a
patch to me solving this problem. It adds a new '-P' switch to
cdparanoia command, which allows ripping Cactus-protected CD's with
Plextor. It (a) changes the way TOC is read, (b) alters the reading command.

The patch is as follows:

----- 8< -----

diff -Nru cdparanoia-III-alpha9.8/interface/cdda_interface.h cdparanoia-III-alpha9.8P/interface/cdda_interface.h
--- cdparanoia-III-alpha9.8/interface/cdda_interface.h	2001-03-24 03:15:46.000000000 +0200
+++ cdparanoia-III-alpha9.8P/interface/cdda_interface.h	2003-03-15 18:07:43.000000000 +0200
@@ -126,7 +126,7 @@
 extern char *cdda_errors(cdrom_drive *d);

 extern int cdda_close(cdrom_drive *d);
-extern int cdda_open(cdrom_drive *d);
+extern int cdda_open(cdrom_drive *d, int protected);
 extern long cdda_read(cdrom_drive *d, void *buffer,
                        long beginsector, long sectors);

diff -Nru cdparanoia-III-alpha9.8/interface/interface.c cdparanoia-III-alpha9.8P/interface/interface.c
--- cdparanoia-III-alpha9.8/interface/interface.c	2000-04-20 01:41:04.000000000 +0300
+++ cdparanoia-III-alpha9.8P/interface/interface.c	2003-03-15 18:07:43.000000000 +0200
@@ -42,13 +42,13 @@
 }

 /* finish initializing the drive! */
-int cdda_open(cdrom_drive *d){
+int cdda_open(cdrom_drive *d, int protected){
   int ret;
   if(d->opened)return(0);

   switch(d->interface){
   case GENERIC_SCSI:
-    if((ret=scsi_init_drive(d)))
+    if((ret=scsi_init_drive(d, protected)))
       return(ret);
     break;
   case COOKED_IOCTL:
diff -Nru cdparanoia-III-alpha9.8/interface/low_interface.h cdparanoia-III-alpha9.8P/interface/low_interface.h
--- cdparanoia-III-alpha9.8/interface/low_interface.h	2001-03-26 09:12:11.000000000 +0300
+++ cdparanoia-III-alpha9.8P/interface/low_interface.h	2003-03-15 18:07:43.000000000 +0200
@@ -65,7 +65,7 @@

 extern int  cooked_init_drive (cdrom_drive *d);
 extern unsigned char *scsi_inquiry (cdrom_drive *d);
-extern int  scsi_init_drive (cdrom_drive *d);
+extern int  scsi_init_drive (cdrom_drive *d, int protected);
 #ifdef CDDA_TEST
 extern int  test_init_drive (cdrom_drive *d);
 #endif
diff -Nru cdparanoia-III-alpha9.8/interface/scsi_interface.c cdparanoia-III-alpha9.8P/interface/scsi_interface.c
--- cdparanoia-III-alpha9.8/interface/scsi_interface.c	2001-03-24 03:15:46.000000000 +0200
+++ cdparanoia-III-alpha9.8P/interface/scsi_interface.c	2003-03-15 18:07:43.000000000 +0200
@@ -600,6 +600,84 @@
   return(tracks);
 }

+/* Yeah, it may be a crude hack. All at once is really the only way to go,
+   kernel ioctl way can be fooled by copy protections, i.e. corrupted TOCs.
+   So, we'll read the whole thing and scan for audio tracks. */
+
+static int scsi_read_toc_hack (cdrom_drive *d){
+    int i,first,last;
+    unsigned tracks;
+
+    /* READTOC, MSF format flag, res, res, res, res, Start track, len msb,
+       len lsb, flags */
+
+    /* read the whole freakin' TOC */
+    memcpy(d->sg_buffer, (char []){ 0x43, 0, 2, 0, 0, 0, 0, 8, 0, 0}, 10);
+    d->sg_buffer[1]=d->lun<<5;
+
+    if (handle_scsi_cmd (d,10, 0, 2048,'\377',1)){
+	cderror(d,"004: Unable to read table of contents header\n");
+	return(-4);
+    }
+
+    {
+	unsigned short len = *(d->sg_buffer)*256 + *(d->sg_buffer+1);
+	unsigned char *ptr = d->sg_buffer+4;
+	unsigned char flag, track;
+	unsigned int msf;
+	unsigned int leadout = 0;
+	unsigned char leadout_flag = 0;
+	first = 100;
+	last = 0;
+	while (ptr < d->sg_buffer+2+len)
+	{
+	    flag = *(ptr+1);
+	    track = *(ptr+3);
+	    if (track < 100)
+	    {
+		if (track < first)
+		    first = track;
+		else if (track > last)
+		    last = track;
+	    }
+	    ptr += 11;
+	}
+
+	tracks=last-first+1;
+
+	if (last > MAXTRK || first > MAXTRK || last<0 || first<0) {
+	    cderror(d,"003: CDROM reporting illegal number of tracks\n");
+	    return(-3);
+	}
+
+	ptr = d->sg_buffer+4;
+	while (ptr < d->sg_buffer+2+len)
+	{
+	    flag = *(ptr+1);
+	    track = *(ptr+3);
+	    msf = (*(ptr+8)*60 + *(ptr+9))*75 + *(ptr+10) - 150;
+	    if (track < 100)
+	    {
+		d->disc_toc[track-first].bFlags = flag;
+		d->disc_toc[track-first].bTrack = track;
+		d->disc_toc[track-first].dwStartSector = d->adjust_ssize * msf;
+	    }
+	    else if (track == 0xa2 && msf > leadout)
+	    {
+		leadout = msf;
+		leadout_flag = flag;
+	    }
+	    ptr += 11;
+	}
+	d->disc_toc[last-first+1].bFlags = leadout_flag;
+	d->disc_toc[last-first+1].bTrack = 0xAA;
+	d->disc_toc[last-first+1].dwStartSector = d->adjust_ssize * leadout;
+    }
+
+    d->cd_extra = FixupTOC(d,tracks+1); /* include lead-out */
+    return(tracks);
+}
+
 /* These do one 'extra' copy in the name of clean code */

 static int i_read_28 (cdrom_drive *d, void *p, long begin, long sectors){
@@ -1391,7 +1469,7 @@
 }

<p>-int scsi_init_drive(cdrom_drive *d){
+int scsi_init_drive(cdrom_drive *d, int protected){
   int ret;

   check_atapi(d);
@@ -1432,7 +1510,10 @@
                                              sector size at 2048 to begin.*/
   d->enable_cdda(d,0);

-  d->read_toc = (!memcmp(d->drive_model, "IMS", 3) && !d->is_atapi) ? scsi_read_toc2 :
+  if (protected)
+      d->read_toc = scsi_read_toc_hack;
+  else
+      d->read_toc = (!memcmp(d->drive_model, "IMS", 3) && !d->is_atapi) ? scsi_read_toc2 :
     scsi_read_toc;
   d->set_speed = NULL;

@@ -1446,6 +1527,9 @@
       d->adjust_ssize = 1;
   }else
     d->adjust_ssize = 1;
+
+  if (protected)
+      d->read_audio = scsi_read_D8;

   d->tracks=d->read_toc(d);
   if(d->tracks<1)
diff -Nru cdparanoia-III-alpha9.8/main.c cdparanoia-III-alpha9.8P/main.c
--- cdparanoia-III-alpha9.8/main.c	2001-03-26 06:44:50.000000000 +0300
+++ cdparanoia-III-alpha9.8P/main.c	2003-03-15 18:07:43.000000000 +0200
@@ -275,7 +275,9 @@
 "                                    retries without progress.\n"
 "  -Z --disable-paranoia           : disable all paranoia checking\n"
 "  -Y --disable-extra-paranoia     : only do cdda2wav-style overlap checking\n"
-"  -X --abort-on-skip              : abort on imperfect reads/skips\n\n"
+"  -X --abort-on-skip              : abort on imperfect reads/skips\n"
+"  -P --protected                  : some workaround stuff for protected\n"
+"                                    discs (SCSI only)\n\n"

 "OUTPUT SMILIES:\n"
 "  :-)   Normal operation, low/no jitter\n"
@@ -585,7 +587,7 @@
     memset(dispcache,' ',graph);
 }

-const char *optstring = "escCn:o:O:d:g:S:prRwafvqVQhZz::YXWBi:Tt:";
+const char *optstring = "escCn:o:O:d:g:S:prRwafvqVQhZz::YXWBi:Tt:P";

 struct option options [] = {
         {"stderr-progress",no_argument,NULL,'e'},
@@ -618,6 +620,7 @@
         {"disable-fragmentation",no_argument,NULL,'F'},
         {"output-info",required_argument,NULL,'i'},
         {"never-skip",optional_argument,NULL,'z'},
+	{"protected",optional_argument,NULL,'P'},

         {NULL,0,NULL,0}
 };
@@ -661,6 +664,7 @@
   int output_endian=0; /* -1=host, 0=little, 1=big */
   int query_only=0;
   int batch=0,i;
+  int protected=0;

   /* full paranoia, but allow skipping */
   int paranoia_mode=PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP;
@@ -790,6 +794,9 @@
     case 'O':
       sample_offset=atoi(optarg);
       break;
+    case 'P':
+      protected = 1;
+      break;
     default:
       usage(stderr);
       exit(1);
@@ -896,7 +903,7 @@
     }
   }

-  switch(cdda_open(d)){
+  switch(cdda_open(d, protected)){
   case -2:case -3:case -4:case -5:
     report("\nUnable to open disc.  Is there an audio CD in the drive?");
     exit(1);

----- 8< -----

<p>Mikko Nummelin
--- >8 ----
List archives:  http://www.xiph.org/archives/
Paranoia homepage: http://www.xiph.org/paranoia/
To unsubscribe from this list, send mail to 'paranoia-dev-request at xiph.org'
containing only the word 'unsubscribe' in the body.  No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.



More information about the Paranoia-dev mailing list